annotate DEPENDENCIES/generic/include/boost/unordered/detail/table.hpp @ 16:2665513ce2d3

Add boost headers
author Chris Cannam
date Tue, 05 Aug 2014 11:11:38 +0100
parents
children c530137014c0
rev   line source
Chris@16 1
Chris@16 2 // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
Chris@16 3 // Copyright (C) 2005-2011 Daniel James
Chris@16 4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
Chris@16 5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Chris@16 6
Chris@16 7 #ifndef BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED
Chris@16 8 #define BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED
Chris@16 9
Chris@16 10 #include <boost/unordered/detail/buckets.hpp>
Chris@16 11 #include <boost/unordered/detail/util.hpp>
Chris@16 12 #include <boost/type_traits/aligned_storage.hpp>
Chris@16 13 #include <boost/type_traits/alignment_of.hpp>
Chris@16 14 #include <cmath>
Chris@16 15
Chris@16 16 #if defined(BOOST_MSVC)
Chris@16 17 #pragma warning(push)
Chris@16 18 #pragma warning(disable:4127) // conditional expression is constant
Chris@16 19 #endif
Chris@16 20
Chris@16 21 #if defined(BOOST_UNORDERED_DEPRECATED_EQUALITY)
Chris@16 22
Chris@16 23 #if defined(__EDG__)
Chris@16 24 #elif defined(_MSC_VER) || defined(__BORLANDC__) || defined(__DMC__)
Chris@16 25 #pragma message("Warning: BOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported.")
Chris@16 26 #elif defined(__GNUC__) || defined(__HP_aCC) || \
Chris@16 27 defined(__SUNPRO_CC) || defined(__IBMCPP__)
Chris@16 28 #warning "BOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported."
Chris@16 29 #endif
Chris@16 30
Chris@16 31 #endif
Chris@16 32
Chris@16 33 namespace boost { namespace unordered { namespace detail {
Chris@16 34
Chris@16 35 ////////////////////////////////////////////////////////////////////////////
Chris@16 36 // convert double to std::size_t
Chris@16 37
Chris@16 38 inline std::size_t double_to_size(double f)
Chris@16 39 {
Chris@16 40 return f >= static_cast<double>(
Chris@16 41 (std::numeric_limits<std::size_t>::max)()) ?
Chris@16 42 (std::numeric_limits<std::size_t>::max)() :
Chris@16 43 static_cast<std::size_t>(f);
Chris@16 44 }
Chris@16 45
Chris@16 46 // The space used to store values in a node.
Chris@16 47
Chris@16 48 template <typename ValueType>
Chris@16 49 struct value_base
Chris@16 50 {
Chris@16 51 typedef ValueType value_type;
Chris@16 52
Chris@16 53 typename boost::aligned_storage<
Chris@16 54 sizeof(value_type),
Chris@16 55 boost::alignment_of<value_type>::value>::type data_;
Chris@16 56
Chris@16 57 void* address() {
Chris@16 58 return this;
Chris@16 59 }
Chris@16 60
Chris@16 61 value_type& value() {
Chris@16 62 return *(ValueType*) this;
Chris@16 63 }
Chris@16 64
Chris@16 65 value_type* value_ptr() {
Chris@16 66 return (ValueType*) this;
Chris@16 67 }
Chris@16 68
Chris@16 69 private:
Chris@16 70
Chris@16 71 value_base& operator=(value_base const&);
Chris@16 72 };
Chris@16 73
Chris@16 74 template <typename NodeAlloc>
Chris@16 75 struct copy_nodes
Chris@16 76 {
Chris@16 77 typedef boost::unordered::detail::allocator_traits<NodeAlloc>
Chris@16 78 node_allocator_traits;
Chris@16 79
Chris@16 80 node_constructor<NodeAlloc> constructor;
Chris@16 81
Chris@16 82 explicit copy_nodes(NodeAlloc& a) : constructor(a) {}
Chris@16 83
Chris@16 84 typename node_allocator_traits::pointer create(
Chris@16 85 typename node_allocator_traits::value_type::value_type const& v)
Chris@16 86 {
Chris@16 87 constructor.construct_with_value2(v);
Chris@16 88 return constructor.release();
Chris@16 89 }
Chris@16 90 };
Chris@16 91
Chris@16 92 template <typename NodeAlloc>
Chris@16 93 struct move_nodes
Chris@16 94 {
Chris@16 95 typedef boost::unordered::detail::allocator_traits<NodeAlloc>
Chris@16 96 node_allocator_traits;
Chris@16 97
Chris@16 98 node_constructor<NodeAlloc> constructor;
Chris@16 99
Chris@16 100 explicit move_nodes(NodeAlloc& a) : constructor(a) {}
Chris@16 101
Chris@16 102 typename node_allocator_traits::pointer create(
Chris@16 103 typename node_allocator_traits::value_type::value_type& v)
Chris@16 104 {
Chris@16 105 constructor.construct_with_value2(boost::move(v));
Chris@16 106 return constructor.release();
Chris@16 107 }
Chris@16 108 };
Chris@16 109
Chris@16 110 template <typename Buckets>
Chris@16 111 struct assign_nodes
Chris@16 112 {
Chris@16 113 node_holder<typename Buckets::node_allocator> holder;
Chris@16 114
Chris@16 115 explicit assign_nodes(Buckets& b) : holder(b) {}
Chris@16 116
Chris@16 117 typename Buckets::node_pointer create(
Chris@16 118 typename Buckets::value_type const& v)
Chris@16 119 {
Chris@16 120 return holder.copy_of(v);
Chris@16 121 }
Chris@16 122 };
Chris@16 123
Chris@16 124 template <typename Buckets>
Chris@16 125 struct move_assign_nodes
Chris@16 126 {
Chris@16 127 node_holder<typename Buckets::node_allocator> holder;
Chris@16 128
Chris@16 129 explicit move_assign_nodes(Buckets& b) : holder(b) {}
Chris@16 130
Chris@16 131 typename Buckets::node_pointer create(
Chris@16 132 typename Buckets::value_type& v)
Chris@16 133 {
Chris@16 134 return holder.move_copy_of(v);
Chris@16 135 }
Chris@16 136 };
Chris@16 137
Chris@16 138 template <typename Types>
Chris@16 139 struct table :
Chris@16 140 boost::unordered::detail::functions<
Chris@16 141 typename Types::hasher,
Chris@16 142 typename Types::key_equal>
Chris@16 143 {
Chris@16 144 private:
Chris@16 145 table(table const&);
Chris@16 146 table& operator=(table const&);
Chris@16 147 public:
Chris@16 148 typedef typename Types::node node;
Chris@16 149 typedef typename Types::bucket bucket;
Chris@16 150 typedef typename Types::hasher hasher;
Chris@16 151 typedef typename Types::key_equal key_equal;
Chris@16 152 typedef typename Types::key_type key_type;
Chris@16 153 typedef typename Types::extractor extractor;
Chris@16 154 typedef typename Types::value_type value_type;
Chris@16 155 typedef typename Types::table table_impl;
Chris@16 156 typedef typename Types::link_pointer link_pointer;
Chris@16 157 typedef typename Types::policy policy;
Chris@16 158
Chris@16 159 typedef boost::unordered::detail::functions<
Chris@16 160 typename Types::hasher,
Chris@16 161 typename Types::key_equal> functions;
Chris@16 162 typedef typename functions::set_hash_functions set_hash_functions;
Chris@16 163
Chris@16 164 typedef typename Types::allocator allocator;
Chris@16 165 typedef typename boost::unordered::detail::
Chris@16 166 rebind_wrap<allocator, node>::type node_allocator;
Chris@16 167 typedef typename boost::unordered::detail::
Chris@16 168 rebind_wrap<allocator, bucket>::type bucket_allocator;
Chris@16 169 typedef boost::unordered::detail::allocator_traits<node_allocator>
Chris@16 170 node_allocator_traits;
Chris@16 171 typedef boost::unordered::detail::allocator_traits<bucket_allocator>
Chris@16 172 bucket_allocator_traits;
Chris@16 173 typedef typename node_allocator_traits::pointer
Chris@16 174 node_pointer;
Chris@16 175 typedef typename node_allocator_traits::const_pointer
Chris@16 176 const_node_pointer;
Chris@16 177 typedef typename bucket_allocator_traits::pointer
Chris@16 178 bucket_pointer;
Chris@16 179 typedef boost::unordered::detail::node_constructor<node_allocator>
Chris@16 180 node_constructor;
Chris@16 181
Chris@16 182 typedef boost::unordered::iterator_detail::
Chris@16 183 iterator<node> iterator;
Chris@16 184 typedef boost::unordered::iterator_detail::
Chris@16 185 c_iterator<node, const_node_pointer> c_iterator;
Chris@16 186 typedef boost::unordered::iterator_detail::
Chris@16 187 l_iterator<node, policy> l_iterator;
Chris@16 188 typedef boost::unordered::iterator_detail::
Chris@16 189 cl_iterator<node, const_node_pointer, policy> cl_iterator;
Chris@16 190
Chris@16 191 ////////////////////////////////////////////////////////////////////////
Chris@16 192 // Members
Chris@16 193
Chris@16 194 boost::unordered::detail::compressed<bucket_allocator, node_allocator>
Chris@16 195 allocators_;
Chris@16 196 std::size_t bucket_count_;
Chris@16 197 std::size_t size_;
Chris@16 198 float mlf_;
Chris@16 199 std::size_t max_load_;
Chris@16 200 bucket_pointer buckets_;
Chris@16 201
Chris@16 202 ////////////////////////////////////////////////////////////////////////
Chris@16 203 // Data access
Chris@16 204
Chris@16 205 bucket_allocator const& bucket_alloc() const
Chris@16 206 {
Chris@16 207 return allocators_.first();
Chris@16 208 }
Chris@16 209
Chris@16 210 node_allocator const& node_alloc() const
Chris@16 211 {
Chris@16 212 return allocators_.second();
Chris@16 213 }
Chris@16 214
Chris@16 215 bucket_allocator& bucket_alloc()
Chris@16 216 {
Chris@16 217 return allocators_.first();
Chris@16 218 }
Chris@16 219
Chris@16 220 node_allocator& node_alloc()
Chris@16 221 {
Chris@16 222 return allocators_.second();
Chris@16 223 }
Chris@16 224
Chris@16 225 std::size_t max_bucket_count() const
Chris@16 226 {
Chris@16 227 // -1 to account for the start bucket.
Chris@16 228 return policy::prev_bucket_count(
Chris@16 229 bucket_allocator_traits::max_size(bucket_alloc()) - 1);
Chris@16 230 }
Chris@16 231
Chris@16 232 bucket_pointer get_bucket(std::size_t bucket_index) const
Chris@16 233 {
Chris@16 234 BOOST_ASSERT(buckets_);
Chris@16 235 return buckets_ + static_cast<std::ptrdiff_t>(bucket_index);
Chris@16 236 }
Chris@16 237
Chris@16 238 link_pointer get_previous_start() const
Chris@16 239 {
Chris@16 240 return get_bucket(bucket_count_)->first_from_start();
Chris@16 241 }
Chris@16 242
Chris@16 243 link_pointer get_previous_start(std::size_t bucket_index) const
Chris@16 244 {
Chris@16 245 return get_bucket(bucket_index)->next_;
Chris@16 246 }
Chris@16 247
Chris@16 248 iterator begin() const
Chris@16 249 {
Chris@16 250 return size_ ? iterator(get_previous_start()->next_) : iterator();
Chris@16 251 }
Chris@16 252
Chris@16 253 iterator begin(std::size_t bucket_index) const
Chris@16 254 {
Chris@16 255 if (!size_) return iterator();
Chris@16 256 link_pointer prev = get_previous_start(bucket_index);
Chris@16 257 return prev ? iterator(prev->next_) : iterator();
Chris@16 258 }
Chris@16 259
Chris@16 260 std::size_t hash_to_bucket(std::size_t hash) const
Chris@16 261 {
Chris@16 262 return policy::to_bucket(bucket_count_, hash);
Chris@16 263 }
Chris@16 264
Chris@16 265 float load_factor() const
Chris@16 266 {
Chris@16 267 BOOST_ASSERT(bucket_count_ != 0);
Chris@16 268 return static_cast<float>(size_)
Chris@16 269 / static_cast<float>(bucket_count_);
Chris@16 270 }
Chris@16 271
Chris@16 272 std::size_t bucket_size(std::size_t index) const
Chris@16 273 {
Chris@16 274 iterator it = begin(index);
Chris@16 275 if (!it.node_) return 0;
Chris@16 276
Chris@16 277 std::size_t count = 0;
Chris@16 278 while(it.node_ && hash_to_bucket(it.node_->hash_) == index)
Chris@16 279 {
Chris@16 280 ++count;
Chris@16 281 ++it;
Chris@16 282 }
Chris@16 283
Chris@16 284 return count;
Chris@16 285 }
Chris@16 286
Chris@16 287 ////////////////////////////////////////////////////////////////////////
Chris@16 288 // Load methods
Chris@16 289
Chris@16 290 std::size_t max_size() const
Chris@16 291 {
Chris@16 292 using namespace std;
Chris@16 293
Chris@16 294 // size < mlf_ * count
Chris@16 295 return boost::unordered::detail::double_to_size(ceil(
Chris@16 296 static_cast<double>(mlf_) *
Chris@16 297 static_cast<double>(max_bucket_count())
Chris@16 298 )) - 1;
Chris@16 299 }
Chris@16 300
Chris@16 301 void recalculate_max_load()
Chris@16 302 {
Chris@16 303 using namespace std;
Chris@16 304
Chris@16 305 // From 6.3.1/13:
Chris@16 306 // Only resize when size >= mlf_ * count
Chris@16 307 max_load_ = buckets_ ? boost::unordered::detail::double_to_size(ceil(
Chris@16 308 static_cast<double>(mlf_) *
Chris@16 309 static_cast<double>(bucket_count_)
Chris@16 310 )) : 0;
Chris@16 311
Chris@16 312 }
Chris@16 313
Chris@16 314 void max_load_factor(float z)
Chris@16 315 {
Chris@16 316 BOOST_ASSERT(z > 0);
Chris@16 317 mlf_ = (std::max)(z, minimum_max_load_factor);
Chris@16 318 recalculate_max_load();
Chris@16 319 }
Chris@16 320
Chris@16 321 std::size_t min_buckets_for_size(std::size_t size) const
Chris@16 322 {
Chris@16 323 BOOST_ASSERT(mlf_ >= minimum_max_load_factor);
Chris@16 324
Chris@16 325 using namespace std;
Chris@16 326
Chris@16 327 // From 6.3.1/13:
Chris@16 328 // size < mlf_ * count
Chris@16 329 // => count > size / mlf_
Chris@16 330 //
Chris@16 331 // Or from rehash post-condition:
Chris@16 332 // count > size / mlf_
Chris@16 333
Chris@16 334 return policy::new_bucket_count(
Chris@16 335 boost::unordered::detail::double_to_size(floor(
Chris@16 336 static_cast<double>(size) /
Chris@16 337 static_cast<double>(mlf_))) + 1);
Chris@16 338 }
Chris@16 339
Chris@16 340 ////////////////////////////////////////////////////////////////////////
Chris@16 341 // Constructors
Chris@16 342
Chris@16 343 table(std::size_t num_buckets,
Chris@16 344 hasher const& hf,
Chris@16 345 key_equal const& eq,
Chris@16 346 node_allocator const& a) :
Chris@16 347 functions(hf, eq),
Chris@16 348 allocators_(a,a),
Chris@16 349 bucket_count_(policy::new_bucket_count(num_buckets)),
Chris@16 350 size_(0),
Chris@16 351 mlf_(1.0f),
Chris@16 352 max_load_(0),
Chris@16 353 buckets_()
Chris@16 354 {}
Chris@16 355
Chris@16 356 table(table const& x, node_allocator const& a) :
Chris@16 357 functions(x),
Chris@16 358 allocators_(a,a),
Chris@16 359 bucket_count_(x.min_buckets_for_size(x.size_)),
Chris@16 360 size_(0),
Chris@16 361 mlf_(x.mlf_),
Chris@16 362 max_load_(0),
Chris@16 363 buckets_()
Chris@16 364 {}
Chris@16 365
Chris@16 366 table(table& x, boost::unordered::detail::move_tag m) :
Chris@16 367 functions(x, m),
Chris@16 368 allocators_(x.allocators_, m),
Chris@16 369 bucket_count_(x.bucket_count_),
Chris@16 370 size_(x.size_),
Chris@16 371 mlf_(x.mlf_),
Chris@16 372 max_load_(x.max_load_),
Chris@16 373 buckets_(x.buckets_)
Chris@16 374 {
Chris@16 375 x.buckets_ = bucket_pointer();
Chris@16 376 x.size_ = 0;
Chris@16 377 x.max_load_ = 0;
Chris@16 378 }
Chris@16 379
Chris@16 380 table(table& x, node_allocator const& a,
Chris@16 381 boost::unordered::detail::move_tag m) :
Chris@16 382 functions(x, m),
Chris@16 383 allocators_(a, a),
Chris@16 384 bucket_count_(x.bucket_count_),
Chris@16 385 size_(0),
Chris@16 386 mlf_(x.mlf_),
Chris@16 387 max_load_(x.max_load_),
Chris@16 388 buckets_()
Chris@16 389 {}
Chris@16 390
Chris@16 391 ////////////////////////////////////////////////////////////////////////
Chris@16 392 // Initialisation.
Chris@16 393
Chris@16 394 void init(table const& x)
Chris@16 395 {
Chris@16 396 if (x.size_) {
Chris@16 397 create_buckets(bucket_count_);
Chris@16 398 copy_nodes<node_allocator> copy(node_alloc());
Chris@16 399 table_impl::fill_buckets(x.begin(), *this, copy);
Chris@16 400 }
Chris@16 401 }
Chris@16 402
Chris@16 403 void move_init(table& x)
Chris@16 404 {
Chris@16 405 if(node_alloc() == x.node_alloc()) {
Chris@16 406 move_buckets_from(x);
Chris@16 407 }
Chris@16 408 else if(x.size_) {
Chris@16 409 // TODO: Could pick new bucket size?
Chris@16 410 create_buckets(bucket_count_);
Chris@16 411
Chris@16 412 move_nodes<node_allocator> move(node_alloc());
Chris@16 413 node_holder<node_allocator> nodes(x);
Chris@16 414 table_impl::fill_buckets(nodes.begin(), *this, move);
Chris@16 415 }
Chris@16 416 }
Chris@16 417
Chris@16 418 ////////////////////////////////////////////////////////////////////////
Chris@16 419 // Create buckets
Chris@16 420
Chris@16 421 void create_buckets(std::size_t new_count)
Chris@16 422 {
Chris@16 423 boost::unordered::detail::array_constructor<bucket_allocator>
Chris@16 424 constructor(bucket_alloc());
Chris@16 425
Chris@16 426 // Creates an extra bucket to act as the start node.
Chris@16 427 constructor.construct(bucket(), new_count + 1);
Chris@16 428
Chris@16 429 if (buckets_)
Chris@16 430 {
Chris@16 431 // Copy the nodes to the new buckets, including the dummy
Chris@16 432 // node if there is one.
Chris@16 433 (constructor.get() +
Chris@16 434 static_cast<std::ptrdiff_t>(new_count))->next_ =
Chris@16 435 (buckets_ + static_cast<std::ptrdiff_t>(
Chris@16 436 bucket_count_))->next_;
Chris@16 437 destroy_buckets();
Chris@16 438 }
Chris@16 439 else if (bucket::extra_node)
Chris@16 440 {
Chris@16 441 node_constructor a(node_alloc());
Chris@16 442 a.construct();
Chris@16 443
Chris@16 444 (constructor.get() +
Chris@16 445 static_cast<std::ptrdiff_t>(new_count))->next_ =
Chris@16 446 a.release();
Chris@16 447 }
Chris@16 448
Chris@16 449 bucket_count_ = new_count;
Chris@16 450 buckets_ = constructor.release();
Chris@16 451 recalculate_max_load();
Chris@16 452 }
Chris@16 453
Chris@16 454 ////////////////////////////////////////////////////////////////////////
Chris@16 455 // Swap and Move
Chris@16 456
Chris@16 457 void swap_allocators(table& other, false_type)
Chris@16 458 {
Chris@16 459 boost::unordered::detail::func::ignore_unused_variable_warning(other);
Chris@16 460
Chris@16 461 // According to 23.2.1.8, if propagate_on_container_swap is
Chris@16 462 // false the behaviour is undefined unless the allocators
Chris@16 463 // are equal.
Chris@16 464 BOOST_ASSERT(node_alloc() == other.node_alloc());
Chris@16 465 }
Chris@16 466
Chris@16 467 void swap_allocators(table& other, true_type)
Chris@16 468 {
Chris@16 469 allocators_.swap(other.allocators_);
Chris@16 470 }
Chris@16 471
Chris@16 472 // Only swaps the allocators if propagate_on_container_swap
Chris@16 473 void swap(table& x)
Chris@16 474 {
Chris@16 475 set_hash_functions op1(*this, x);
Chris@16 476 set_hash_functions op2(x, *this);
Chris@16 477
Chris@16 478 // I think swap can throw if Propagate::value,
Chris@16 479 // since the allocators' swap can throw. Not sure though.
Chris@16 480 swap_allocators(x,
Chris@16 481 boost::unordered::detail::integral_constant<bool,
Chris@16 482 allocator_traits<node_allocator>::
Chris@16 483 propagate_on_container_swap::value>());
Chris@16 484
Chris@16 485 boost::swap(buckets_, x.buckets_);
Chris@16 486 boost::swap(bucket_count_, x.bucket_count_);
Chris@16 487 boost::swap(size_, x.size_);
Chris@16 488 std::swap(mlf_, x.mlf_);
Chris@16 489 std::swap(max_load_, x.max_load_);
Chris@16 490 op1.commit();
Chris@16 491 op2.commit();
Chris@16 492 }
Chris@16 493
Chris@16 494 void move_buckets_from(table& other)
Chris@16 495 {
Chris@16 496 BOOST_ASSERT(node_alloc() == other.node_alloc());
Chris@16 497 BOOST_ASSERT(!buckets_);
Chris@16 498 buckets_ = other.buckets_;
Chris@16 499 bucket_count_ = other.bucket_count_;
Chris@16 500 size_ = other.size_;
Chris@16 501 other.buckets_ = bucket_pointer();
Chris@16 502 other.size_ = 0;
Chris@16 503 other.max_load_ = 0;
Chris@16 504 }
Chris@16 505
Chris@16 506 ////////////////////////////////////////////////////////////////////////
Chris@16 507 // Delete/destruct
Chris@16 508
Chris@16 509 ~table()
Chris@16 510 {
Chris@16 511 delete_buckets();
Chris@16 512 }
Chris@16 513
Chris@16 514 void delete_node(link_pointer prev)
Chris@16 515 {
Chris@16 516 node_pointer n = static_cast<node_pointer>(prev->next_);
Chris@16 517 prev->next_ = n->next_;
Chris@16 518
Chris@16 519 boost::unordered::detail::func::destroy_value_impl(node_alloc(),
Chris@16 520 n->value_ptr());
Chris@16 521 node_allocator_traits::destroy(node_alloc(),
Chris@16 522 boost::addressof(*n));
Chris@16 523 node_allocator_traits::deallocate(node_alloc(), n, 1);
Chris@16 524 --size_;
Chris@16 525 }
Chris@16 526
Chris@16 527 std::size_t delete_nodes(link_pointer prev, link_pointer end)
Chris@16 528 {
Chris@16 529 BOOST_ASSERT(prev->next_ != end);
Chris@16 530
Chris@16 531 std::size_t count = 0;
Chris@16 532
Chris@16 533 do {
Chris@16 534 delete_node(prev);
Chris@16 535 ++count;
Chris@16 536 } while (prev->next_ != end);
Chris@16 537
Chris@16 538 return count;
Chris@16 539 }
Chris@16 540
Chris@16 541 void delete_buckets()
Chris@16 542 {
Chris@16 543 if(buckets_) {
Chris@16 544 if (size_) delete_nodes(get_previous_start(), link_pointer());
Chris@16 545
Chris@16 546 if (bucket::extra_node) {
Chris@16 547 node_pointer n = static_cast<node_pointer>(
Chris@16 548 get_bucket(bucket_count_)->next_);
Chris@16 549 node_allocator_traits::destroy(node_alloc(),
Chris@16 550 boost::addressof(*n));
Chris@16 551 node_allocator_traits::deallocate(node_alloc(), n, 1);
Chris@16 552 }
Chris@16 553
Chris@16 554 destroy_buckets();
Chris@16 555 buckets_ = bucket_pointer();
Chris@16 556 max_load_ = 0;
Chris@16 557 }
Chris@16 558
Chris@16 559 BOOST_ASSERT(!size_);
Chris@16 560 }
Chris@16 561
Chris@16 562 void clear()
Chris@16 563 {
Chris@16 564 if (!size_) return;
Chris@16 565
Chris@16 566 delete_nodes(get_previous_start(), link_pointer());
Chris@16 567 clear_buckets();
Chris@16 568
Chris@16 569 BOOST_ASSERT(!size_);
Chris@16 570 }
Chris@16 571
Chris@16 572 void clear_buckets()
Chris@16 573 {
Chris@16 574 bucket_pointer end = get_bucket(bucket_count_);
Chris@16 575 for(bucket_pointer it = buckets_; it != end; ++it)
Chris@16 576 {
Chris@16 577 it->next_ = node_pointer();
Chris@16 578 }
Chris@16 579 }
Chris@16 580
Chris@16 581 void destroy_buckets()
Chris@16 582 {
Chris@16 583 bucket_pointer end = get_bucket(bucket_count_ + 1);
Chris@16 584 for(bucket_pointer it = buckets_; it != end; ++it)
Chris@16 585 {
Chris@16 586 bucket_allocator_traits::destroy(bucket_alloc(),
Chris@16 587 boost::addressof(*it));
Chris@16 588 }
Chris@16 589
Chris@16 590 bucket_allocator_traits::deallocate(bucket_alloc(),
Chris@16 591 buckets_, bucket_count_ + 1);
Chris@16 592 }
Chris@16 593
Chris@16 594 ////////////////////////////////////////////////////////////////////////
Chris@16 595 // Fix buckets after delete
Chris@16 596 //
Chris@16 597
Chris@16 598 std::size_t fix_bucket(std::size_t bucket_index, link_pointer prev)
Chris@16 599 {
Chris@16 600 link_pointer end = prev->next_;
Chris@16 601 std::size_t bucket_index2 = bucket_index;
Chris@16 602
Chris@16 603 if (end)
Chris@16 604 {
Chris@16 605 bucket_index2 = hash_to_bucket(
Chris@16 606 static_cast<node_pointer>(end)->hash_);
Chris@16 607
Chris@16 608 // If begin and end are in the same bucket, then
Chris@16 609 // there's nothing to do.
Chris@16 610 if (bucket_index == bucket_index2) return bucket_index2;
Chris@16 611
Chris@16 612 // Update the bucket containing end.
Chris@16 613 get_bucket(bucket_index2)->next_ = prev;
Chris@16 614 }
Chris@16 615
Chris@16 616 // Check if this bucket is now empty.
Chris@16 617 bucket_pointer this_bucket = get_bucket(bucket_index);
Chris@16 618 if (this_bucket->next_ == prev)
Chris@16 619 this_bucket->next_ = link_pointer();
Chris@16 620
Chris@16 621 return bucket_index2;
Chris@16 622 }
Chris@16 623
Chris@16 624 ////////////////////////////////////////////////////////////////////////
Chris@16 625 // Assignment
Chris@16 626
Chris@16 627 void assign(table const& x)
Chris@16 628 {
Chris@16 629 if (this != boost::addressof(x))
Chris@16 630 {
Chris@16 631 assign(x,
Chris@16 632 boost::unordered::detail::integral_constant<bool,
Chris@16 633 allocator_traits<node_allocator>::
Chris@16 634 propagate_on_container_copy_assignment::value>());
Chris@16 635 }
Chris@16 636 }
Chris@16 637
Chris@16 638 void assign(table const& x, false_type)
Chris@16 639 {
Chris@16 640 // Strong exception safety.
Chris@16 641 set_hash_functions new_func_this(*this, x);
Chris@16 642 new_func_this.commit();
Chris@16 643 mlf_ = x.mlf_;
Chris@16 644 recalculate_max_load();
Chris@16 645
Chris@16 646 if (!size_ && !x.size_) return;
Chris@16 647
Chris@16 648 if (x.size_ >= max_load_) {
Chris@16 649 create_buckets(min_buckets_for_size(x.size_));
Chris@16 650 }
Chris@16 651 else {
Chris@16 652 clear_buckets();
Chris@16 653 }
Chris@16 654
Chris@16 655 // assign_nodes takes ownership of the container's elements,
Chris@16 656 // assigning to them if possible, and deleting any that are
Chris@16 657 // left over.
Chris@16 658 assign_nodes<table> assign(*this);
Chris@16 659 table_impl::fill_buckets(x.begin(), *this, assign);
Chris@16 660 }
Chris@16 661
Chris@16 662 void assign(table const& x, true_type)
Chris@16 663 {
Chris@16 664 if (node_alloc() == x.node_alloc()) {
Chris@16 665 allocators_.assign(x.allocators_);
Chris@16 666 assign(x, false_type());
Chris@16 667 }
Chris@16 668 else {
Chris@16 669 set_hash_functions new_func_this(*this, x);
Chris@16 670
Chris@16 671 // Delete everything with current allocators before assigning
Chris@16 672 // the new ones.
Chris@16 673 delete_buckets();
Chris@16 674 allocators_.assign(x.allocators_);
Chris@16 675
Chris@16 676 // Copy over other data, all no throw.
Chris@16 677 new_func_this.commit();
Chris@16 678 mlf_ = x.mlf_;
Chris@16 679 bucket_count_ = min_buckets_for_size(x.size_);
Chris@16 680 max_load_ = 0;
Chris@16 681
Chris@16 682 // Finally copy the elements.
Chris@16 683 if (x.size_) {
Chris@16 684 create_buckets(bucket_count_);
Chris@16 685 copy_nodes<node_allocator> copy(node_alloc());
Chris@16 686 table_impl::fill_buckets(x.begin(), *this, copy);
Chris@16 687 }
Chris@16 688 }
Chris@16 689 }
Chris@16 690
Chris@16 691 void move_assign(table& x)
Chris@16 692 {
Chris@16 693 if (this != boost::addressof(x))
Chris@16 694 {
Chris@16 695 move_assign(x,
Chris@16 696 boost::unordered::detail::integral_constant<bool,
Chris@16 697 allocator_traits<node_allocator>::
Chris@16 698 propagate_on_container_move_assignment::value>());
Chris@16 699 }
Chris@16 700 }
Chris@16 701
Chris@16 702 void move_assign(table& x, true_type)
Chris@16 703 {
Chris@16 704 delete_buckets();
Chris@16 705 allocators_.move_assign(x.allocators_);
Chris@16 706 move_assign_no_alloc(x);
Chris@16 707 }
Chris@16 708
Chris@16 709 void move_assign(table& x, false_type)
Chris@16 710 {
Chris@16 711 if (node_alloc() == x.node_alloc()) {
Chris@16 712 delete_buckets();
Chris@16 713 move_assign_no_alloc(x);
Chris@16 714 }
Chris@16 715 else {
Chris@16 716 set_hash_functions new_func_this(*this, x);
Chris@16 717 new_func_this.commit();
Chris@16 718 mlf_ = x.mlf_;
Chris@16 719 recalculate_max_load();
Chris@16 720
Chris@16 721 if (!size_ && !x.size_) return;
Chris@16 722
Chris@16 723 if (x.size_ >= max_load_) {
Chris@16 724 create_buckets(min_buckets_for_size(x.size_));
Chris@16 725 }
Chris@16 726 else {
Chris@16 727 clear_buckets();
Chris@16 728 }
Chris@16 729
Chris@16 730 // move_assign_nodes takes ownership of the container's
Chris@16 731 // elements, assigning to them if possible, and deleting
Chris@16 732 // any that are left over.
Chris@16 733 move_assign_nodes<table> assign(*this);
Chris@16 734 node_holder<node_allocator> nodes(x);
Chris@16 735 table_impl::fill_buckets(nodes.begin(), *this, assign);
Chris@16 736 }
Chris@16 737 }
Chris@16 738
Chris@16 739 void move_assign_no_alloc(table& x)
Chris@16 740 {
Chris@16 741 set_hash_functions new_func_this(*this, x);
Chris@16 742 // No throw from here.
Chris@16 743 mlf_ = x.mlf_;
Chris@16 744 max_load_ = x.max_load_;
Chris@16 745 move_buckets_from(x);
Chris@16 746 new_func_this.commit();
Chris@16 747 }
Chris@16 748
Chris@16 749 // Accessors
Chris@16 750
Chris@16 751 key_type const& get_key(value_type const& x) const
Chris@16 752 {
Chris@16 753 return extractor::extract(x);
Chris@16 754 }
Chris@16 755
Chris@16 756 std::size_t hash(key_type const& k) const
Chris@16 757 {
Chris@16 758 return policy::apply_hash(this->hash_function(), k);
Chris@16 759 }
Chris@16 760
Chris@16 761 // Find Node
Chris@16 762
Chris@16 763 template <typename Key, typename Hash, typename Pred>
Chris@16 764 iterator generic_find_node(
Chris@16 765 Key const& k,
Chris@16 766 Hash const& hf,
Chris@16 767 Pred const& eq) const
Chris@16 768 {
Chris@16 769 return static_cast<table_impl const*>(this)->
Chris@16 770 find_node_impl(policy::apply_hash(hf, k), k, eq);
Chris@16 771 }
Chris@16 772
Chris@16 773 iterator find_node(
Chris@16 774 std::size_t key_hash,
Chris@16 775 key_type const& k) const
Chris@16 776 {
Chris@16 777 return static_cast<table_impl const*>(this)->
Chris@16 778 find_node_impl(key_hash, k, this->key_eq());
Chris@16 779 }
Chris@16 780
Chris@16 781 iterator find_node(key_type const& k) const
Chris@16 782 {
Chris@16 783 return static_cast<table_impl const*>(this)->
Chris@16 784 find_node_impl(hash(k), k, this->key_eq());
Chris@16 785 }
Chris@16 786
Chris@16 787 iterator find_matching_node(iterator n) const
Chris@16 788 {
Chris@16 789 // TODO: Does this apply to C++11?
Chris@16 790 //
Chris@16 791 // For some stupid reason, I decided to support equality comparison
Chris@16 792 // when different hash functions are used. So I can't use the hash
Chris@16 793 // value from the node here.
Chris@16 794
Chris@16 795 return find_node(get_key(*n));
Chris@16 796 }
Chris@16 797
Chris@16 798 // Reserve and rehash
Chris@16 799
Chris@16 800 void reserve_for_insert(std::size_t);
Chris@16 801 void rehash(std::size_t);
Chris@16 802 void reserve(std::size_t);
Chris@16 803 };
Chris@16 804
Chris@16 805 ////////////////////////////////////////////////////////////////////////////
Chris@16 806 // Reserve & Rehash
Chris@16 807
Chris@16 808 // basic exception safety
Chris@16 809 template <typename Types>
Chris@16 810 inline void table<Types>::reserve_for_insert(std::size_t size)
Chris@16 811 {
Chris@16 812 if (!buckets_) {
Chris@16 813 create_buckets((std::max)(bucket_count_,
Chris@16 814 min_buckets_for_size(size)));
Chris@16 815 }
Chris@16 816 // According to the standard this should be 'size >= max_load_',
Chris@16 817 // but I think this is better, defect report filed.
Chris@16 818 else if(size > max_load_) {
Chris@16 819 std::size_t num_buckets
Chris@16 820 = min_buckets_for_size((std::max)(size,
Chris@16 821 size_ + (size_ >> 1)));
Chris@16 822
Chris@16 823 if (num_buckets != bucket_count_)
Chris@16 824 static_cast<table_impl*>(this)->rehash_impl(num_buckets);
Chris@16 825 }
Chris@16 826 }
Chris@16 827
Chris@16 828 // if hash function throws, basic exception safety
Chris@16 829 // strong otherwise.
Chris@16 830
Chris@16 831 template <typename Types>
Chris@16 832 inline void table<Types>::rehash(std::size_t min_buckets)
Chris@16 833 {
Chris@16 834 using namespace std;
Chris@16 835
Chris@16 836 if(!size_) {
Chris@16 837 delete_buckets();
Chris@16 838 bucket_count_ = policy::new_bucket_count(min_buckets);
Chris@16 839 }
Chris@16 840 else {
Chris@16 841 min_buckets = policy::new_bucket_count((std::max)(min_buckets,
Chris@16 842 boost::unordered::detail::double_to_size(floor(
Chris@16 843 static_cast<double>(size_) /
Chris@16 844 static_cast<double>(mlf_))) + 1));
Chris@16 845
Chris@16 846 if(min_buckets != bucket_count_)
Chris@16 847 static_cast<table_impl*>(this)->rehash_impl(min_buckets);
Chris@16 848 }
Chris@16 849 }
Chris@16 850
Chris@16 851 template <typename Types>
Chris@16 852 inline void table<Types>::reserve(std::size_t num_elements)
Chris@16 853 {
Chris@16 854 rehash(static_cast<std::size_t>(
Chris@16 855 std::ceil(static_cast<double>(num_elements) / mlf_)));
Chris@16 856 }
Chris@16 857 }}}
Chris@16 858
Chris@16 859 #if defined(BOOST_MSVC)
Chris@16 860 #pragma warning(pop)
Chris@16 861 #endif
Chris@16 862
Chris@16 863 #endif