unordered_flat_set.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. // Copyright (C) 2022-2023 Christian Mazakas
  2. // Copyright (C) 2024-2025 Joaquin M Lopez Munoz
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_UNORDERED_UNORDERED_FLAT_SET_HPP_INCLUDED
  6. #define BOOST_UNORDERED_UNORDERED_FLAT_SET_HPP_INCLUDED
  7. #include <boost/config.hpp>
  8. #if defined(BOOST_HAS_PRAGMA_ONCE)
  9. #pragma once
  10. #endif
  11. #include <boost/unordered/concurrent_flat_set_fwd.hpp>
  12. #include <boost/unordered/detail/foa/flat_set_types.hpp>
  13. #include <boost/unordered/detail/foa/table.hpp>
  14. #include <boost/unordered/detail/serialize_container.hpp>
  15. #include <boost/unordered/detail/type_traits.hpp>
  16. #include <boost/unordered/unordered_flat_set_fwd.hpp>
  17. #include <boost/core/allocator_access.hpp>
  18. #include <boost/container_hash/hash.hpp>
  19. #include <initializer_list>
  20. #include <iterator>
  21. #include <type_traits>
  22. #include <utility>
  23. namespace boost {
  24. namespace unordered {
  25. #if defined(BOOST_MSVC)
  26. #pragma warning(push)
  27. #pragma warning(disable : 4714) /* marked as __forceinline not inlined */
  28. #endif
  29. template <class Key, class Hash, class KeyEqual, class Allocator>
  30. class unordered_flat_set
  31. {
  32. template <class Key2, class Hash2, class KeyEqual2, class Allocator2>
  33. friend class concurrent_flat_set;
  34. using set_types = detail::foa::flat_set_types<Key>;
  35. using table_type = detail::foa::table<set_types, Hash, KeyEqual,
  36. typename boost::allocator_rebind<Allocator,
  37. typename set_types::value_type>::type>;
  38. table_type table_;
  39. template <class K, class H, class KE, class A>
  40. bool friend operator==(unordered_flat_set<K, H, KE, A> const& lhs,
  41. unordered_flat_set<K, H, KE, A> const& rhs);
  42. template <class K, class H, class KE, class A, class Pred>
  43. typename unordered_flat_set<K, H, KE, A>::size_type friend erase_if(
  44. unordered_flat_set<K, H, KE, A>& set, Pred pred);
  45. public:
  46. using key_type = Key;
  47. using value_type = typename set_types::value_type;
  48. using init_type = typename set_types::init_type;
  49. using size_type = std::size_t;
  50. using difference_type = std::ptrdiff_t;
  51. using hasher = Hash;
  52. using key_equal = KeyEqual;
  53. using allocator_type = Allocator;
  54. using reference = value_type&;
  55. using const_reference = value_type const&;
  56. using pointer = typename boost::allocator_pointer<allocator_type>::type;
  57. using const_pointer =
  58. typename boost::allocator_const_pointer<allocator_type>::type;
  59. using iterator = typename table_type::iterator;
  60. using const_iterator = typename table_type::const_iterator;
  61. #if defined(BOOST_UNORDERED_ENABLE_STATS)
  62. using stats = typename table_type::stats;
  63. #endif
  64. unordered_flat_set() : unordered_flat_set(0) {}
  65. explicit unordered_flat_set(size_type n, hasher const& h = hasher(),
  66. key_equal const& pred = key_equal(),
  67. allocator_type const& a = allocator_type())
  68. : table_(n, h, pred, a)
  69. {
  70. }
  71. unordered_flat_set(size_type n, allocator_type const& a)
  72. : unordered_flat_set(n, hasher(), key_equal(), a)
  73. {
  74. }
  75. unordered_flat_set(size_type n, hasher const& h, allocator_type const& a)
  76. : unordered_flat_set(n, h, key_equal(), a)
  77. {
  78. }
  79. template <class InputIterator>
  80. unordered_flat_set(
  81. InputIterator f, InputIterator l, allocator_type const& a)
  82. : unordered_flat_set(f, l, size_type(0), hasher(), key_equal(), a)
  83. {
  84. }
  85. explicit unordered_flat_set(allocator_type const& a)
  86. : unordered_flat_set(0, a)
  87. {
  88. }
  89. template <class Iterator>
  90. unordered_flat_set(Iterator first, Iterator last, size_type n = 0,
  91. hasher const& h = hasher(), key_equal const& pred = key_equal(),
  92. allocator_type const& a = allocator_type())
  93. : unordered_flat_set(n, h, pred, a)
  94. {
  95. this->insert(first, last);
  96. }
  97. template <class InputIt>
  98. unordered_flat_set(
  99. InputIt first, InputIt last, size_type n, allocator_type const& a)
  100. : unordered_flat_set(first, last, n, hasher(), key_equal(), a)
  101. {
  102. }
  103. template <class Iterator>
  104. unordered_flat_set(Iterator first, Iterator last, size_type n,
  105. hasher const& h, allocator_type const& a)
  106. : unordered_flat_set(first, last, n, h, key_equal(), a)
  107. {
  108. }
  109. unordered_flat_set(unordered_flat_set const& other) : table_(other.table_)
  110. {
  111. }
  112. unordered_flat_set(
  113. unordered_flat_set const& other, allocator_type const& a)
  114. : table_(other.table_, a)
  115. {
  116. }
  117. unordered_flat_set(unordered_flat_set&& other)
  118. noexcept(std::is_nothrow_move_constructible<table_type>::value)
  119. : table_(std::move(other.table_))
  120. {
  121. }
  122. unordered_flat_set(unordered_flat_set&& other, allocator_type const& al)
  123. : table_(std::move(other.table_), al)
  124. {
  125. }
  126. unordered_flat_set(std::initializer_list<value_type> ilist,
  127. size_type n = 0, hasher const& h = hasher(),
  128. key_equal const& pred = key_equal(),
  129. allocator_type const& a = allocator_type())
  130. : unordered_flat_set(ilist.begin(), ilist.end(), n, h, pred, a)
  131. {
  132. }
  133. unordered_flat_set(
  134. std::initializer_list<value_type> il, allocator_type const& a)
  135. : unordered_flat_set(il, size_type(0), hasher(), key_equal(), a)
  136. {
  137. }
  138. unordered_flat_set(std::initializer_list<value_type> init, size_type n,
  139. allocator_type const& a)
  140. : unordered_flat_set(init, n, hasher(), key_equal(), a)
  141. {
  142. }
  143. unordered_flat_set(std::initializer_list<value_type> init, size_type n,
  144. hasher const& h, allocator_type const& a)
  145. : unordered_flat_set(init, n, h, key_equal(), a)
  146. {
  147. }
  148. template <bool avoid_explicit_instantiation = true>
  149. unordered_flat_set(
  150. concurrent_flat_set<Key, Hash, KeyEqual, Allocator>&& other)
  151. : table_(std::move(other.table_))
  152. {
  153. }
  154. ~unordered_flat_set() = default;
  155. unordered_flat_set& operator=(unordered_flat_set const& other)
  156. {
  157. table_ = other.table_;
  158. return *this;
  159. }
  160. unordered_flat_set& operator=(unordered_flat_set&& other) noexcept(
  161. noexcept(std::declval<table_type&>() = std::declval<table_type&&>()))
  162. {
  163. table_ = std::move(other.table_);
  164. return *this;
  165. }
  166. unordered_flat_set& operator=(std::initializer_list<value_type> il)
  167. {
  168. this->clear();
  169. this->insert(il.begin(), il.end());
  170. return *this;
  171. }
  172. allocator_type get_allocator() const noexcept
  173. {
  174. return table_.get_allocator();
  175. }
  176. /// Iterators
  177. ///
  178. iterator begin() noexcept { return table_.begin(); }
  179. const_iterator begin() const noexcept { return table_.begin(); }
  180. const_iterator cbegin() const noexcept { return table_.cbegin(); }
  181. iterator end() noexcept { return table_.end(); }
  182. const_iterator end() const noexcept { return table_.end(); }
  183. const_iterator cend() const noexcept { return table_.cend(); }
  184. /// Capacity
  185. ///
  186. BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept
  187. {
  188. return table_.empty();
  189. }
  190. size_type size() const noexcept { return table_.size(); }
  191. size_type max_size() const noexcept { return table_.max_size(); }
  192. /// Modifiers
  193. ///
  194. void clear() noexcept { table_.clear(); }
  195. BOOST_FORCEINLINE std::pair<iterator, bool> insert(
  196. value_type const& value)
  197. {
  198. return table_.insert(value);
  199. }
  200. BOOST_FORCEINLINE std::pair<iterator, bool> insert(value_type&& value)
  201. {
  202. return table_.insert(std::move(value));
  203. }
  204. template <class K>
  205. BOOST_FORCEINLINE typename std::enable_if<
  206. detail::transparent_non_iterable<K, unordered_flat_set>::value,
  207. std::pair<iterator, bool> >::type
  208. insert(K&& k)
  209. {
  210. return table_.try_emplace(std::forward<K>(k));
  211. }
  212. BOOST_FORCEINLINE iterator insert(const_iterator, value_type const& value)
  213. {
  214. return table_.insert(value).first;
  215. }
  216. BOOST_FORCEINLINE iterator insert(const_iterator, value_type&& value)
  217. {
  218. return table_.insert(std::move(value)).first;
  219. }
  220. template <class K>
  221. BOOST_FORCEINLINE typename std::enable_if<
  222. detail::transparent_non_iterable<K, unordered_flat_set>::value,
  223. iterator>::type
  224. insert(const_iterator, K&& k)
  225. {
  226. return table_.try_emplace(std::forward<K>(k)).first;
  227. }
  228. template <class InputIterator>
  229. void insert(InputIterator first, InputIterator last)
  230. {
  231. for (auto pos = first; pos != last; ++pos) {
  232. table_.emplace(*pos);
  233. }
  234. }
  235. void insert(std::initializer_list<value_type> ilist)
  236. {
  237. this->insert(ilist.begin(), ilist.end());
  238. }
  239. template <class... Args>
  240. BOOST_FORCEINLINE std::pair<iterator, bool> emplace(Args&&... args)
  241. {
  242. return table_.emplace(std::forward<Args>(args)...);
  243. }
  244. template <class... Args>
  245. BOOST_FORCEINLINE iterator emplace_hint(const_iterator, Args&&... args)
  246. {
  247. return table_.emplace(std::forward<Args>(args)...).first;
  248. }
  249. BOOST_FORCEINLINE typename table_type::erase_return_type erase(
  250. const_iterator pos)
  251. {
  252. return table_.erase(pos);
  253. }
  254. iterator erase(const_iterator first, const_iterator last)
  255. {
  256. while (first != last) {
  257. this->erase(first++);
  258. }
  259. return iterator{detail::foa::const_iterator_cast_tag{}, last};
  260. }
  261. BOOST_FORCEINLINE size_type erase(key_type const& key)
  262. {
  263. return table_.erase(key);
  264. }
  265. template <class K>
  266. BOOST_FORCEINLINE typename std::enable_if<
  267. detail::transparent_non_iterable<K, unordered_flat_set>::value,
  268. size_type>::type
  269. erase(K const& key)
  270. {
  271. return table_.erase(key);
  272. }
  273. BOOST_FORCEINLINE init_type pull(const_iterator pos)
  274. {
  275. return table_.pull(pos);
  276. }
  277. void swap(unordered_flat_set& rhs) noexcept(
  278. noexcept(std::declval<table_type&>().swap(std::declval<table_type&>())))
  279. {
  280. table_.swap(rhs.table_);
  281. }
  282. template <class H2, class P2>
  283. void merge(unordered_flat_set<key_type, H2, P2, allocator_type>& source)
  284. {
  285. table_.merge(source.table_);
  286. }
  287. template <class H2, class P2>
  288. void merge(unordered_flat_set<key_type, H2, P2, allocator_type>&& source)
  289. {
  290. table_.merge(std::move(source.table_));
  291. }
  292. /// Lookup
  293. ///
  294. BOOST_FORCEINLINE size_type count(key_type const& key) const
  295. {
  296. auto pos = table_.find(key);
  297. return pos != table_.end() ? 1 : 0;
  298. }
  299. template <class K>
  300. BOOST_FORCEINLINE typename std::enable_if<
  301. detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
  302. count(K const& key) const
  303. {
  304. auto pos = table_.find(key);
  305. return pos != table_.end() ? 1 : 0;
  306. }
  307. BOOST_FORCEINLINE iterator find(key_type const& key)
  308. {
  309. return table_.find(key);
  310. }
  311. BOOST_FORCEINLINE const_iterator find(key_type const& key) const
  312. {
  313. return table_.find(key);
  314. }
  315. template <class K>
  316. BOOST_FORCEINLINE typename std::enable_if<
  317. boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
  318. iterator>::type
  319. find(K const& key)
  320. {
  321. return table_.find(key);
  322. }
  323. template <class K>
  324. BOOST_FORCEINLINE typename std::enable_if<
  325. boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
  326. const_iterator>::type
  327. find(K const& key) const
  328. {
  329. return table_.find(key);
  330. }
  331. BOOST_FORCEINLINE bool contains(key_type const& key) const
  332. {
  333. return this->find(key) != this->end();
  334. }
  335. template <class K>
  336. BOOST_FORCEINLINE typename std::enable_if<
  337. boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
  338. bool>::type
  339. contains(K const& key) const
  340. {
  341. return this->find(key) != this->end();
  342. }
  343. std::pair<iterator, iterator> equal_range(key_type const& key)
  344. {
  345. auto pos = table_.find(key);
  346. if (pos == table_.end()) {
  347. return {pos, pos};
  348. }
  349. auto next = pos;
  350. ++next;
  351. return {pos, next};
  352. }
  353. std::pair<const_iterator, const_iterator> equal_range(
  354. key_type const& key) const
  355. {
  356. auto pos = table_.find(key);
  357. if (pos == table_.end()) {
  358. return {pos, pos};
  359. }
  360. auto next = pos;
  361. ++next;
  362. return {pos, next};
  363. }
  364. template <class K>
  365. typename std::enable_if<
  366. detail::are_transparent<K, hasher, key_equal>::value,
  367. std::pair<iterator, iterator> >::type
  368. equal_range(K const& key)
  369. {
  370. auto pos = table_.find(key);
  371. if (pos == table_.end()) {
  372. return {pos, pos};
  373. }
  374. auto next = pos;
  375. ++next;
  376. return {pos, next};
  377. }
  378. template <class K>
  379. typename std::enable_if<
  380. detail::are_transparent<K, hasher, key_equal>::value,
  381. std::pair<const_iterator, const_iterator> >::type
  382. equal_range(K const& key) const
  383. {
  384. auto pos = table_.find(key);
  385. if (pos == table_.end()) {
  386. return {pos, pos};
  387. }
  388. auto next = pos;
  389. ++next;
  390. return {pos, next};
  391. }
  392. /// Hash Policy
  393. ///
  394. size_type bucket_count() const noexcept { return table_.capacity(); }
  395. float load_factor() const noexcept { return table_.load_factor(); }
  396. float max_load_factor() const noexcept
  397. {
  398. return table_.max_load_factor();
  399. }
  400. void max_load_factor(float) {}
  401. size_type max_load() const noexcept { return table_.max_load(); }
  402. void rehash(size_type n) { table_.rehash(n); }
  403. void reserve(size_type n) { table_.reserve(n); }
  404. #if defined(BOOST_UNORDERED_ENABLE_STATS)
  405. /// Stats
  406. ///
  407. stats get_stats() const { return table_.get_stats(); }
  408. void reset_stats() noexcept { table_.reset_stats(); }
  409. #endif
  410. /// Observers
  411. ///
  412. hasher hash_function() const { return table_.hash_function(); }
  413. key_equal key_eq() const { return table_.key_eq(); }
  414. };
  415. template <class Key, class Hash, class KeyEqual, class Allocator>
  416. bool operator==(
  417. unordered_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
  418. unordered_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs)
  419. {
  420. return lhs.table_ == rhs.table_;
  421. }
  422. template <class Key, class Hash, class KeyEqual, class Allocator>
  423. bool operator!=(
  424. unordered_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
  425. unordered_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs)
  426. {
  427. return !(lhs == rhs);
  428. }
  429. template <class Key, class Hash, class KeyEqual, class Allocator>
  430. void swap(unordered_flat_set<Key, Hash, KeyEqual, Allocator>& lhs,
  431. unordered_flat_set<Key, Hash, KeyEqual, Allocator>& rhs)
  432. noexcept(noexcept(lhs.swap(rhs)))
  433. {
  434. lhs.swap(rhs);
  435. }
  436. template <class Key, class Hash, class KeyEqual, class Allocator,
  437. class Pred>
  438. typename unordered_flat_set<Key, Hash, KeyEqual, Allocator>::size_type
  439. erase_if(unordered_flat_set<Key, Hash, KeyEqual, Allocator>& set, Pred pred)
  440. {
  441. return erase_if(set.table_, pred);
  442. }
  443. template <class Archive, class Key, class Hash, class KeyEqual,
  444. class Allocator>
  445. void serialize(Archive& ar,
  446. unordered_flat_set<Key, Hash, KeyEqual, Allocator>& set,
  447. unsigned int version)
  448. {
  449. detail::serialize_container(ar, set, version);
  450. }
  451. #if defined(BOOST_MSVC)
  452. #pragma warning(pop) /* C4714 */
  453. #endif
  454. #if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
  455. template <class InputIterator,
  456. class Hash =
  457. boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
  458. class Pred =
  459. std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
  460. class Allocator = std::allocator<
  461. typename std::iterator_traits<InputIterator>::value_type>,
  462. class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
  463. class = std::enable_if_t<detail::is_hash_v<Hash> >,
  464. class = std::enable_if_t<detail::is_pred_v<Pred> >,
  465. class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
  466. unordered_flat_set(InputIterator, InputIterator,
  467. std::size_t = boost::unordered::detail::foa::default_bucket_count,
  468. Hash = Hash(), Pred = Pred(), Allocator = Allocator())
  469. -> unordered_flat_set<
  470. typename std::iterator_traits<InputIterator>::value_type, Hash, Pred,
  471. Allocator>;
  472. template <class T, class Hash = boost::hash<T>,
  473. class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
  474. class = std::enable_if_t<detail::is_hash_v<Hash> >,
  475. class = std::enable_if_t<detail::is_pred_v<Pred> >,
  476. class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
  477. unordered_flat_set(std::initializer_list<T>,
  478. std::size_t = boost::unordered::detail::foa::default_bucket_count,
  479. Hash = Hash(), Pred = Pred(), Allocator = Allocator())
  480. -> unordered_flat_set<T, Hash, Pred, Allocator>;
  481. template <class InputIterator, class Allocator,
  482. class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
  483. class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
  484. unordered_flat_set(InputIterator, InputIterator, std::size_t, Allocator)
  485. -> unordered_flat_set<
  486. typename std::iterator_traits<InputIterator>::value_type,
  487. boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
  488. std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
  489. Allocator>;
  490. template <class InputIterator, class Hash, class Allocator,
  491. class = std::enable_if_t<detail::is_hash_v<Hash> >,
  492. class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
  493. class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
  494. unordered_flat_set(
  495. InputIterator, InputIterator, std::size_t, Hash, Allocator)
  496. -> unordered_flat_set<
  497. typename std::iterator_traits<InputIterator>::value_type, Hash,
  498. std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
  499. Allocator>;
  500. template <class T, class Allocator,
  501. class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
  502. unordered_flat_set(std::initializer_list<T>, std::size_t, Allocator)
  503. -> unordered_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
  504. template <class T, class Hash, class Allocator,
  505. class = std::enable_if_t<detail::is_hash_v<Hash> >,
  506. class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
  507. unordered_flat_set(std::initializer_list<T>, std::size_t, Hash, Allocator)
  508. -> unordered_flat_set<T, Hash, std::equal_to<T>, Allocator>;
  509. template <class InputIterator, class Allocator,
  510. class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
  511. class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
  512. unordered_flat_set(InputIterator, InputIterator, Allocator)
  513. -> unordered_flat_set<
  514. typename std::iterator_traits<InputIterator>::value_type,
  515. boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
  516. std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
  517. Allocator>;
  518. template <class T, class Allocator,
  519. class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
  520. unordered_flat_set(std::initializer_list<T>, Allocator)
  521. -> unordered_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
  522. #endif
  523. } // namespace unordered
  524. } // namespace boost
  525. #endif