Jeff Thompson | a28eed8 | 2013-08-22 16:21:10 -0700 | [diff] [blame] | 1 | |
| 2 | // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. |
| 3 | // Copyright (C) 2005-2011 Daniel James |
| 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
| 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 6 | |
| 7 | #ifndef BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED |
| 8 | #define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED |
| 9 | |
| 10 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) |
| 11 | # pragma once |
| 12 | #endif |
| 13 | |
| 14 | #include <ndnboost/unordered/detail/util.hpp> |
| 15 | #include <ndnboost/unordered/detail/allocate.hpp> |
| 16 | #include <ndnboost/type_traits/aligned_storage.hpp> |
| 17 | #include <ndnboost/type_traits/alignment_of.hpp> |
| 18 | #include <ndnboost/type_traits/is_nothrow_move_constructible.hpp> |
| 19 | #include <ndnboost/type_traits/is_nothrow_move_assignable.hpp> |
| 20 | #include <ndnboost/swap.hpp> |
| 21 | #include <ndnboost/assert.hpp> |
| 22 | #include <ndnboost/limits.hpp> |
| 23 | #include <ndnboost/iterator.hpp> |
| 24 | |
| 25 | namespace ndnboost { namespace unordered { namespace detail { |
| 26 | |
| 27 | template <typename Types> struct table; |
| 28 | template <typename NodePointer> struct bucket; |
| 29 | struct ptr_bucket; |
| 30 | template <typename Types> struct table_impl; |
| 31 | template <typename Types> struct grouped_table_impl; |
| 32 | |
| 33 | }}} |
| 34 | |
| 35 | namespace ndnboost { namespace unordered { namespace iterator_detail { |
| 36 | |
| 37 | //////////////////////////////////////////////////////////////////////////// |
| 38 | // Iterators |
| 39 | // |
| 40 | // all no throw |
| 41 | |
| 42 | template <typename Node> struct iterator; |
| 43 | template <typename Node, typename ConstNodePointer> struct c_iterator; |
| 44 | template <typename Node, typename Policy> struct l_iterator; |
| 45 | template <typename Node, typename ConstNodePointer, typename Policy> |
| 46 | struct cl_iterator; |
| 47 | |
| 48 | // Local Iterators |
| 49 | // |
| 50 | // all no throw |
| 51 | |
| 52 | template <typename Node, typename Policy> |
| 53 | struct l_iterator |
| 54 | : public ndnboost::iterator< |
| 55 | std::forward_iterator_tag, |
| 56 | typename Node::value_type, |
| 57 | std::ptrdiff_t, |
| 58 | typename Node::node_pointer, |
| 59 | typename Node::value_type&> |
| 60 | { |
| 61 | #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) |
| 62 | template <typename Node2, typename ConstNodePointer, typename Policy2> |
| 63 | friend struct ndnboost::unordered::iterator_detail::cl_iterator; |
| 64 | private: |
| 65 | #endif |
| 66 | typedef typename Node::node_pointer node_pointer; |
| 67 | typedef ndnboost::unordered::iterator_detail::iterator<Node> iterator; |
| 68 | node_pointer ptr_; |
| 69 | std::size_t bucket_; |
| 70 | std::size_t bucket_count_; |
| 71 | |
| 72 | public: |
| 73 | |
| 74 | typedef typename Node::value_type value_type; |
| 75 | |
| 76 | l_iterator() : ptr_() {} |
| 77 | |
| 78 | l_iterator(iterator x, std::size_t b, std::size_t c) |
| 79 | : ptr_(x.node_), bucket_(b), bucket_count_(c) {} |
| 80 | |
| 81 | value_type& operator*() const { |
| 82 | return ptr_->value(); |
| 83 | } |
| 84 | |
| 85 | value_type* operator->() const { |
| 86 | return ptr_->value_ptr(); |
| 87 | } |
| 88 | |
| 89 | l_iterator& operator++() { |
| 90 | ptr_ = static_cast<node_pointer>(ptr_->next_); |
| 91 | if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_) |
| 92 | != bucket_) |
| 93 | ptr_ = node_pointer(); |
| 94 | return *this; |
| 95 | } |
| 96 | |
| 97 | l_iterator operator++(int) { |
| 98 | l_iterator tmp(*this); |
| 99 | ++(*this); |
| 100 | return tmp; |
| 101 | } |
| 102 | |
| 103 | bool operator==(l_iterator x) const { |
| 104 | return ptr_ == x.ptr_; |
| 105 | } |
| 106 | |
| 107 | bool operator!=(l_iterator x) const { |
| 108 | return ptr_ != x.ptr_; |
| 109 | } |
| 110 | }; |
| 111 | |
| 112 | template <typename Node, typename ConstNodePointer, typename Policy> |
| 113 | struct cl_iterator |
| 114 | : public ndnboost::iterator< |
| 115 | std::forward_iterator_tag, |
| 116 | typename Node::value_type, |
| 117 | std::ptrdiff_t, |
| 118 | ConstNodePointer, |
| 119 | typename Node::value_type const&> |
| 120 | { |
| 121 | friend struct ndnboost::unordered::iterator_detail::l_iterator |
| 122 | <Node, Policy>; |
| 123 | private: |
| 124 | |
| 125 | typedef typename Node::node_pointer node_pointer; |
| 126 | typedef ndnboost::unordered::iterator_detail::iterator<Node> iterator; |
| 127 | node_pointer ptr_; |
| 128 | std::size_t bucket_; |
| 129 | std::size_t bucket_count_; |
| 130 | |
| 131 | public: |
| 132 | |
| 133 | typedef typename Node::value_type value_type; |
| 134 | |
| 135 | cl_iterator() : ptr_() {} |
| 136 | |
| 137 | cl_iterator(iterator x, std::size_t b, std::size_t c) : |
| 138 | ptr_(x.node_), bucket_(b), bucket_count_(c) {} |
| 139 | |
| 140 | cl_iterator(ndnboost::unordered::iterator_detail::l_iterator< |
| 141 | Node, Policy> const& x) : |
| 142 | ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_) |
| 143 | {} |
| 144 | |
| 145 | value_type const& operator*() const { |
| 146 | return ptr_->value(); |
| 147 | } |
| 148 | |
| 149 | value_type const* operator->() const { |
| 150 | return ptr_->value_ptr(); |
| 151 | } |
| 152 | |
| 153 | cl_iterator& operator++() { |
| 154 | ptr_ = static_cast<node_pointer>(ptr_->next_); |
| 155 | if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_) |
| 156 | != bucket_) |
| 157 | ptr_ = node_pointer(); |
| 158 | return *this; |
| 159 | } |
| 160 | |
| 161 | cl_iterator operator++(int) { |
| 162 | cl_iterator tmp(*this); |
| 163 | ++(*this); |
| 164 | return tmp; |
| 165 | } |
| 166 | |
| 167 | friend bool operator==(cl_iterator const& x, cl_iterator const& y) { |
| 168 | return x.ptr_ == y.ptr_; |
| 169 | } |
| 170 | |
| 171 | friend bool operator!=(cl_iterator const& x, cl_iterator const& y) { |
| 172 | return x.ptr_ != y.ptr_; |
| 173 | } |
| 174 | }; |
| 175 | |
| 176 | template <typename Node> |
| 177 | struct iterator |
| 178 | : public ndnboost::iterator< |
| 179 | std::forward_iterator_tag, |
| 180 | typename Node::value_type, |
| 181 | std::ptrdiff_t, |
| 182 | typename Node::node_pointer, |
| 183 | typename Node::value_type&> |
| 184 | { |
| 185 | #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) |
| 186 | template <typename, typename> |
| 187 | friend struct ndnboost::unordered::iterator_detail::c_iterator; |
| 188 | template <typename, typename> |
| 189 | friend struct ndnboost::unordered::iterator_detail::l_iterator; |
| 190 | template <typename, typename, typename> |
| 191 | friend struct ndnboost::unordered::iterator_detail::cl_iterator; |
| 192 | template <typename> |
| 193 | friend struct ndnboost::unordered::detail::table; |
| 194 | template <typename> |
| 195 | friend struct ndnboost::unordered::detail::table_impl; |
| 196 | template <typename> |
| 197 | friend struct ndnboost::unordered::detail::grouped_table_impl; |
| 198 | private: |
| 199 | #endif |
| 200 | typedef typename Node::node_pointer node_pointer; |
| 201 | node_pointer node_; |
| 202 | |
| 203 | public: |
| 204 | |
| 205 | typedef typename Node::value_type value_type; |
| 206 | |
| 207 | iterator() : node_() {} |
| 208 | |
| 209 | explicit iterator(typename Node::link_pointer x) : |
| 210 | node_(static_cast<node_pointer>(x)) {} |
| 211 | |
| 212 | value_type& operator*() const { |
| 213 | return node_->value(); |
| 214 | } |
| 215 | |
| 216 | value_type* operator->() const { |
| 217 | return &node_->value(); |
| 218 | } |
| 219 | |
| 220 | iterator& operator++() { |
| 221 | node_ = static_cast<node_pointer>(node_->next_); |
| 222 | return *this; |
| 223 | } |
| 224 | |
| 225 | iterator operator++(int) { |
| 226 | iterator tmp(node_); |
| 227 | node_ = static_cast<node_pointer>(node_->next_); |
| 228 | return tmp; |
| 229 | } |
| 230 | |
| 231 | bool operator==(iterator const& x) const { |
| 232 | return node_ == x.node_; |
| 233 | } |
| 234 | |
| 235 | bool operator!=(iterator const& x) const { |
| 236 | return node_ != x.node_; |
| 237 | } |
| 238 | }; |
| 239 | |
| 240 | template <typename Node, typename ConstNodePointer> |
| 241 | struct c_iterator |
| 242 | : public ndnboost::iterator< |
| 243 | std::forward_iterator_tag, |
| 244 | typename Node::value_type, |
| 245 | std::ptrdiff_t, |
| 246 | ConstNodePointer, |
| 247 | typename Node::value_type const&> |
| 248 | { |
| 249 | friend struct ndnboost::unordered::iterator_detail::iterator<Node>; |
| 250 | |
| 251 | #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) |
| 252 | template <typename> |
| 253 | friend struct ndnboost::unordered::detail::table; |
| 254 | template <typename> |
| 255 | friend struct ndnboost::unordered::detail::table_impl; |
| 256 | template <typename> |
| 257 | friend struct ndnboost::unordered::detail::grouped_table_impl; |
| 258 | |
| 259 | private: |
| 260 | #endif |
| 261 | typedef typename Node::node_pointer node_pointer; |
| 262 | typedef ndnboost::unordered::iterator_detail::iterator<Node> iterator; |
| 263 | node_pointer node_; |
| 264 | |
| 265 | public: |
| 266 | |
| 267 | typedef typename Node::value_type value_type; |
| 268 | |
| 269 | c_iterator() : node_() {} |
| 270 | |
| 271 | explicit c_iterator(typename Node::link_pointer x) : |
| 272 | node_(static_cast<node_pointer>(x)) {} |
| 273 | |
| 274 | c_iterator(iterator const& x) : node_(x.node_) {} |
| 275 | |
| 276 | value_type const& operator*() const { |
| 277 | return node_->value(); |
| 278 | } |
| 279 | |
| 280 | value_type const* operator->() const { |
| 281 | return &node_->value(); |
| 282 | } |
| 283 | |
| 284 | c_iterator& operator++() { |
| 285 | node_ = static_cast<node_pointer>(node_->next_); |
| 286 | return *this; |
| 287 | } |
| 288 | |
| 289 | c_iterator operator++(int) { |
| 290 | c_iterator tmp(node_); |
| 291 | node_ = static_cast<node_pointer>(node_->next_); |
| 292 | return tmp; |
| 293 | } |
| 294 | |
| 295 | friend bool operator==(c_iterator const& x, c_iterator const& y) { |
| 296 | return x.node_ == y.node_; |
| 297 | } |
| 298 | |
| 299 | friend bool operator!=(c_iterator const& x, c_iterator const& y) { |
| 300 | return x.node_ != y.node_; |
| 301 | } |
| 302 | }; |
| 303 | }}} |
| 304 | |
| 305 | namespace ndnboost { namespace unordered { namespace detail { |
| 306 | |
| 307 | /////////////////////////////////////////////////////////////////// |
| 308 | // |
| 309 | // Node construction |
| 310 | |
| 311 | template <typename NodeAlloc> |
| 312 | struct node_constructor |
| 313 | { |
| 314 | private: |
| 315 | |
| 316 | typedef NodeAlloc node_allocator; |
| 317 | typedef ndnboost::unordered::detail::allocator_traits<NodeAlloc> |
| 318 | node_allocator_traits; |
| 319 | typedef typename node_allocator_traits::value_type node; |
| 320 | typedef typename node_allocator_traits::pointer node_pointer; |
| 321 | typedef typename node::value_type value_type; |
| 322 | |
| 323 | protected: |
| 324 | |
| 325 | node_allocator& alloc_; |
| 326 | node_pointer node_; |
| 327 | bool node_constructed_; |
| 328 | bool value_constructed_; |
| 329 | |
| 330 | public: |
| 331 | |
| 332 | node_constructor(node_allocator& n) : |
| 333 | alloc_(n), |
| 334 | node_(), |
| 335 | node_constructed_(false), |
| 336 | value_constructed_(false) |
| 337 | { |
| 338 | } |
| 339 | |
| 340 | ~node_constructor(); |
| 341 | |
| 342 | void construct(); |
| 343 | |
| 344 | template <BOOST_UNORDERED_EMPLACE_TEMPLATE> |
| 345 | void construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS) |
| 346 | { |
| 347 | construct(); |
| 348 | ndnboost::unordered::detail::construct_value_impl( |
| 349 | alloc_, node_->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); |
| 350 | value_constructed_ = true; |
| 351 | } |
| 352 | |
| 353 | template <typename A0> |
| 354 | void construct_with_value2(BOOST_FWD_REF(A0) a0) |
| 355 | { |
| 356 | construct(); |
| 357 | ndnboost::unordered::detail::construct_value_impl( |
| 358 | alloc_, node_->value_ptr(), |
| 359 | BOOST_UNORDERED_EMPLACE_ARGS1(ndnboost::forward<A0>(a0))); |
| 360 | value_constructed_ = true; |
| 361 | } |
| 362 | |
| 363 | value_type const& value() const { |
| 364 | BOOST_ASSERT(node_ && node_constructed_ && value_constructed_); |
| 365 | return node_->value(); |
| 366 | } |
| 367 | |
| 368 | // no throw |
| 369 | node_pointer release() |
| 370 | { |
| 371 | BOOST_ASSERT(node_ && node_constructed_); |
| 372 | node_pointer p = node_; |
| 373 | node_ = node_pointer(); |
| 374 | return p; |
| 375 | } |
| 376 | |
| 377 | private: |
| 378 | node_constructor(node_constructor const&); |
| 379 | node_constructor& operator=(node_constructor const&); |
| 380 | }; |
| 381 | |
| 382 | template <typename Alloc> |
| 383 | node_constructor<Alloc>::~node_constructor() |
| 384 | { |
| 385 | if (node_) { |
| 386 | if (value_constructed_) { |
| 387 | ndnboost::unordered::detail::destroy_value_impl(alloc_, |
| 388 | node_->value_ptr()); |
| 389 | } |
| 390 | |
| 391 | if (node_constructed_) { |
| 392 | node_allocator_traits::destroy(alloc_, |
| 393 | ndnboost::addressof(*node_)); |
| 394 | } |
| 395 | |
| 396 | node_allocator_traits::deallocate(alloc_, node_, 1); |
| 397 | } |
| 398 | } |
| 399 | |
| 400 | template <typename Alloc> |
| 401 | void node_constructor<Alloc>::construct() |
| 402 | { |
| 403 | if(!node_) { |
| 404 | node_constructed_ = false; |
| 405 | value_constructed_ = false; |
| 406 | |
| 407 | node_ = node_allocator_traits::allocate(alloc_, 1); |
| 408 | |
| 409 | node_allocator_traits::construct(alloc_, |
| 410 | ndnboost::addressof(*node_), node()); |
| 411 | node_->init(node_); |
| 412 | node_constructed_ = true; |
| 413 | } |
| 414 | else { |
| 415 | BOOST_ASSERT(node_constructed_); |
| 416 | |
| 417 | if (value_constructed_) |
| 418 | { |
| 419 | ndnboost::unordered::detail::destroy_value_impl(alloc_, |
| 420 | node_->value_ptr()); |
| 421 | value_constructed_ = false; |
| 422 | } |
| 423 | } |
| 424 | } |
| 425 | |
| 426 | /////////////////////////////////////////////////////////////////// |
| 427 | // |
| 428 | // Node Holder |
| 429 | // |
| 430 | // Temporary store for nodes. Deletes any that aren't used. |
| 431 | |
| 432 | template <typename NodeAlloc> |
| 433 | struct node_holder : private node_constructor<NodeAlloc> |
| 434 | { |
| 435 | private: |
| 436 | typedef node_constructor<NodeAlloc> base; |
| 437 | |
| 438 | typedef NodeAlloc node_allocator; |
| 439 | typedef ndnboost::unordered::detail::allocator_traits<NodeAlloc> |
| 440 | node_allocator_traits; |
| 441 | typedef typename node_allocator_traits::value_type node; |
| 442 | typedef typename node_allocator_traits::pointer node_pointer; |
| 443 | typedef typename node::value_type value_type; |
| 444 | typedef typename node::link_pointer link_pointer; |
| 445 | typedef ndnboost::unordered::iterator_detail::iterator<node> iterator; |
| 446 | |
| 447 | node_pointer nodes_; |
| 448 | |
| 449 | public: |
| 450 | |
| 451 | template <typename Table> |
| 452 | explicit node_holder(Table& b) : |
| 453 | base(b.node_alloc()), |
| 454 | nodes_() |
| 455 | { |
| 456 | if (b.size_) { |
| 457 | typename Table::link_pointer prev = b.get_previous_start(); |
| 458 | nodes_ = static_cast<node_pointer>(prev->next_); |
| 459 | prev->next_ = link_pointer(); |
| 460 | b.size_ = 0; |
| 461 | } |
| 462 | } |
| 463 | |
| 464 | ~node_holder(); |
| 465 | |
| 466 | void node_for_assignment() |
| 467 | { |
| 468 | if (!this->node_ && nodes_) { |
| 469 | this->node_ = nodes_; |
| 470 | nodes_ = static_cast<node_pointer>(nodes_->next_); |
| 471 | this->node_->init(this->node_); |
| 472 | this->node_->next_ = link_pointer(); |
| 473 | |
| 474 | this->node_constructed_ = true; |
| 475 | this->value_constructed_ = true; |
| 476 | } |
| 477 | } |
| 478 | |
| 479 | template <typename T> |
| 480 | inline void assign_impl(T const& v) { |
| 481 | if (this->node_ && this->value_constructed_) { |
| 482 | this->node_->value() = v; |
| 483 | } |
| 484 | else { |
| 485 | this->construct_with_value2(v); |
| 486 | } |
| 487 | } |
| 488 | |
| 489 | template <typename T1, typename T2> |
| 490 | inline void assign_impl(std::pair<T1 const, T2> const& v) { |
| 491 | this->construct_with_value2(v); |
| 492 | } |
| 493 | |
| 494 | template <typename T> |
| 495 | inline void move_assign_impl(T& v) { |
| 496 | if (this->node_ && this->value_constructed_) { |
| 497 | this->node_->value() = ndnboost::move(v); |
| 498 | } |
| 499 | else { |
| 500 | this->construct_with_value2(ndnboost::move(v)); |
| 501 | } |
| 502 | } |
| 503 | |
| 504 | template <typename T1, typename T2> |
| 505 | inline void move_assign_impl(std::pair<T1 const, T2>& v) { |
| 506 | this->construct_with_value2(ndnboost::move(v)); |
| 507 | } |
| 508 | |
| 509 | node_pointer copy_of(value_type const& v) |
| 510 | { |
| 511 | node_for_assignment(); |
| 512 | assign_impl(v); |
| 513 | return base::release(); |
| 514 | } |
| 515 | |
| 516 | node_pointer move_copy_of(value_type& v) |
| 517 | { |
| 518 | node_for_assignment(); |
| 519 | move_assign_impl(v); |
| 520 | return base::release(); |
| 521 | } |
| 522 | |
| 523 | iterator begin() const |
| 524 | { |
| 525 | return iterator(nodes_); |
| 526 | } |
| 527 | }; |
| 528 | |
| 529 | template <typename Alloc> |
| 530 | node_holder<Alloc>::~node_holder() |
| 531 | { |
| 532 | while (nodes_) { |
| 533 | node_pointer p = nodes_; |
| 534 | nodes_ = static_cast<node_pointer>(p->next_); |
| 535 | |
| 536 | ndnboost::unordered::detail::destroy_value_impl(this->alloc_, |
| 537 | p->value_ptr()); |
| 538 | node_allocator_traits::destroy(this->alloc_, ndnboost::addressof(*p)); |
| 539 | node_allocator_traits::deallocate(this->alloc_, p, 1); |
| 540 | } |
| 541 | } |
| 542 | |
| 543 | /////////////////////////////////////////////////////////////////// |
| 544 | // |
| 545 | // Bucket |
| 546 | |
| 547 | template <typename NodePointer> |
| 548 | struct bucket |
| 549 | { |
| 550 | typedef NodePointer link_pointer; |
| 551 | link_pointer next_; |
| 552 | |
| 553 | bucket() : next_() {} |
| 554 | |
| 555 | link_pointer first_from_start() |
| 556 | { |
| 557 | return next_; |
| 558 | } |
| 559 | |
| 560 | enum { extra_node = true }; |
| 561 | }; |
| 562 | |
| 563 | struct ptr_bucket |
| 564 | { |
| 565 | typedef ptr_bucket* link_pointer; |
| 566 | link_pointer next_; |
| 567 | |
| 568 | ptr_bucket() : next_(0) {} |
| 569 | |
| 570 | link_pointer first_from_start() |
| 571 | { |
| 572 | return this; |
| 573 | } |
| 574 | |
| 575 | enum { extra_node = false }; |
| 576 | }; |
| 577 | |
| 578 | /////////////////////////////////////////////////////////////////// |
| 579 | // |
| 580 | // Hash Policy |
| 581 | |
| 582 | template <typename SizeT> |
| 583 | struct prime_policy |
| 584 | { |
| 585 | template <typename Hash, typename T> |
| 586 | static inline SizeT apply_hash(Hash const& hf, T const& x) { |
| 587 | return hf(x); |
| 588 | } |
| 589 | |
| 590 | static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) { |
| 591 | return hash % bucket_count; |
| 592 | } |
| 593 | |
| 594 | static inline SizeT new_bucket_count(SizeT min) { |
| 595 | return ndnboost::unordered::detail::next_prime(min); |
| 596 | } |
| 597 | |
| 598 | static inline SizeT prev_bucket_count(SizeT max) { |
| 599 | return ndnboost::unordered::detail::prev_prime(max); |
| 600 | } |
| 601 | }; |
| 602 | |
| 603 | template <typename SizeT> |
| 604 | struct mix64_policy |
| 605 | { |
| 606 | template <typename Hash, typename T> |
| 607 | static inline SizeT apply_hash(Hash const& hf, T const& x) { |
| 608 | SizeT key = hf(x); |
| 609 | key = (~key) + (key << 21); // key = (key << 21) - key - 1; |
| 610 | key = key ^ (key >> 24); |
| 611 | key = (key + (key << 3)) + (key << 8); // key * 265 |
| 612 | key = key ^ (key >> 14); |
| 613 | key = (key + (key << 2)) + (key << 4); // key * 21 |
| 614 | key = key ^ (key >> 28); |
| 615 | key = key + (key << 31); |
| 616 | return key; |
| 617 | } |
| 618 | |
| 619 | static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) { |
| 620 | return hash & (bucket_count - 1); |
| 621 | } |
| 622 | |
| 623 | static inline SizeT new_bucket_count(SizeT min) { |
| 624 | if (min <= 4) return 4; |
| 625 | --min; |
| 626 | min |= min >> 1; |
| 627 | min |= min >> 2; |
| 628 | min |= min >> 4; |
| 629 | min |= min >> 8; |
| 630 | min |= min >> 16; |
| 631 | min |= min >> 32; |
| 632 | return min + 1; |
| 633 | } |
| 634 | |
| 635 | static inline SizeT prev_bucket_count(SizeT max) { |
| 636 | max |= max >> 1; |
| 637 | max |= max >> 2; |
| 638 | max |= max >> 4; |
| 639 | max |= max >> 8; |
| 640 | max |= max >> 16; |
| 641 | max |= max >> 32; |
| 642 | return (max >> 1) + 1; |
| 643 | } |
| 644 | }; |
| 645 | |
| 646 | template <int digits, int radix> |
| 647 | struct pick_policy_impl { |
| 648 | typedef prime_policy<std::size_t> type; |
| 649 | }; |
| 650 | |
| 651 | template <> |
| 652 | struct pick_policy_impl<64, 2> { |
| 653 | typedef mix64_policy<std::size_t> type; |
| 654 | }; |
| 655 | |
| 656 | struct pick_policy : |
| 657 | pick_policy_impl< |
| 658 | std::numeric_limits<std::size_t>::digits, |
| 659 | std::numeric_limits<std::size_t>::radix> {}; |
| 660 | |
| 661 | //////////////////////////////////////////////////////////////////////////// |
| 662 | // Functions |
| 663 | |
| 664 | // Assigning and swapping the equality and hash function objects |
| 665 | // needs strong exception safety. To implement that normally we'd |
| 666 | // require one of them to be known to not throw and the other to |
| 667 | // guarantee strong exception safety. Unfortunately they both only |
| 668 | // have basic exception safety. So to acheive strong exception |
| 669 | // safety we have storage space for two copies, and assign the new |
| 670 | // copies to the unused space. Then switch to using that to use |
| 671 | // them. This is implemented in 'set_hash_functions' which |
| 672 | // atomically assigns the new function objects in a strongly |
| 673 | // exception safe manner. |
| 674 | |
| 675 | template <class H, class P, bool NoThrowMoveAssign> |
| 676 | class set_hash_functions; |
| 677 | |
| 678 | template <class H, class P> |
| 679 | class functions |
| 680 | { |
| 681 | public: |
| 682 | static const bool nothrow_move_assignable = |
| 683 | ndnboost::is_nothrow_move_assignable<H>::value && |
| 684 | ndnboost::is_nothrow_move_assignable<P>::value; |
| 685 | static const bool nothrow_move_constructible = |
| 686 | ndnboost::is_nothrow_move_constructible<H>::value && |
| 687 | ndnboost::is_nothrow_move_constructible<P>::value; |
| 688 | |
| 689 | private: |
| 690 | friend class ndnboost::unordered::detail::set_hash_functions<H, P, |
| 691 | nothrow_move_assignable>; |
| 692 | functions& operator=(functions const&); |
| 693 | |
| 694 | typedef compressed<H, P> function_pair; |
| 695 | |
| 696 | typedef typename ndnboost::aligned_storage< |
| 697 | sizeof(function_pair), |
| 698 | ndnboost::alignment_of<function_pair>::value>::type aligned_function; |
| 699 | |
| 700 | bool current_; // The currently active functions. |
| 701 | aligned_function funcs_[2]; |
| 702 | |
| 703 | function_pair const& current() const { |
| 704 | return *static_cast<function_pair const*>( |
| 705 | static_cast<void const*>(&funcs_[current_])); |
| 706 | } |
| 707 | |
| 708 | function_pair& current() { |
| 709 | return *static_cast<function_pair*>( |
| 710 | static_cast<void*>(&funcs_[current_])); |
| 711 | } |
| 712 | |
| 713 | void construct(bool which, H const& hf, P const& eq) |
| 714 | { |
| 715 | new((void*) &funcs_[which]) function_pair(hf, eq); |
| 716 | } |
| 717 | |
| 718 | void construct(bool which, function_pair const& f) |
| 719 | { |
| 720 | new((void*) &funcs_[which]) function_pair(f); |
| 721 | } |
| 722 | |
| 723 | void construct(bool which, function_pair& f, |
| 724 | ndnboost::unordered::detail::move_tag m) |
| 725 | { |
| 726 | new((void*) &funcs_[which]) function_pair(f, m); |
| 727 | } |
| 728 | |
| 729 | void destroy(bool which) |
| 730 | { |
| 731 | ndnboost::unordered::detail::destroy((function_pair*)(&funcs_[which])); |
| 732 | } |
| 733 | |
| 734 | public: |
| 735 | |
| 736 | typedef ndnboost::unordered::detail::set_hash_functions<H, P, |
| 737 | nothrow_move_assignable> set_hash_functions; |
| 738 | |
| 739 | functions(H const& hf, P const& eq) |
| 740 | : current_(false) |
| 741 | { |
| 742 | construct(current_, hf, eq); |
| 743 | } |
| 744 | |
| 745 | functions(functions const& bf) |
| 746 | : current_(false) |
| 747 | { |
| 748 | construct(current_, bf.current()); |
| 749 | } |
| 750 | |
| 751 | functions(functions& bf, ndnboost::unordered::detail::move_tag m) |
| 752 | : current_(false) |
| 753 | { |
| 754 | if (nothrow_move_constructible) { |
| 755 | construct(current_, bf.current(), m); |
| 756 | } |
| 757 | else { |
| 758 | construct(current_, bf.current()); |
| 759 | } |
| 760 | } |
| 761 | |
| 762 | ~functions() { |
| 763 | this->destroy(current_); |
| 764 | } |
| 765 | |
| 766 | H const& hash_function() const { |
| 767 | return current().first(); |
| 768 | } |
| 769 | |
| 770 | P const& key_eq() const { |
| 771 | return current().second(); |
| 772 | } |
| 773 | }; |
| 774 | |
| 775 | template <class H, class P> |
| 776 | class set_hash_functions<H, P, false> |
| 777 | { |
| 778 | set_hash_functions(set_hash_functions const&); |
| 779 | set_hash_functions& operator=(set_hash_functions const&); |
| 780 | |
| 781 | typedef functions<H, P> functions_type; |
| 782 | |
| 783 | functions_type& functions_; |
| 784 | bool tmp_functions_; |
| 785 | |
| 786 | public: |
| 787 | |
| 788 | set_hash_functions(functions_type& f, H const& h, P const& p) |
| 789 | : functions_(f), |
| 790 | tmp_functions_(!f.current_) |
| 791 | { |
| 792 | f.construct(tmp_functions_, h, p); |
| 793 | } |
| 794 | |
| 795 | set_hash_functions(functions_type& f, functions_type const& other) |
| 796 | : functions_(f), |
| 797 | tmp_functions_(!f.current_) |
| 798 | { |
| 799 | f.construct(tmp_functions_, other.current()); |
| 800 | } |
| 801 | |
| 802 | ~set_hash_functions() |
| 803 | { |
| 804 | functions_.destroy(tmp_functions_); |
| 805 | } |
| 806 | |
| 807 | void commit() |
| 808 | { |
| 809 | functions_.current_ = tmp_functions_; |
| 810 | tmp_functions_ = !tmp_functions_; |
| 811 | } |
| 812 | }; |
| 813 | |
| 814 | template <class H, class P> |
| 815 | class set_hash_functions<H, P, true> |
| 816 | { |
| 817 | set_hash_functions(set_hash_functions const&); |
| 818 | set_hash_functions& operator=(set_hash_functions const&); |
| 819 | |
| 820 | typedef functions<H, P> functions_type; |
| 821 | |
| 822 | functions_type& functions_; |
| 823 | H hash_; |
| 824 | P pred_; |
| 825 | |
| 826 | public: |
| 827 | |
| 828 | set_hash_functions(functions_type& f, H const& h, P const& p) : |
| 829 | functions_(f), |
| 830 | hash_(h), |
| 831 | pred_(p) {} |
| 832 | |
| 833 | set_hash_functions(functions_type& f, functions_type const& other) : |
| 834 | functions_(f), |
| 835 | hash_(other.hash_function()), |
| 836 | pred_(other.key_eq()) {} |
| 837 | |
| 838 | void commit() |
| 839 | { |
| 840 | functions_.current().first() = ndnboost::move(hash_); |
| 841 | functions_.current().second() = ndnboost::move(pred_); |
| 842 | } |
| 843 | }; |
| 844 | |
| 845 | //////////////////////////////////////////////////////////////////////////// |
| 846 | // rvalue parameters when type can't be a BOOST_RV_REF(T) parameter |
| 847 | // e.g. for int |
| 848 | |
| 849 | #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) |
| 850 | # define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T) |
| 851 | #else |
| 852 | struct please_ignore_this_overload { |
| 853 | typedef please_ignore_this_overload type; |
| 854 | }; |
| 855 | |
| 856 | template <typename T> |
| 857 | struct rv_ref_impl { |
| 858 | typedef BOOST_RV_REF(T) type; |
| 859 | }; |
| 860 | |
| 861 | template <typename T> |
| 862 | struct rv_ref : |
| 863 | ndnboost::detail::if_true< |
| 864 | ndnboost::is_class<T>::value |
| 865 | >::BOOST_NESTED_TEMPLATE then < |
| 866 | ndnboost::unordered::detail::rv_ref_impl<T>, |
| 867 | please_ignore_this_overload |
| 868 | >::type |
| 869 | {}; |
| 870 | |
| 871 | # define BOOST_UNORDERED_RV_REF(T) \ |
| 872 | typename ndnboost::unordered::detail::rv_ref<T>::type |
| 873 | #endif |
| 874 | }}} |
| 875 | |
| 876 | #endif |