unordered_node_map.hpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  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_NODE_MAP_HPP_INCLUDED
  6. #define BOOST_UNORDERED_UNORDERED_NODE_MAP_HPP_INCLUDED
  7. #include <boost/config.hpp>
  8. #if defined(BOOST_HAS_PRAGMA_ONCE)
  9. #pragma once
  10. #endif
  11. #include <boost/unordered/concurrent_node_map_fwd.hpp>
  12. #include <boost/unordered/detail/foa/node_map_handle.hpp>
  13. #include <boost/unordered/detail/foa/node_map_types.hpp>
  14. #include <boost/unordered/detail/foa/table.hpp>
  15. #include <boost/unordered/detail/serialize_container.hpp>
  16. #include <boost/unordered/detail/throw_exception.hpp>
  17. #include <boost/unordered/detail/type_traits.hpp>
  18. #include <boost/unordered/unordered_node_map_fwd.hpp>
  19. #include <boost/core/allocator_access.hpp>
  20. #include <boost/container_hash/hash.hpp>
  21. #include <initializer_list>
  22. #include <iterator>
  23. #include <stdexcept>
  24. #include <type_traits>
  25. #include <utility>
  26. namespace boost {
  27. namespace unordered {
  28. #if defined(BOOST_MSVC)
  29. #pragma warning(push)
  30. #pragma warning(disable : 4714) /* marked as __forceinline not inlined */
  31. #endif
  32. template <class Key, class T, class Hash, class KeyEqual, class Allocator>
  33. class unordered_node_map
  34. {
  35. template <class Key2, class T2, class Hash2, class Pred2,
  36. class Allocator2>
  37. friend class concurrent_node_map;
  38. using map_types = detail::foa::node_map_types<Key, T,
  39. typename boost::allocator_void_pointer<Allocator>::type>;
  40. using table_type = detail::foa::table<map_types, Hash, KeyEqual,
  41. typename boost::allocator_rebind<Allocator,
  42. std::pair<Key const, T> >::type>;
  43. table_type table_;
  44. template <class K, class V, class H, class KE, class A>
  45. bool friend operator==(unordered_node_map<K, V, H, KE, A> const& lhs,
  46. unordered_node_map<K, V, H, KE, A> const& rhs);
  47. template <class K, class V, class H, class KE, class A, class Pred>
  48. typename unordered_node_map<K, V, H, KE, A>::size_type friend erase_if(
  49. unordered_node_map<K, V, H, KE, A>& set, Pred pred);
  50. public:
  51. using key_type = Key;
  52. using mapped_type = T;
  53. using value_type = typename map_types::value_type;
  54. using init_type = typename map_types::init_type;
  55. using size_type = std::size_t;
  56. using difference_type = std::ptrdiff_t;
  57. using hasher = typename boost::unordered::detail::type_identity<Hash>::type;
  58. using key_equal = typename boost::unordered::detail::type_identity<KeyEqual>::type;
  59. using allocator_type = typename boost::unordered::detail::type_identity<Allocator>::type;
  60. using reference = value_type&;
  61. using const_reference = value_type const&;
  62. using pointer = typename boost::allocator_pointer<allocator_type>::type;
  63. using const_pointer =
  64. typename boost::allocator_const_pointer<allocator_type>::type;
  65. using iterator = typename table_type::iterator;
  66. using const_iterator = typename table_type::const_iterator;
  67. using node_type = detail::foa::node_map_handle<map_types,
  68. typename boost::allocator_rebind<Allocator,
  69. typename map_types::value_type>::type>;
  70. using insert_return_type =
  71. detail::foa::insert_return_type<iterator, node_type>;
  72. #if defined(BOOST_UNORDERED_ENABLE_STATS)
  73. using stats = typename table_type::stats;
  74. #endif
  75. unordered_node_map() : unordered_node_map(0) {}
  76. explicit unordered_node_map(size_type n, hasher const& h = hasher(),
  77. key_equal const& pred = key_equal(),
  78. allocator_type const& a = allocator_type())
  79. : table_(n, h, pred, a)
  80. {
  81. }
  82. unordered_node_map(size_type n, allocator_type const& a)
  83. : unordered_node_map(n, hasher(), key_equal(), a)
  84. {
  85. }
  86. unordered_node_map(size_type n, hasher const& h, allocator_type const& a)
  87. : unordered_node_map(n, h, key_equal(), a)
  88. {
  89. }
  90. template <class InputIterator>
  91. unordered_node_map(
  92. InputIterator f, InputIterator l, allocator_type const& a)
  93. : unordered_node_map(f, l, size_type(0), hasher(), key_equal(), a)
  94. {
  95. }
  96. explicit unordered_node_map(allocator_type const& a)
  97. : unordered_node_map(0, a)
  98. {
  99. }
  100. template <class Iterator>
  101. unordered_node_map(Iterator first, Iterator last, size_type n = 0,
  102. hasher const& h = hasher(), key_equal const& pred = key_equal(),
  103. allocator_type const& a = allocator_type())
  104. : unordered_node_map(n, h, pred, a)
  105. {
  106. this->insert(first, last);
  107. }
  108. template <class Iterator>
  109. unordered_node_map(
  110. Iterator first, Iterator last, size_type n, allocator_type const& a)
  111. : unordered_node_map(first, last, n, hasher(), key_equal(), a)
  112. {
  113. }
  114. template <class Iterator>
  115. unordered_node_map(Iterator first, Iterator last, size_type n,
  116. hasher const& h, allocator_type const& a)
  117. : unordered_node_map(first, last, n, h, key_equal(), a)
  118. {
  119. }
  120. unordered_node_map(unordered_node_map const& other) : table_(other.table_)
  121. {
  122. }
  123. unordered_node_map(
  124. unordered_node_map const& other, allocator_type const& a)
  125. : table_(other.table_, a)
  126. {
  127. }
  128. unordered_node_map(unordered_node_map&& other)
  129. noexcept(std::is_nothrow_move_constructible<table_type>::value)
  130. : table_(std::move(other.table_))
  131. {
  132. }
  133. unordered_node_map(unordered_node_map&& other, allocator_type const& al)
  134. : table_(std::move(other.table_), al)
  135. {
  136. }
  137. unordered_node_map(std::initializer_list<value_type> ilist,
  138. size_type n = 0, hasher const& h = hasher(),
  139. key_equal const& pred = key_equal(),
  140. allocator_type const& a = allocator_type())
  141. : unordered_node_map(ilist.begin(), ilist.end(), n, h, pred, a)
  142. {
  143. }
  144. unordered_node_map(
  145. std::initializer_list<value_type> il, allocator_type const& a)
  146. : unordered_node_map(il, size_type(0), hasher(), key_equal(), a)
  147. {
  148. }
  149. unordered_node_map(std::initializer_list<value_type> init, size_type n,
  150. allocator_type const& a)
  151. : unordered_node_map(init, n, hasher(), key_equal(), a)
  152. {
  153. }
  154. unordered_node_map(std::initializer_list<value_type> init, size_type n,
  155. hasher const& h, allocator_type const& a)
  156. : unordered_node_map(init, n, h, key_equal(), a)
  157. {
  158. }
  159. template <bool avoid_explicit_instantiation = true>
  160. unordered_node_map(
  161. concurrent_node_map<Key, T, Hash, KeyEqual, Allocator>&& other)
  162. : table_(std::move(other.table_))
  163. {
  164. }
  165. ~unordered_node_map() = default;
  166. unordered_node_map& operator=(unordered_node_map const& other)
  167. {
  168. table_ = other.table_;
  169. return *this;
  170. }
  171. unordered_node_map& operator=(unordered_node_map&& other) noexcept(
  172. noexcept(std::declval<table_type&>() = std::declval<table_type&&>()))
  173. {
  174. table_ = std::move(other.table_);
  175. return *this;
  176. }
  177. unordered_node_map& operator=(std::initializer_list<value_type> il)
  178. {
  179. this->clear();
  180. this->insert(il.begin(), il.end());
  181. return *this;
  182. }
  183. allocator_type get_allocator() const noexcept
  184. {
  185. return table_.get_allocator();
  186. }
  187. /// Iterators
  188. ///
  189. iterator begin() noexcept { return table_.begin(); }
  190. const_iterator begin() const noexcept { return table_.begin(); }
  191. const_iterator cbegin() const noexcept { return table_.cbegin(); }
  192. iterator end() noexcept { return table_.end(); }
  193. const_iterator end() const noexcept { return table_.end(); }
  194. const_iterator cend() const noexcept { return table_.cend(); }
  195. /// Capacity
  196. ///
  197. BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept
  198. {
  199. return table_.empty();
  200. }
  201. size_type size() const noexcept { return table_.size(); }
  202. size_type max_size() const noexcept { return table_.max_size(); }
  203. /// Modifiers
  204. ///
  205. void clear() noexcept { table_.clear(); }
  206. template <class Ty>
  207. BOOST_FORCEINLINE auto insert(Ty&& value)
  208. -> decltype(table_.insert(std::forward<Ty>(value)))
  209. {
  210. return table_.insert(std::forward<Ty>(value));
  211. }
  212. BOOST_FORCEINLINE std::pair<iterator, bool> insert(init_type&& value)
  213. {
  214. return table_.insert(std::move(value));
  215. }
  216. template <class Ty>
  217. BOOST_FORCEINLINE auto insert(const_iterator, Ty&& value)
  218. -> decltype(table_.insert(std::forward<Ty>(value)).first)
  219. {
  220. return table_.insert(std::forward<Ty>(value)).first;
  221. }
  222. BOOST_FORCEINLINE iterator insert(const_iterator, init_type&& value)
  223. {
  224. return table_.insert(std::move(value)).first;
  225. }
  226. template <class InputIterator>
  227. BOOST_FORCEINLINE void insert(InputIterator first, InputIterator last)
  228. {
  229. for (auto pos = first; pos != last; ++pos) {
  230. table_.emplace(*pos);
  231. }
  232. }
  233. void insert(std::initializer_list<value_type> ilist)
  234. {
  235. this->insert(ilist.begin(), ilist.end());
  236. }
  237. insert_return_type insert(node_type&& nh)
  238. {
  239. using access = detail::foa::node_handle_access;
  240. if (nh.empty()) {
  241. return {end(), false, node_type{}};
  242. }
  243. BOOST_ASSERT(get_allocator() == nh.get_allocator());
  244. auto itp = table_.insert(std::move(access::element(nh)));
  245. if (itp.second) {
  246. access::reset(nh);
  247. return {itp.first, true, node_type{}};
  248. } else {
  249. return {itp.first, false, std::move(nh)};
  250. }
  251. }
  252. iterator insert(const_iterator, node_type&& nh)
  253. {
  254. using access = detail::foa::node_handle_access;
  255. if (nh.empty()) {
  256. return end();
  257. }
  258. BOOST_ASSERT(get_allocator() == nh.get_allocator());
  259. auto itp = table_.insert(std::move(access::element(nh)));
  260. if (itp.second) {
  261. access::reset(nh);
  262. return itp.first;
  263. } else {
  264. return itp.first;
  265. }
  266. }
  267. template <class M>
  268. std::pair<iterator, bool> insert_or_assign(key_type const& key, M&& obj)
  269. {
  270. auto ibp = table_.try_emplace(key, std::forward<M>(obj));
  271. if (ibp.second) {
  272. return ibp;
  273. }
  274. ibp.first->second = std::forward<M>(obj);
  275. return ibp;
  276. }
  277. template <class M>
  278. std::pair<iterator, bool> insert_or_assign(key_type&& key, M&& obj)
  279. {
  280. auto ibp = table_.try_emplace(std::move(key), std::forward<M>(obj));
  281. if (ibp.second) {
  282. return ibp;
  283. }
  284. ibp.first->second = std::forward<M>(obj);
  285. return ibp;
  286. }
  287. template <class K, class M>
  288. typename std::enable_if<
  289. boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
  290. std::pair<iterator, bool> >::type
  291. insert_or_assign(K&& k, M&& obj)
  292. {
  293. auto ibp = table_.try_emplace(std::forward<K>(k), std::forward<M>(obj));
  294. if (ibp.second) {
  295. return ibp;
  296. }
  297. ibp.first->second = std::forward<M>(obj);
  298. return ibp;
  299. }
  300. template <class M>
  301. iterator insert_or_assign(const_iterator, key_type const& key, M&& obj)
  302. {
  303. return this->insert_or_assign(key, std::forward<M>(obj)).first;
  304. }
  305. template <class M>
  306. iterator insert_or_assign(const_iterator, key_type&& key, M&& obj)
  307. {
  308. return this->insert_or_assign(std::move(key), std::forward<M>(obj))
  309. .first;
  310. }
  311. template <class K, class M>
  312. typename std::enable_if<
  313. boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
  314. iterator>::type
  315. insert_or_assign(const_iterator, K&& k, M&& obj)
  316. {
  317. return this->insert_or_assign(std::forward<K>(k), std::forward<M>(obj))
  318. .first;
  319. }
  320. template <class... Args>
  321. BOOST_FORCEINLINE std::pair<iterator, bool> emplace(Args&&... args)
  322. {
  323. return table_.emplace(std::forward<Args>(args)...);
  324. }
  325. template <class... Args>
  326. BOOST_FORCEINLINE iterator emplace_hint(const_iterator, Args&&... args)
  327. {
  328. return table_.emplace(std::forward<Args>(args)...).first;
  329. }
  330. template <class... Args>
  331. BOOST_FORCEINLINE std::pair<iterator, bool> try_emplace(
  332. key_type const& key, Args&&... args)
  333. {
  334. return table_.try_emplace(key, std::forward<Args>(args)...);
  335. }
  336. template <class... Args>
  337. BOOST_FORCEINLINE std::pair<iterator, bool> try_emplace(
  338. key_type&& key, Args&&... args)
  339. {
  340. return table_.try_emplace(std::move(key), std::forward<Args>(args)...);
  341. }
  342. template <class K, class... Args>
  343. BOOST_FORCEINLINE typename std::enable_if<
  344. boost::unordered::detail::transparent_non_iterable<K,
  345. unordered_node_map>::value,
  346. std::pair<iterator, bool> >::type
  347. try_emplace(K&& key, Args&&... args)
  348. {
  349. return table_.try_emplace(
  350. std::forward<K>(key), std::forward<Args>(args)...);
  351. }
  352. template <class... Args>
  353. BOOST_FORCEINLINE iterator try_emplace(
  354. const_iterator, key_type const& key, Args&&... args)
  355. {
  356. return table_.try_emplace(key, std::forward<Args>(args)...).first;
  357. }
  358. template <class... Args>
  359. BOOST_FORCEINLINE iterator try_emplace(
  360. const_iterator, key_type&& key, Args&&... args)
  361. {
  362. return table_.try_emplace(std::move(key), std::forward<Args>(args)...)
  363. .first;
  364. }
  365. template <class K, class... Args>
  366. BOOST_FORCEINLINE typename std::enable_if<
  367. boost::unordered::detail::transparent_non_iterable<K,
  368. unordered_node_map>::value,
  369. iterator>::type
  370. try_emplace(const_iterator, K&& key, Args&&... args)
  371. {
  372. return table_
  373. .try_emplace(std::forward<K>(key), std::forward<Args>(args)...)
  374. .first;
  375. }
  376. BOOST_FORCEINLINE typename table_type::erase_return_type erase(
  377. iterator pos)
  378. {
  379. return table_.erase(pos);
  380. }
  381. BOOST_FORCEINLINE typename table_type::erase_return_type erase(
  382. const_iterator pos)
  383. {
  384. return table_.erase(pos);
  385. }
  386. iterator erase(const_iterator first, const_iterator last)
  387. {
  388. while (first != last) {
  389. this->erase(first++);
  390. }
  391. return iterator{detail::foa::const_iterator_cast_tag{}, last};
  392. }
  393. BOOST_FORCEINLINE size_type erase(key_type const& key)
  394. {
  395. return table_.erase(key);
  396. }
  397. template <class K>
  398. BOOST_FORCEINLINE typename std::enable_if<
  399. detail::transparent_non_iterable<K, unordered_node_map>::value,
  400. size_type>::type
  401. erase(K const& key)
  402. {
  403. return table_.erase(key);
  404. }
  405. BOOST_FORCEINLINE init_type pull(const_iterator pos)
  406. {
  407. return table_.pull(pos);
  408. }
  409. void swap(unordered_node_map& rhs) noexcept(
  410. noexcept(std::declval<table_type&>().swap(std::declval<table_type&>())))
  411. {
  412. table_.swap(rhs.table_);
  413. }
  414. node_type extract(const_iterator pos)
  415. {
  416. BOOST_ASSERT(pos != end());
  417. node_type nh;
  418. auto elem = table_.extract(pos);
  419. detail::foa::node_handle_emplacer(nh)(
  420. std::move(elem), get_allocator());
  421. return nh;
  422. }
  423. node_type extract(key_type const& key)
  424. {
  425. auto pos = find(key);
  426. return pos != end() ? extract(pos) : node_type();
  427. }
  428. template <class K>
  429. typename std::enable_if<
  430. boost::unordered::detail::transparent_non_iterable<K,
  431. unordered_node_map>::value,
  432. node_type>::type
  433. extract(K const& key)
  434. {
  435. auto pos = find(key);
  436. return pos != end() ? extract(pos) : node_type();
  437. }
  438. template <class H2, class P2>
  439. void merge(
  440. unordered_node_map<key_type, mapped_type, H2, P2, allocator_type>&
  441. source)
  442. {
  443. BOOST_ASSERT(get_allocator() == source.get_allocator());
  444. table_.merge(source.table_);
  445. }
  446. template <class H2, class P2>
  447. void merge(
  448. unordered_node_map<key_type, mapped_type, H2, P2, allocator_type>&&
  449. source)
  450. {
  451. BOOST_ASSERT(get_allocator() == source.get_allocator());
  452. table_.merge(std::move(source.table_));
  453. }
  454. /// Lookup
  455. ///
  456. mapped_type& at(key_type const& key)
  457. {
  458. auto pos = table_.find(key);
  459. if (pos != table_.end()) {
  460. return pos->second;
  461. }
  462. // TODO: someday refactor this to conditionally serialize the key and
  463. // include it in the error message
  464. //
  465. boost::unordered::detail::throw_out_of_range(
  466. "key was not found in unordered_node_map");
  467. }
  468. mapped_type const& at(key_type const& key) const
  469. {
  470. auto pos = table_.find(key);
  471. if (pos != table_.end()) {
  472. return pos->second;
  473. }
  474. boost::unordered::detail::throw_out_of_range(
  475. "key was not found in unordered_node_map");
  476. }
  477. template <class K>
  478. typename std::enable_if<
  479. boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
  480. mapped_type&>::type
  481. at(K&& key)
  482. {
  483. auto pos = table_.find(std::forward<K>(key));
  484. if (pos != table_.end()) {
  485. return pos->second;
  486. }
  487. boost::unordered::detail::throw_out_of_range(
  488. "key was not found in unordered_node_map");
  489. }
  490. template <class K>
  491. typename std::enable_if<
  492. boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
  493. mapped_type const&>::type
  494. at(K&& key) const
  495. {
  496. auto pos = table_.find(std::forward<K>(key));
  497. if (pos != table_.end()) {
  498. return pos->second;
  499. }
  500. boost::unordered::detail::throw_out_of_range(
  501. "key was not found in unordered_node_map");
  502. }
  503. BOOST_FORCEINLINE mapped_type& operator[](key_type const& key)
  504. {
  505. return table_.try_emplace(key).first->second;
  506. }
  507. BOOST_FORCEINLINE mapped_type& operator[](key_type&& key)
  508. {
  509. return table_.try_emplace(std::move(key)).first->second;
  510. }
  511. template <class K>
  512. typename std::enable_if<
  513. boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
  514. mapped_type&>::type
  515. operator[](K&& key)
  516. {
  517. return table_.try_emplace(std::forward<K>(key)).first->second;
  518. }
  519. BOOST_FORCEINLINE size_type count(key_type const& key) const
  520. {
  521. auto pos = table_.find(key);
  522. return pos != table_.end() ? 1 : 0;
  523. }
  524. template <class K>
  525. BOOST_FORCEINLINE typename std::enable_if<
  526. detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
  527. count(K const& key) const
  528. {
  529. auto pos = table_.find(key);
  530. return pos != table_.end() ? 1 : 0;
  531. }
  532. BOOST_FORCEINLINE iterator find(key_type const& key)
  533. {
  534. return table_.find(key);
  535. }
  536. BOOST_FORCEINLINE const_iterator find(key_type const& key) const
  537. {
  538. return table_.find(key);
  539. }
  540. template <class K>
  541. BOOST_FORCEINLINE typename std::enable_if<
  542. boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
  543. iterator>::type
  544. find(K const& key)
  545. {
  546. return table_.find(key);
  547. }
  548. template <class K>
  549. BOOST_FORCEINLINE typename std::enable_if<
  550. boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
  551. const_iterator>::type
  552. find(K const& key) const
  553. {
  554. return table_.find(key);
  555. }
  556. BOOST_FORCEINLINE bool contains(key_type const& key) const
  557. {
  558. return this->find(key) != this->end();
  559. }
  560. template <class K>
  561. BOOST_FORCEINLINE typename std::enable_if<
  562. boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
  563. bool>::type
  564. contains(K const& key) const
  565. {
  566. return this->find(key) != this->end();
  567. }
  568. std::pair<iterator, iterator> equal_range(key_type const& key)
  569. {
  570. auto pos = table_.find(key);
  571. if (pos == table_.end()) {
  572. return {pos, pos};
  573. }
  574. auto next = pos;
  575. ++next;
  576. return {pos, next};
  577. }
  578. std::pair<const_iterator, const_iterator> equal_range(
  579. key_type const& key) const
  580. {
  581. auto pos = table_.find(key);
  582. if (pos == table_.end()) {
  583. return {pos, pos};
  584. }
  585. auto next = pos;
  586. ++next;
  587. return {pos, next};
  588. }
  589. template <class K>
  590. typename std::enable_if<
  591. detail::are_transparent<K, hasher, key_equal>::value,
  592. std::pair<iterator, iterator> >::type
  593. equal_range(K const& key)
  594. {
  595. auto pos = table_.find(key);
  596. if (pos == table_.end()) {
  597. return {pos, pos};
  598. }
  599. auto next = pos;
  600. ++next;
  601. return {pos, next};
  602. }
  603. template <class K>
  604. typename std::enable_if<
  605. detail::are_transparent<K, hasher, key_equal>::value,
  606. std::pair<const_iterator, const_iterator> >::type
  607. equal_range(K const& key) const
  608. {
  609. auto pos = table_.find(key);
  610. if (pos == table_.end()) {
  611. return {pos, pos};
  612. }
  613. auto next = pos;
  614. ++next;
  615. return {pos, next};
  616. }
  617. /// Hash Policy
  618. ///
  619. size_type bucket_count() const noexcept { return table_.capacity(); }
  620. float load_factor() const noexcept { return table_.load_factor(); }
  621. float max_load_factor() const noexcept
  622. {
  623. return table_.max_load_factor();
  624. }
  625. void max_load_factor(float) {}
  626. size_type max_load() const noexcept { return table_.max_load(); }
  627. void rehash(size_type n) { table_.rehash(n); }
  628. void reserve(size_type n) { table_.reserve(n); }
  629. #if defined(BOOST_UNORDERED_ENABLE_STATS)
  630. /// Stats
  631. ///
  632. stats get_stats() const { return table_.get_stats(); }
  633. void reset_stats() noexcept { table_.reset_stats(); }
  634. #endif
  635. /// Observers
  636. ///
  637. hasher hash_function() const { return table_.hash_function(); }
  638. key_equal key_eq() const { return table_.key_eq(); }
  639. };
  640. template <class Key, class T, class Hash, class KeyEqual, class Allocator>
  641. bool operator==(
  642. unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
  643. unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
  644. {
  645. return lhs.table_ == rhs.table_;
  646. }
  647. template <class Key, class T, class Hash, class KeyEqual, class Allocator>
  648. bool operator!=(
  649. unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
  650. unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
  651. {
  652. return !(lhs == rhs);
  653. }
  654. template <class Key, class T, class Hash, class KeyEqual, class Allocator>
  655. void swap(unordered_node_map<Key, T, Hash, KeyEqual, Allocator>& lhs,
  656. unordered_node_map<Key, T, Hash, KeyEqual, Allocator>& rhs)
  657. noexcept(noexcept(lhs.swap(rhs)))
  658. {
  659. lhs.swap(rhs);
  660. }
  661. template <class Key, class T, class Hash, class KeyEqual, class Allocator,
  662. class Pred>
  663. typename unordered_node_map<Key, T, Hash, KeyEqual, Allocator>::size_type
  664. erase_if(
  665. unordered_node_map<Key, T, Hash, KeyEqual, Allocator>& map, Pred pred)
  666. {
  667. return erase_if(map.table_, pred);
  668. }
  669. template <class Archive, class Key, class T, class Hash, class KeyEqual,
  670. class Allocator>
  671. void serialize(Archive& ar,
  672. unordered_node_map<Key, T, Hash, KeyEqual, Allocator>& map,
  673. unsigned int version)
  674. {
  675. detail::serialize_container(ar, map, version);
  676. }
  677. #if defined(BOOST_MSVC)
  678. #pragma warning(pop) /* C4714 */
  679. #endif
  680. #if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
  681. template <class InputIterator,
  682. class Hash =
  683. boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
  684. class Pred =
  685. std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
  686. class Allocator = std::allocator<
  687. boost::unordered::detail::iter_to_alloc_t<InputIterator> >,
  688. class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
  689. class = std::enable_if_t<detail::is_hash_v<Hash> >,
  690. class = std::enable_if_t<detail::is_pred_v<Pred> >,
  691. class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
  692. unordered_node_map(InputIterator, InputIterator,
  693. std::size_t = boost::unordered::detail::foa::default_bucket_count,
  694. Hash = Hash(), Pred = Pred(), Allocator = Allocator())
  695. -> unordered_node_map<boost::unordered::detail::iter_key_t<InputIterator>,
  696. boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred,
  697. Allocator>;
  698. template <class Key, class T,
  699. class Hash = boost::hash<std::remove_const_t<Key> >,
  700. class Pred = std::equal_to<std::remove_const_t<Key> >,
  701. class Allocator = std::allocator<std::pair<const Key, T> >,
  702. class = std::enable_if_t<detail::is_hash_v<Hash> >,
  703. class = std::enable_if_t<detail::is_pred_v<Pred> >,
  704. class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
  705. unordered_node_map(std::initializer_list<std::pair<Key, T> >,
  706. std::size_t = boost::unordered::detail::foa::default_bucket_count,
  707. Hash = Hash(), Pred = Pred(), Allocator = Allocator())
  708. -> unordered_node_map<std::remove_const_t<Key>, T, Hash, Pred,
  709. Allocator>;
  710. template <class InputIterator, class Allocator,
  711. class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
  712. class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
  713. unordered_node_map(InputIterator, InputIterator, std::size_t, Allocator)
  714. -> unordered_node_map<boost::unordered::detail::iter_key_t<InputIterator>,
  715. boost::unordered::detail::iter_val_t<InputIterator>,
  716. boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
  717. std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
  718. Allocator>;
  719. template <class InputIterator, class Allocator,
  720. class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
  721. class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
  722. unordered_node_map(InputIterator, InputIterator, Allocator)
  723. -> unordered_node_map<boost::unordered::detail::iter_key_t<InputIterator>,
  724. boost::unordered::detail::iter_val_t<InputIterator>,
  725. boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
  726. std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
  727. Allocator>;
  728. template <class InputIterator, class Hash, class Allocator,
  729. class = std::enable_if_t<detail::is_hash_v<Hash> >,
  730. class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
  731. class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
  732. unordered_node_map(
  733. InputIterator, InputIterator, std::size_t, Hash, Allocator)
  734. -> unordered_node_map<boost::unordered::detail::iter_key_t<InputIterator>,
  735. boost::unordered::detail::iter_val_t<InputIterator>, Hash,
  736. std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
  737. Allocator>;
  738. template <class Key, class T, class Allocator,
  739. class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
  740. unordered_node_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
  741. Allocator) -> unordered_node_map<std::remove_const_t<Key>, T,
  742. boost::hash<std::remove_const_t<Key> >,
  743. std::equal_to<std::remove_const_t<Key> >, Allocator>;
  744. template <class Key, class T, class Allocator,
  745. class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
  746. unordered_node_map(std::initializer_list<std::pair<Key, T> >, Allocator)
  747. -> unordered_node_map<std::remove_const_t<Key>, T,
  748. boost::hash<std::remove_const_t<Key> >,
  749. std::equal_to<std::remove_const_t<Key> >, Allocator>;
  750. template <class Key, class T, class Hash, class Allocator,
  751. class = std::enable_if_t<detail::is_hash_v<Hash> >,
  752. class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
  753. unordered_node_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
  754. Hash, Allocator) -> unordered_node_map<std::remove_const_t<Key>, T,
  755. Hash, std::equal_to<std::remove_const_t<Key> >, Allocator>;
  756. #endif
  757. } // namespace unordered
  758. } // namespace boost
  759. #endif