unordered_flat_set.hpp 20 KB

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