annotate DEPENDENCIES/generic/include/boost/unordered/detail/table.hpp @ 133:4acb5d8d80b6 tip

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