File indexing completed on 2025-07-09 08:28:05
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_UNORDERED_DETAIL_FCA_HPP
0008 #define BOOST_UNORDERED_DETAIL_FCA_HPP
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116 #include <boost/unordered/detail/prime_fmod.hpp>
0117 #include <boost/unordered/detail/serialize_tracked_address.hpp>
0118 #include <boost/unordered/detail/opt_storage.hpp>
0119
0120 #include <boost/assert.hpp>
0121 #include <boost/core/allocator_access.hpp>
0122 #include <boost/core/bit.hpp>
0123 #include <boost/core/empty_value.hpp>
0124 #include <boost/core/invoke_swap.hpp>
0125 #include <boost/core/no_exceptions_support.hpp>
0126 #include <boost/core/serialization.hpp>
0127 #include <boost/cstdint.hpp>
0128
0129 #include <boost/config.hpp>
0130
0131 #include <iterator>
0132
0133 namespace boost {
0134 namespace unordered {
0135 namespace detail {
0136
0137 template <class ValueType, class VoidPtr> struct node
0138 {
0139 typedef ValueType value_type;
0140 typedef typename boost::pointer_traits<VoidPtr>::template rebind_to<
0141 node>::type node_pointer;
0142
0143 node_pointer next;
0144 opt_storage<value_type> buf;
0145
0146 node() noexcept : next(), buf() {}
0147
0148 value_type* value_ptr() noexcept
0149 {
0150 return buf.address();
0151 }
0152
0153 value_type& value() noexcept
0154 {
0155 return *buf.address();
0156 }
0157 };
0158
0159 template <class Node, class VoidPtr> struct bucket
0160 {
0161 typedef typename boost::pointer_traits<VoidPtr>::template rebind_to<
0162 Node>::type node_pointer;
0163
0164 typedef typename boost::pointer_traits<VoidPtr>::template rebind_to<
0165 bucket>::type bucket_pointer;
0166
0167 node_pointer next;
0168
0169 bucket() noexcept : next() {}
0170 };
0171
0172 template <class Bucket> struct bucket_group
0173 {
0174 typedef typename Bucket::bucket_pointer bucket_pointer;
0175 typedef
0176 typename boost::pointer_traits<bucket_pointer>::template rebind_to<
0177 bucket_group>::type bucket_group_pointer;
0178
0179 BOOST_STATIC_CONSTANT(std::size_t, N = sizeof(std::size_t) * CHAR_BIT);
0180
0181 bucket_pointer buckets;
0182 std::size_t bitmask;
0183 bucket_group_pointer next, prev;
0184
0185 bucket_group() noexcept : buckets(), bitmask(0), next(), prev() {}
0186 ~bucket_group() {}
0187 };
0188
0189 inline std::size_t set_bit(std::size_t n) { return std::size_t(1) << n; }
0190
0191 inline std::size_t reset_bit(std::size_t n)
0192 {
0193 return ~(std::size_t(1) << n);
0194 }
0195
0196 inline std::size_t reset_first_bits(std::size_t n)
0197 {
0198 return ~(~(std::size_t(0)) >> (sizeof(std::size_t) * 8 - n));
0199 }
0200
0201 template <class Bucket> struct grouped_bucket_iterator
0202 {
0203 public:
0204 typedef typename Bucket::bucket_pointer bucket_pointer;
0205 typedef
0206 typename boost::pointer_traits<bucket_pointer>::template rebind_to<
0207 bucket_group<Bucket> >::type bucket_group_pointer;
0208
0209 typedef Bucket value_type;
0210 typedef typename boost::pointer_traits<bucket_pointer>::difference_type
0211 difference_type;
0212 typedef Bucket& reference;
0213 typedef Bucket* pointer;
0214 typedef std::forward_iterator_tag iterator_category;
0215
0216 private:
0217 bucket_pointer p;
0218 bucket_group_pointer pbg;
0219
0220 public:
0221 grouped_bucket_iterator() : p(), pbg() {}
0222
0223 reference operator*() const noexcept { return dereference(); }
0224 pointer operator->() const noexcept { return boost::to_address(p); }
0225
0226 grouped_bucket_iterator& operator++() noexcept
0227 {
0228 increment();
0229 return *this;
0230 }
0231
0232 grouped_bucket_iterator operator++(int) noexcept
0233 {
0234 grouped_bucket_iterator old = *this;
0235 increment();
0236 return old;
0237 }
0238
0239 bool operator==(grouped_bucket_iterator const& other) const noexcept
0240 {
0241 return equal(other);
0242 }
0243
0244 bool operator!=(grouped_bucket_iterator const& other) const noexcept
0245 {
0246 return !equal(other);
0247 }
0248
0249 private:
0250 template <typename, typename, typename>
0251 friend class grouped_bucket_array;
0252
0253 BOOST_STATIC_CONSTANT(std::size_t, N = bucket_group<Bucket>::N);
0254
0255 grouped_bucket_iterator(bucket_pointer p_, bucket_group_pointer pbg_)
0256 : p(p_), pbg(pbg_)
0257 {
0258 }
0259
0260 Bucket& dereference() const noexcept { return *p; }
0261
0262 bool equal(const grouped_bucket_iterator& x) const noexcept
0263 {
0264 return p == x.p;
0265 }
0266
0267 void increment() noexcept
0268 {
0269 std::size_t const offset = static_cast<std::size_t>(p - pbg->buckets);
0270
0271 std::size_t n = std::size_t(boost::core::countr_zero(
0272 pbg->bitmask & reset_first_bits(offset + 1)));
0273
0274 if (n < N) {
0275 p = pbg->buckets + static_cast<difference_type>(n);
0276 } else {
0277 pbg = pbg->next;
0278
0279 std::ptrdiff_t x = boost::core::countr_zero(pbg->bitmask);
0280 p = pbg->buckets + x;
0281 }
0282 }
0283
0284 template <typename Archive>
0285 friend void serialization_track(
0286 Archive& ar, grouped_bucket_iterator const& x)
0287 {
0288
0289 track_address(ar, x.p);
0290 track_address(ar, x.pbg);
0291 }
0292
0293 friend class boost::serialization::access;
0294
0295 template <typename Archive> void serialize(Archive& ar, unsigned int)
0296 {
0297
0298 serialize_tracked_address(ar, p);
0299 serialize_tracked_address(ar, pbg);
0300 }
0301 };
0302
0303 template <class Node> struct const_grouped_local_bucket_iterator;
0304
0305 template <class Node> struct grouped_local_bucket_iterator
0306 {
0307 typedef typename Node::node_pointer node_pointer;
0308
0309 public:
0310 typedef typename Node::value_type value_type;
0311 typedef value_type element_type;
0312 typedef value_type* pointer;
0313 typedef value_type& reference;
0314 typedef std::ptrdiff_t difference_type;
0315 typedef std::forward_iterator_tag iterator_category;
0316
0317 grouped_local_bucket_iterator() : p() {}
0318
0319 reference operator*() const noexcept { return dereference(); }
0320
0321 pointer operator->() const noexcept
0322 {
0323 return std::addressof(dereference());
0324 }
0325
0326 grouped_local_bucket_iterator& operator++() noexcept
0327 {
0328 increment();
0329 return *this;
0330 }
0331
0332 grouped_local_bucket_iterator operator++(int) noexcept
0333 {
0334 grouped_local_bucket_iterator old = *this;
0335 increment();
0336 return old;
0337 }
0338
0339 bool operator==(
0340 grouped_local_bucket_iterator const& other) const noexcept
0341 {
0342 return equal(other);
0343 }
0344
0345 bool operator!=(
0346 grouped_local_bucket_iterator const& other) const noexcept
0347 {
0348 return !equal(other);
0349 }
0350
0351 private:
0352 template <typename, typename, typename>
0353 friend class grouped_bucket_array;
0354
0355 template <class> friend struct const_grouped_local_bucket_iterator;
0356
0357 grouped_local_bucket_iterator(node_pointer p_) : p(p_) {}
0358
0359 value_type& dereference() const noexcept { return p->value(); }
0360
0361 bool equal(const grouped_local_bucket_iterator& x) const noexcept
0362 {
0363 return p == x.p;
0364 }
0365
0366 void increment() noexcept { p = p->next; }
0367
0368 node_pointer p;
0369 };
0370
0371 template <class Node> struct const_grouped_local_bucket_iterator
0372 {
0373 typedef typename Node::node_pointer node_pointer;
0374
0375 public:
0376 typedef typename Node::value_type const value_type;
0377 typedef value_type const element_type;
0378 typedef value_type const* pointer;
0379 typedef value_type const& reference;
0380 typedef std::ptrdiff_t difference_type;
0381 typedef std::forward_iterator_tag iterator_category;
0382
0383 const_grouped_local_bucket_iterator() : p() {}
0384 const_grouped_local_bucket_iterator(
0385 grouped_local_bucket_iterator<Node> it)
0386 : p(it.p)
0387 {
0388 }
0389
0390 reference operator*() const noexcept { return dereference(); }
0391
0392 pointer operator->() const noexcept
0393 {
0394 return std::addressof(dereference());
0395 }
0396
0397 const_grouped_local_bucket_iterator& operator++() noexcept
0398 {
0399 increment();
0400 return *this;
0401 }
0402
0403 const_grouped_local_bucket_iterator operator++(int) noexcept
0404 {
0405 const_grouped_local_bucket_iterator old = *this;
0406 increment();
0407 return old;
0408 }
0409
0410 bool operator==(
0411 const_grouped_local_bucket_iterator const& other) const noexcept
0412 {
0413 return equal(other);
0414 }
0415
0416 bool operator!=(
0417 const_grouped_local_bucket_iterator const& other) const noexcept
0418 {
0419 return !equal(other);
0420 }
0421
0422 private:
0423 template <typename, typename, typename>
0424 friend class grouped_bucket_array;
0425
0426 const_grouped_local_bucket_iterator(node_pointer p_) : p(p_) {}
0427
0428 value_type& dereference() const noexcept { return p->value(); }
0429
0430 bool equal(const const_grouped_local_bucket_iterator& x) const noexcept
0431 {
0432 return p == x.p;
0433 }
0434
0435 void increment() noexcept { p = p->next; }
0436
0437 node_pointer p;
0438 };
0439
0440 template <class T> struct span
0441 {
0442 T* begin() const noexcept { return data; }
0443 T* end() const noexcept { return data + size; }
0444
0445 T* data;
0446 std::size_t size;
0447
0448 span(T* data_, std::size_t size_) : data(data_), size(size_) {}
0449 };
0450
0451 template <class Bucket, class Allocator, class SizePolicy>
0452 class grouped_bucket_array
0453 : boost::empty_value<typename boost::allocator_rebind<Allocator,
0454 node<typename boost::allocator_value_type<Allocator>::type,
0455 typename boost::allocator_void_pointer<Allocator>::type> >::
0456 type>
0457 {
0458 typedef typename boost::allocator_value_type<Allocator>::type
0459 allocator_value_type;
0460 typedef
0461 typename boost::allocator_void_pointer<Allocator>::type void_pointer;
0462 typedef typename boost::allocator_difference_type<Allocator>::type
0463 difference_type;
0464
0465 public:
0466 typedef typename boost::allocator_rebind<Allocator,
0467 node<allocator_value_type, void_pointer> >::type node_allocator_type;
0468
0469 typedef node<allocator_value_type, void_pointer> node_type;
0470 typedef typename boost::allocator_pointer<node_allocator_type>::type
0471 node_pointer;
0472 typedef SizePolicy size_policy;
0473
0474 private:
0475 typedef typename boost::allocator_rebind<Allocator, Bucket>::type
0476 bucket_allocator_type;
0477 typedef typename boost::allocator_pointer<bucket_allocator_type>::type
0478 bucket_pointer;
0479 typedef boost::pointer_traits<bucket_pointer> bucket_pointer_traits;
0480
0481 typedef bucket_group<Bucket> group;
0482 typedef typename boost::allocator_rebind<Allocator, group>::type
0483 group_allocator_type;
0484 typedef typename boost::allocator_pointer<group_allocator_type>::type
0485 group_pointer;
0486 typedef typename boost::pointer_traits<group_pointer>
0487 group_pointer_traits;
0488
0489 public:
0490 typedef Bucket value_type;
0491 typedef Bucket bucket_type;
0492 typedef std::size_t size_type;
0493 typedef Allocator allocator_type;
0494 typedef grouped_bucket_iterator<Bucket> iterator;
0495 typedef grouped_local_bucket_iterator<node_type> local_iterator;
0496 typedef const_grouped_local_bucket_iterator<node_type>
0497 const_local_iterator;
0498
0499 private:
0500 std::size_t size_index_, size_;
0501 bucket_pointer buckets;
0502 group_pointer groups;
0503
0504 public:
0505 static std::size_t bucket_count_for(std::size_t num_buckets)
0506 {
0507 if (num_buckets == 0) {
0508 return 0;
0509 }
0510 return size_policy::size(size_policy::size_index(num_buckets));
0511 }
0512
0513 grouped_bucket_array()
0514 : empty_value<node_allocator_type>(
0515 empty_init_t(), node_allocator_type()),
0516 size_index_(0), size_(0), buckets(), groups()
0517 {
0518 }
0519
0520 grouped_bucket_array(size_type n, const Allocator& al)
0521 : empty_value<node_allocator_type>(
0522 empty_init_t(), node_allocator_type(al)),
0523 size_index_(0), size_(0), buckets(), groups()
0524 {
0525 if (n == 0) {
0526 return;
0527 }
0528
0529 size_index_ = size_policy::size_index(n);
0530 size_ = size_policy::size(size_index_);
0531
0532 bucket_allocator_type bucket_alloc = this->get_bucket_allocator();
0533 group_allocator_type group_alloc = this->get_group_allocator();
0534
0535 size_type const num_buckets = buckets_len();
0536 size_type const num_groups = groups_len();
0537
0538 buckets = boost::allocator_allocate(bucket_alloc, num_buckets);
0539 BOOST_TRY
0540 {
0541 groups = boost::allocator_allocate(group_alloc, num_groups);
0542
0543 bucket_type* pb = boost::to_address(buckets);
0544 for (size_type i = 0; i < num_buckets; ++i) {
0545 new (pb + i) bucket_type();
0546 }
0547
0548 group* pg = boost::to_address(groups);
0549 for (size_type i = 0; i < num_groups; ++i) {
0550 new (pg + i) group();
0551 }
0552 }
0553 BOOST_CATCH(...)
0554 {
0555 boost::allocator_deallocate(bucket_alloc, buckets, num_buckets);
0556 BOOST_RETHROW
0557 }
0558 BOOST_CATCH_END
0559
0560 size_type const N = group::N;
0561 group_pointer pbg =
0562 groups + static_cast<difference_type>(num_groups - 1);
0563
0564 pbg->buckets =
0565 buckets + static_cast<difference_type>(N * (size_ / N));
0566 pbg->bitmask = set_bit(size_ % N);
0567 pbg->next = pbg->prev = pbg;
0568 }
0569
0570 ~grouped_bucket_array() { this->deallocate(); }
0571
0572 grouped_bucket_array(grouped_bucket_array const&) = delete;
0573 grouped_bucket_array& operator=(grouped_bucket_array const&) = delete;
0574
0575 grouped_bucket_array(grouped_bucket_array&& other) noexcept
0576 : empty_value<node_allocator_type>(
0577 empty_init_t(), other.get_node_allocator()),
0578 size_index_(other.size_index_),
0579 size_(other.size_),
0580 buckets(other.buckets),
0581 groups(other.groups)
0582 {
0583 other.size_ = 0;
0584 other.size_index_ = 0;
0585 other.buckets = bucket_pointer();
0586 other.groups = group_pointer();
0587 }
0588
0589 grouped_bucket_array& operator=(grouped_bucket_array&& other) noexcept
0590 {
0591 BOOST_ASSERT(
0592 this->get_node_allocator() == other.get_node_allocator());
0593
0594 if (this == std::addressof(other)) {
0595 return *this;
0596 }
0597
0598 this->deallocate();
0599 size_index_ = other.size_index_;
0600 size_ = other.size_;
0601
0602 buckets = other.buckets;
0603 groups = other.groups;
0604
0605 other.size_index_ = 0;
0606 other.size_ = 0;
0607 other.buckets = bucket_pointer();
0608 other.groups = group_pointer();
0609
0610 return *this;
0611 }
0612
0613 #if defined(BOOST_MSVC)
0614 #pragma warning(push)
0615 #pragma warning(disable : 4100)
0616 #endif
0617
0618 void deallocate() noexcept
0619 {
0620 if (buckets) {
0621 size_type const num_buckets = buckets_len();
0622 bucket_type* pb = boost::to_address(buckets);
0623 (void)pb;
0624
0625 for (size_type i = 0; i < num_buckets; ++i) {
0626 (pb + i)->~bucket_type();
0627 }
0628
0629 bucket_allocator_type bucket_alloc = this->get_bucket_allocator();
0630 boost::allocator_deallocate(bucket_alloc, buckets, num_buckets);
0631
0632 buckets = bucket_pointer();
0633 }
0634
0635 if (groups) {
0636 size_type const num_groups = groups_len();
0637 group* pg = boost::to_address(groups);
0638 (void)pg;
0639
0640 for (size_type i = 0; i < num_groups; ++i) {
0641 (pg + i)->~group();
0642 }
0643
0644 group_allocator_type group_alloc = this->get_group_allocator();
0645 boost::allocator_deallocate(group_alloc, groups, num_groups);
0646
0647 groups = group_pointer();
0648 }
0649 }
0650
0651 #if defined(BOOST_MSVC)
0652 #pragma warning(pop)
0653 #endif
0654
0655 void swap(grouped_bucket_array& other)
0656 {
0657 std::swap(size_index_, other.size_index_);
0658 std::swap(size_, other.size_);
0659 std::swap(buckets, other.buckets);
0660 std::swap(groups, other.groups);
0661
0662 swap_allocator_if_pocs(other);
0663 }
0664
0665 node_allocator_type const& get_node_allocator() const
0666 {
0667 return empty_value<node_allocator_type>::get();
0668 }
0669
0670 node_allocator_type& get_node_allocator()
0671 {
0672 return empty_value<node_allocator_type>::get();
0673 }
0674
0675 bucket_allocator_type get_bucket_allocator() const
0676 {
0677 return bucket_allocator_type(this->get_node_allocator());
0678 }
0679
0680 group_allocator_type get_group_allocator() const
0681 {
0682 return group_allocator_type(this->get_node_allocator());
0683 }
0684
0685 Allocator get_allocator() const
0686 {
0687 return Allocator(this->get_node_allocator());
0688 }
0689
0690 size_type buckets_len() const noexcept { return size_ + 1; }
0691
0692 size_type groups_len() const noexcept { return size_ / group::N + 1; }
0693
0694 void reset_allocator(Allocator const& allocator_)
0695 {
0696 this->get_node_allocator() = node_allocator_type(allocator_);
0697 }
0698
0699 size_type bucket_count() const { return size_; }
0700
0701 iterator begin() const { return size_ == 0 ? end() : ++at(size_); }
0702
0703 iterator end() const
0704 {
0705
0706
0707 iterator pbg;
0708 pbg.p =
0709 buckets + static_cast<difference_type>(this->buckets_len() - 1);
0710 return pbg;
0711 }
0712
0713 local_iterator begin(size_type n) const
0714 {
0715 if (size_ == 0) {
0716 return this->end(n);
0717 }
0718
0719 return local_iterator(
0720 (buckets + static_cast<difference_type>(n))->next);
0721 }
0722
0723 local_iterator end(size_type) const { return local_iterator(); }
0724
0725 size_type capacity() const noexcept { return size_; }
0726
0727 iterator at(size_type n) const
0728 {
0729 if (size_ > 0) {
0730 std::size_t const N = group::N;
0731
0732 iterator pbg(buckets + static_cast<difference_type>(n),
0733 groups + static_cast<difference_type>(n / N));
0734
0735 return pbg;
0736 } else {
0737 return this->end();
0738 }
0739 }
0740
0741 span<Bucket> raw()
0742 {
0743 BOOST_ASSERT(size_ == 0 || size_ < this->buckets_len());
0744 return span<Bucket>(boost::to_address(buckets), size_);
0745 }
0746
0747 size_type position(std::size_t hash) const
0748 {
0749 return size_policy::position(hash, size_index_);
0750 }
0751
0752 void clear()
0753 {
0754 this->deallocate();
0755 size_index_ = 0;
0756 size_ = 0;
0757 }
0758
0759 void append_bucket_group(iterator itb) noexcept
0760 {
0761 std::size_t const N = group::N;
0762
0763 bool const is_empty_bucket = (!itb->next);
0764 if (is_empty_bucket) {
0765 bucket_pointer pb = itb.p;
0766 group_pointer pbg = itb.pbg;
0767
0768 std::size_t n =
0769 static_cast<std::size_t>(boost::to_address(pb) - &buckets[0]);
0770
0771 bool const is_empty_group = (!pbg->bitmask);
0772 if (is_empty_group) {
0773 size_type const num_groups = this->groups_len();
0774 group_pointer last_group =
0775 groups + static_cast<difference_type>(num_groups - 1);
0776
0777 pbg->buckets =
0778 buckets + static_cast<difference_type>(N * (n / N));
0779 pbg->next = last_group->next;
0780 pbg->next->prev = pbg;
0781 pbg->prev = last_group;
0782 pbg->prev->next = pbg;
0783 }
0784
0785 pbg->bitmask |= set_bit(n % N);
0786 }
0787 }
0788
0789 void insert_node(iterator itb, node_pointer p) noexcept
0790 {
0791 this->append_bucket_group(itb);
0792
0793 p->next = itb->next;
0794 itb->next = p;
0795 }
0796
0797 void insert_node_hint(
0798 iterator itb, node_pointer p, node_pointer hint) noexcept
0799 {
0800 this->append_bucket_group(itb);
0801
0802 if (hint) {
0803 p->next = hint->next;
0804 hint->next = p;
0805 } else {
0806 p->next = itb->next;
0807 itb->next = p;
0808 }
0809 }
0810
0811 void extract_node(iterator itb, node_pointer p) noexcept
0812 {
0813 node_pointer* pp = std::addressof(itb->next);
0814 while ((*pp) != p)
0815 pp = std::addressof((*pp)->next);
0816 *pp = p->next;
0817 if (!itb->next)
0818 unlink_bucket(itb);
0819 }
0820
0821 void extract_node_after(iterator itb, node_pointer* pp) noexcept
0822 {
0823 *pp = (*pp)->next;
0824 if (!itb->next)
0825 unlink_bucket(itb);
0826 }
0827
0828 void unlink_empty_buckets() noexcept
0829 {
0830 std::size_t const N = group::N;
0831
0832 group_pointer pbg = groups,
0833 last = groups + static_cast<difference_type>(
0834 this->groups_len() - 1);
0835
0836 for (; pbg != last; ++pbg) {
0837 if (!pbg->buckets) {
0838 continue;
0839 }
0840
0841 for (std::size_t n = 0; n < N; ++n) {
0842 bucket_pointer bs = pbg->buckets;
0843 bucket_type& b = bs[static_cast<std::ptrdiff_t>(n)];
0844 if (!b.next)
0845 pbg->bitmask &= reset_bit(n);
0846 }
0847 if (!pbg->bitmask && pbg->next)
0848 unlink_group(pbg);
0849 }
0850
0851
0852 for (std::size_t n = 0; n < size_ % N; ++n) {
0853 if (!pbg->buckets[static_cast<std::ptrdiff_t>(n)].next)
0854 pbg->bitmask &= reset_bit(n);
0855 }
0856 }
0857
0858 void unlink_bucket(iterator itb)
0859 {
0860 typename iterator::bucket_pointer p = itb.p;
0861 typename iterator::bucket_group_pointer pbg = itb.pbg;
0862 if (!(pbg->bitmask &=
0863 reset_bit(static_cast<std::size_t>(p - pbg->buckets))))
0864 unlink_group(pbg);
0865 }
0866
0867 private:
0868 void unlink_group(group_pointer pbg)
0869 {
0870 pbg->next->prev = pbg->prev;
0871 pbg->prev->next = pbg->next;
0872 pbg->prev = pbg->next = group_pointer();
0873 }
0874
0875 void swap_allocator_if_pocs(grouped_bucket_array& other)
0876 {
0877 using allocator_pocs =
0878 typename boost::allocator_propagate_on_container_swap<
0879 allocator_type>::type;
0880 swap_allocator_if_pocs(
0881 other, std::integral_constant<bool, allocator_pocs::value>());
0882 }
0883
0884 void swap_allocator_if_pocs(
0885 grouped_bucket_array& other, std::true_type )
0886 {
0887 boost::core::invoke_swap(
0888 get_node_allocator(), other.get_node_allocator());
0889 }
0890
0891 void swap_allocator_if_pocs(
0892 grouped_bucket_array&, std::false_type )
0893 {
0894 }
0895 };
0896 }
0897 }
0898 }
0899
0900 #endif