File indexing completed on 2025-09-15 08:53:53
0001
0002
0003
0004
0005
0006 #ifndef BOOST_UNORDERED_UNORDERED_FLAT_SET_HPP_INCLUDED
0007 #define BOOST_UNORDERED_UNORDERED_FLAT_SET_HPP_INCLUDED
0008
0009 #include <boost/config.hpp>
0010 #if defined(BOOST_HAS_PRAGMA_ONCE)
0011 #pragma once
0012 #endif
0013
0014 #include <boost/unordered/concurrent_flat_set_fwd.hpp>
0015 #include <boost/unordered/detail/foa/flat_set_types.hpp>
0016 #include <boost/unordered/detail/foa/table.hpp>
0017 #include <boost/unordered/detail/serialize_container.hpp>
0018 #include <boost/unordered/detail/type_traits.hpp>
0019 #include <boost/unordered/unordered_flat_set_fwd.hpp>
0020
0021 #include <boost/core/allocator_access.hpp>
0022 #include <boost/container_hash/hash.hpp>
0023
0024 #include <initializer_list>
0025 #include <iterator>
0026 #include <type_traits>
0027 #include <utility>
0028
0029 namespace boost {
0030 namespace unordered {
0031
0032 #if defined(BOOST_MSVC)
0033 #pragma warning(push)
0034 #pragma warning(disable : 4714)
0035 #endif
0036
0037 template <class Key, class Hash, class KeyEqual, class Allocator>
0038 class unordered_flat_set
0039 {
0040 template <class Key2, class Hash2, class KeyEqual2, class Allocator2>
0041 friend class concurrent_flat_set;
0042
0043 using set_types = detail::foa::flat_set_types<Key>;
0044
0045 using table_type = detail::foa::table<set_types, Hash, KeyEqual,
0046 typename boost::allocator_rebind<Allocator,
0047 typename set_types::value_type>::type>;
0048
0049 table_type table_;
0050
0051 template <class K, class H, class KE, class A>
0052 bool friend operator==(unordered_flat_set<K, H, KE, A> const& lhs,
0053 unordered_flat_set<K, H, KE, A> const& rhs);
0054
0055 template <class K, class H, class KE, class A, class Pred>
0056 typename unordered_flat_set<K, H, KE, A>::size_type friend erase_if(
0057 unordered_flat_set<K, H, KE, A>& set, Pred pred);
0058
0059 public:
0060 using key_type = Key;
0061 using value_type = typename set_types::value_type;
0062 using init_type = typename set_types::init_type;
0063 using size_type = std::size_t;
0064 using difference_type = std::ptrdiff_t;
0065 using hasher = Hash;
0066 using key_equal = KeyEqual;
0067 using allocator_type = Allocator;
0068 using reference = value_type&;
0069 using const_reference = value_type const&;
0070 using pointer = typename boost::allocator_pointer<allocator_type>::type;
0071 using const_pointer =
0072 typename boost::allocator_const_pointer<allocator_type>::type;
0073 using iterator = typename table_type::iterator;
0074 using const_iterator = typename table_type::const_iterator;
0075
0076 #if defined(BOOST_UNORDERED_ENABLE_STATS)
0077 using stats = typename table_type::stats;
0078 #endif
0079
0080 unordered_flat_set() : unordered_flat_set(0) {}
0081
0082 explicit unordered_flat_set(size_type n, hasher const& h = hasher(),
0083 key_equal const& pred = key_equal(),
0084 allocator_type const& a = allocator_type())
0085 : table_(n, h, pred, a)
0086 {
0087 }
0088
0089 unordered_flat_set(size_type n, allocator_type const& a)
0090 : unordered_flat_set(n, hasher(), key_equal(), a)
0091 {
0092 }
0093
0094 unordered_flat_set(size_type n, hasher const& h, allocator_type const& a)
0095 : unordered_flat_set(n, h, key_equal(), a)
0096 {
0097 }
0098
0099 template <class InputIterator>
0100 unordered_flat_set(
0101 InputIterator f, InputIterator l, allocator_type const& a)
0102 : unordered_flat_set(f, l, size_type(0), hasher(), key_equal(), a)
0103 {
0104 }
0105
0106 explicit unordered_flat_set(allocator_type const& a)
0107 : unordered_flat_set(0, a)
0108 {
0109 }
0110
0111 template <class Iterator>
0112 unordered_flat_set(Iterator first, Iterator last, size_type n = 0,
0113 hasher const& h = hasher(), key_equal const& pred = key_equal(),
0114 allocator_type const& a = allocator_type())
0115 : unordered_flat_set(n, h, pred, a)
0116 {
0117 this->insert(first, last);
0118 }
0119
0120 template <class InputIt>
0121 unordered_flat_set(
0122 InputIt first, InputIt last, size_type n, allocator_type const& a)
0123 : unordered_flat_set(first, last, n, hasher(), key_equal(), a)
0124 {
0125 }
0126
0127 template <class Iterator>
0128 unordered_flat_set(Iterator first, Iterator last, size_type n,
0129 hasher const& h, allocator_type const& a)
0130 : unordered_flat_set(first, last, n, h, key_equal(), a)
0131 {
0132 }
0133
0134 unordered_flat_set(unordered_flat_set const& other) : table_(other.table_)
0135 {
0136 }
0137
0138 unordered_flat_set(
0139 unordered_flat_set const& other, allocator_type const& a)
0140 : table_(other.table_, a)
0141 {
0142 }
0143
0144 unordered_flat_set(unordered_flat_set&& other)
0145 noexcept(std::is_nothrow_move_constructible<table_type>::value)
0146 : table_(std::move(other.table_))
0147 {
0148 }
0149
0150 unordered_flat_set(unordered_flat_set&& other, allocator_type const& al)
0151 : table_(std::move(other.table_), al)
0152 {
0153 }
0154
0155 unordered_flat_set(std::initializer_list<value_type> ilist,
0156 size_type n = 0, hasher const& h = hasher(),
0157 key_equal const& pred = key_equal(),
0158 allocator_type const& a = allocator_type())
0159 : unordered_flat_set(ilist.begin(), ilist.end(), n, h, pred, a)
0160 {
0161 }
0162
0163 unordered_flat_set(
0164 std::initializer_list<value_type> il, allocator_type const& a)
0165 : unordered_flat_set(il, size_type(0), hasher(), key_equal(), a)
0166 {
0167 }
0168
0169 unordered_flat_set(std::initializer_list<value_type> init, size_type n,
0170 allocator_type const& a)
0171 : unordered_flat_set(init, n, hasher(), key_equal(), a)
0172 {
0173 }
0174
0175 unordered_flat_set(std::initializer_list<value_type> init, size_type n,
0176 hasher const& h, allocator_type const& a)
0177 : unordered_flat_set(init, n, h, key_equal(), a)
0178 {
0179 }
0180
0181 template <bool avoid_explicit_instantiation = true>
0182 unordered_flat_set(
0183 concurrent_flat_set<Key, Hash, KeyEqual, Allocator>&& other)
0184 : table_(std::move(other.table_))
0185 {
0186 }
0187
0188 ~unordered_flat_set() = default;
0189
0190 unordered_flat_set& operator=(unordered_flat_set const& other)
0191 {
0192 table_ = other.table_;
0193 return *this;
0194 }
0195
0196 unordered_flat_set& operator=(unordered_flat_set&& other) noexcept(
0197 noexcept(std::declval<table_type&>() = std::declval<table_type&&>()))
0198 {
0199 table_ = std::move(other.table_);
0200 return *this;
0201 }
0202
0203 unordered_flat_set& operator=(std::initializer_list<value_type> il)
0204 {
0205 this->clear();
0206 this->insert(il.begin(), il.end());
0207 return *this;
0208 }
0209
0210 allocator_type get_allocator() const noexcept
0211 {
0212 return table_.get_allocator();
0213 }
0214
0215
0216
0217
0218 iterator begin() noexcept { return table_.begin(); }
0219 const_iterator begin() const noexcept { return table_.begin(); }
0220 const_iterator cbegin() const noexcept { return table_.cbegin(); }
0221
0222 iterator end() noexcept { return table_.end(); }
0223 const_iterator end() const noexcept { return table_.end(); }
0224 const_iterator cend() const noexcept { return table_.cend(); }
0225
0226
0227
0228
0229 BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept
0230 {
0231 return table_.empty();
0232 }
0233
0234 size_type size() const noexcept { return table_.size(); }
0235
0236 size_type max_size() const noexcept { return table_.max_size(); }
0237
0238
0239
0240
0241 void clear() noexcept { table_.clear(); }
0242
0243 BOOST_FORCEINLINE std::pair<iterator, bool> insert(
0244 value_type const& value)
0245 {
0246 return table_.insert(value);
0247 }
0248
0249 BOOST_FORCEINLINE std::pair<iterator, bool> insert(value_type&& value)
0250 {
0251 return table_.insert(std::move(value));
0252 }
0253
0254 template <class K>
0255 BOOST_FORCEINLINE typename std::enable_if<
0256 detail::transparent_non_iterable<K, unordered_flat_set>::value,
0257 std::pair<iterator, bool> >::type
0258 insert(K&& k)
0259 {
0260 return table_.try_emplace(std::forward<K>(k));
0261 }
0262
0263 BOOST_FORCEINLINE iterator insert(const_iterator, value_type const& value)
0264 {
0265 return table_.insert(value).first;
0266 }
0267
0268 BOOST_FORCEINLINE iterator insert(const_iterator, value_type&& value)
0269 {
0270 return table_.insert(std::move(value)).first;
0271 }
0272
0273 template <class K>
0274 BOOST_FORCEINLINE typename std::enable_if<
0275 detail::transparent_non_iterable<K, unordered_flat_set>::value,
0276 iterator>::type
0277 insert(const_iterator, K&& k)
0278 {
0279 return table_.try_emplace(std::forward<K>(k)).first;
0280 }
0281
0282 template <class InputIterator>
0283 void insert(InputIterator first, InputIterator last)
0284 {
0285 for (auto pos = first; pos != last; ++pos) {
0286 table_.emplace(*pos);
0287 }
0288 }
0289
0290 void insert(std::initializer_list<value_type> ilist)
0291 {
0292 this->insert(ilist.begin(), ilist.end());
0293 }
0294
0295 template <class... Args>
0296 BOOST_FORCEINLINE std::pair<iterator, bool> emplace(Args&&... args)
0297 {
0298 return table_.emplace(std::forward<Args>(args)...);
0299 }
0300
0301 template <class... Args>
0302 BOOST_FORCEINLINE iterator emplace_hint(const_iterator, Args&&... args)
0303 {
0304 return table_.emplace(std::forward<Args>(args)...).first;
0305 }
0306
0307 BOOST_FORCEINLINE typename table_type::erase_return_type erase(
0308 const_iterator pos)
0309 {
0310 return table_.erase(pos);
0311 }
0312
0313 iterator erase(const_iterator first, const_iterator last)
0314 {
0315 while (first != last) {
0316 this->erase(first++);
0317 }
0318 return iterator{detail::foa::const_iterator_cast_tag{}, last};
0319 }
0320
0321 BOOST_FORCEINLINE size_type erase(key_type const& key)
0322 {
0323 return table_.erase(key);
0324 }
0325
0326 template <class K>
0327 BOOST_FORCEINLINE typename std::enable_if<
0328 detail::transparent_non_iterable<K, unordered_flat_set>::value,
0329 size_type>::type
0330 erase(K const& key)
0331 {
0332 return table_.erase(key);
0333 }
0334
0335 void swap(unordered_flat_set& rhs) noexcept(
0336 noexcept(std::declval<table_type&>().swap(std::declval<table_type&>())))
0337 {
0338 table_.swap(rhs.table_);
0339 }
0340
0341 template <class H2, class P2>
0342 void merge(unordered_flat_set<key_type, H2, P2, allocator_type>& source)
0343 {
0344 table_.merge(source.table_);
0345 }
0346
0347 template <class H2, class P2>
0348 void merge(unordered_flat_set<key_type, H2, P2, allocator_type>&& source)
0349 {
0350 table_.merge(std::move(source.table_));
0351 }
0352
0353
0354
0355
0356 BOOST_FORCEINLINE size_type count(key_type const& key) const
0357 {
0358 auto pos = table_.find(key);
0359 return pos != table_.end() ? 1 : 0;
0360 }
0361
0362 template <class K>
0363 BOOST_FORCEINLINE typename std::enable_if<
0364 detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
0365 count(K const& key) const
0366 {
0367 auto pos = table_.find(key);
0368 return pos != table_.end() ? 1 : 0;
0369 }
0370
0371 BOOST_FORCEINLINE iterator find(key_type const& key)
0372 {
0373 return table_.find(key);
0374 }
0375
0376 BOOST_FORCEINLINE const_iterator find(key_type const& key) const
0377 {
0378 return table_.find(key);
0379 }
0380
0381 template <class K>
0382 BOOST_FORCEINLINE typename std::enable_if<
0383 boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
0384 iterator>::type
0385 find(K const& key)
0386 {
0387 return table_.find(key);
0388 }
0389
0390 template <class K>
0391 BOOST_FORCEINLINE typename std::enable_if<
0392 boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
0393 const_iterator>::type
0394 find(K const& key) const
0395 {
0396 return table_.find(key);
0397 }
0398
0399 BOOST_FORCEINLINE bool contains(key_type const& key) const
0400 {
0401 return this->find(key) != this->end();
0402 }
0403
0404 template <class K>
0405 BOOST_FORCEINLINE typename std::enable_if<
0406 boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
0407 bool>::type
0408 contains(K const& key) const
0409 {
0410 return this->find(key) != this->end();
0411 }
0412
0413 std::pair<iterator, iterator> equal_range(key_type const& key)
0414 {
0415 auto pos = table_.find(key);
0416 if (pos == table_.end()) {
0417 return {pos, pos};
0418 }
0419
0420 auto next = pos;
0421 ++next;
0422 return {pos, next};
0423 }
0424
0425 std::pair<const_iterator, const_iterator> equal_range(
0426 key_type const& key) const
0427 {
0428 auto pos = table_.find(key);
0429 if (pos == table_.end()) {
0430 return {pos, pos};
0431 }
0432
0433 auto next = pos;
0434 ++next;
0435 return {pos, next};
0436 }
0437
0438 template <class K>
0439 typename std::enable_if<
0440 detail::are_transparent<K, hasher, key_equal>::value,
0441 std::pair<iterator, iterator> >::type
0442 equal_range(K const& key)
0443 {
0444 auto pos = table_.find(key);
0445 if (pos == table_.end()) {
0446 return {pos, pos};
0447 }
0448
0449 auto next = pos;
0450 ++next;
0451 return {pos, next};
0452 }
0453
0454 template <class K>
0455 typename std::enable_if<
0456 detail::are_transparent<K, hasher, key_equal>::value,
0457 std::pair<const_iterator, const_iterator> >::type
0458 equal_range(K const& key) const
0459 {
0460 auto pos = table_.find(key);
0461 if (pos == table_.end()) {
0462 return {pos, pos};
0463 }
0464
0465 auto next = pos;
0466 ++next;
0467 return {pos, next};
0468 }
0469
0470
0471
0472
0473 size_type bucket_count() const noexcept { return table_.capacity(); }
0474
0475 float load_factor() const noexcept { return table_.load_factor(); }
0476
0477 float max_load_factor() const noexcept
0478 {
0479 return table_.max_load_factor();
0480 }
0481
0482 void max_load_factor(float) {}
0483
0484 size_type max_load() const noexcept { return table_.max_load(); }
0485
0486 void rehash(size_type n) { table_.rehash(n); }
0487
0488 void reserve(size_type n) { table_.reserve(n); }
0489
0490 #if defined(BOOST_UNORDERED_ENABLE_STATS)
0491
0492
0493 stats get_stats() const { return table_.get_stats(); }
0494
0495 void reset_stats() noexcept { table_.reset_stats(); }
0496 #endif
0497
0498
0499
0500
0501 hasher hash_function() const { return table_.hash_function(); }
0502
0503 key_equal key_eq() const { return table_.key_eq(); }
0504 };
0505
0506 template <class Key, class Hash, class KeyEqual, class Allocator>
0507 bool operator==(
0508 unordered_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
0509 unordered_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs)
0510 {
0511 return lhs.table_ == rhs.table_;
0512 }
0513
0514 template <class Key, class Hash, class KeyEqual, class Allocator>
0515 bool operator!=(
0516 unordered_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
0517 unordered_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs)
0518 {
0519 return !(lhs == rhs);
0520 }
0521
0522 template <class Key, class Hash, class KeyEqual, class Allocator>
0523 void swap(unordered_flat_set<Key, Hash, KeyEqual, Allocator>& lhs,
0524 unordered_flat_set<Key, Hash, KeyEqual, Allocator>& rhs)
0525 noexcept(noexcept(lhs.swap(rhs)))
0526 {
0527 lhs.swap(rhs);
0528 }
0529
0530 template <class Key, class Hash, class KeyEqual, class Allocator,
0531 class Pred>
0532 typename unordered_flat_set<Key, Hash, KeyEqual, Allocator>::size_type
0533 erase_if(unordered_flat_set<Key, Hash, KeyEqual, Allocator>& set, Pred pred)
0534 {
0535 return erase_if(set.table_, pred);
0536 }
0537
0538 template <class Archive, class Key, class Hash, class KeyEqual,
0539 class Allocator>
0540 void serialize(Archive& ar,
0541 unordered_flat_set<Key, Hash, KeyEqual, Allocator>& set,
0542 unsigned int version)
0543 {
0544 detail::serialize_container(ar, set, version);
0545 }
0546
0547 #if defined(BOOST_MSVC)
0548 #pragma warning(pop)
0549 #endif
0550
0551 #if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
0552 template <class InputIterator,
0553 class Hash =
0554 boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
0555 class Pred =
0556 std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
0557 class Allocator = std::allocator<
0558 typename std::iterator_traits<InputIterator>::value_type>,
0559 class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0560 class = std::enable_if_t<detail::is_hash_v<Hash> >,
0561 class = std::enable_if_t<detail::is_pred_v<Pred> >,
0562 class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0563 unordered_flat_set(InputIterator, InputIterator,
0564 std::size_t = boost::unordered::detail::foa::default_bucket_count,
0565 Hash = Hash(), Pred = Pred(), Allocator = Allocator())
0566 -> unordered_flat_set<
0567 typename std::iterator_traits<InputIterator>::value_type, Hash, Pred,
0568 Allocator>;
0569
0570 template <class T, class Hash = boost::hash<T>,
0571 class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
0572 class = std::enable_if_t<detail::is_hash_v<Hash> >,
0573 class = std::enable_if_t<detail::is_pred_v<Pred> >,
0574 class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0575 unordered_flat_set(std::initializer_list<T>,
0576 std::size_t = boost::unordered::detail::foa::default_bucket_count,
0577 Hash = Hash(), Pred = Pred(), Allocator = Allocator())
0578 -> unordered_flat_set<T, Hash, Pred, Allocator>;
0579
0580 template <class InputIterator, class Allocator,
0581 class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0582 class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0583 unordered_flat_set(InputIterator, InputIterator, std::size_t, Allocator)
0584 -> unordered_flat_set<
0585 typename std::iterator_traits<InputIterator>::value_type,
0586 boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
0587 std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
0588 Allocator>;
0589
0590 template <class InputIterator, class Hash, class Allocator,
0591 class = std::enable_if_t<detail::is_hash_v<Hash> >,
0592 class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0593 class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0594 unordered_flat_set(
0595 InputIterator, InputIterator, std::size_t, Hash, Allocator)
0596 -> unordered_flat_set<
0597 typename std::iterator_traits<InputIterator>::value_type, Hash,
0598 std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
0599 Allocator>;
0600
0601 template <class T, class Allocator,
0602 class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0603 unordered_flat_set(std::initializer_list<T>, std::size_t, Allocator)
0604 -> unordered_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
0605
0606 template <class T, class Hash, class Allocator,
0607 class = std::enable_if_t<detail::is_hash_v<Hash> >,
0608 class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0609 unordered_flat_set(std::initializer_list<T>, std::size_t, Hash, Allocator)
0610 -> unordered_flat_set<T, Hash, std::equal_to<T>, Allocator>;
0611
0612 template <class InputIterator, class Allocator,
0613 class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
0614 class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0615 unordered_flat_set(InputIterator, InputIterator, Allocator)
0616 -> unordered_flat_set<
0617 typename std::iterator_traits<InputIterator>::value_type,
0618 boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
0619 std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
0620 Allocator>;
0621
0622 template <class T, class Allocator,
0623 class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
0624 unordered_flat_set(std::initializer_list<T>, Allocator)
0625 -> unordered_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
0626 #endif
0627
0628 }
0629 }
0630
0631 #endif