unordered_flat_set.hpp 19 KB

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