hash_table.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. /* Declarations for the hash table template type.
  2. This file is part of xrcu.
  3. xrcu is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  13. #ifndef __XRCU_HASHTABLE_HPP__
  14. #define __XRCU_HASHTABLE_HPP__ 1
  15. #include "xrcu.hpp"
  16. #include "xatomic.hpp"
  17. #include "optional.hpp"
  18. #include "lwlock.hpp"
  19. #include "utils.hpp"
  20. #include <atomic>
  21. #include <functional>
  22. #include <type_traits>
  23. #include <initializer_list>
  24. #include <cstddef>
  25. namespace std
  26. {
  27. struct forward_iterator_tag;
  28. }
  29. namespace xrcu
  30. {
  31. namespace detail
  32. {
  33. inline constexpr size_t table_idx (size_t idx)
  34. {
  35. return (idx * 2);
  36. }
  37. struct alignas (uintptr_t) ht_vector : public finalizable
  38. {
  39. uintptr_t *data;
  40. size_t entries;
  41. size_t pidx;
  42. std::atomic<size_t> nelems { 0 };
  43. ht_vector (uintptr_t *ep) : data (ep) {}
  44. void safe_destroy ();
  45. size_t size () const
  46. {
  47. return (table_idx (this->entries));
  48. }
  49. };
  50. inline size_t
  51. secondary_hash (size_t hval)
  52. {
  53. static const size_t keys[] = { 2, 3, 5, 7 };
  54. return (keys[hval % (sizeof (keys) / sizeof (keys[0]))]);
  55. }
  56. extern size_t find_hsize (size_t size, float ldf, size_t& pidx);
  57. extern ht_vector* make_htvec (size_t pidx, uintptr_t key, uintptr_t val);
  58. struct ht_sentry
  59. {
  60. lwlock *lock;
  61. uintptr_t xbit;
  62. ht_vector *vector = nullptr;
  63. ht_sentry (lwlock *lp, uintptr_t xb) : lock (lp), xbit (~xb)
  64. {
  65. this->lock->acquire ();
  66. }
  67. ~ht_sentry ()
  68. {
  69. if (this->vector)
  70. for (size_t i = table_idx (0) + 1; i < this->vector->size (); i += 2)
  71. xatomic_and (&this->vector->data[i], this->xbit);
  72. this->lock->release ();
  73. }
  74. };
  75. template <class Ktraits, class Vtraits>
  76. struct ht_iter : public cs_guard
  77. {
  78. const ht_vector *vec = nullptr;
  79. size_t idx = 0;
  80. uintptr_t c_key;
  81. uintptr_t c_val;
  82. bool valid = false;
  83. typedef std::forward_iterator_tag iterator_category;
  84. void _Init (const ht_vector *vp)
  85. {
  86. this->vec = vp;
  87. this->_Adv ();
  88. }
  89. ht_iter ()
  90. {
  91. }
  92. ht_iter (const ht_iter<Ktraits, Vtraits>& right) :
  93. vec (right.vec), idx (right.idx), c_key (right.c_key),
  94. c_val (right.c_val), valid (right.valid)
  95. {
  96. }
  97. ht_iter (ht_iter<Ktraits, Vtraits>&& right) :
  98. vec (right.vec), idx (right.idx), c_key (right.c_key),
  99. c_val (right.c_val), valid (right.valid)
  100. {
  101. right.vec = nullptr;
  102. right.idx = 0;
  103. right.valid = false;
  104. }
  105. void _Adv ()
  106. {
  107. this->valid = false;
  108. for (; this->idx < this->vec->size (); )
  109. {
  110. this->c_key = this->vec->data[this->idx + 0];
  111. this->c_val = this->vec->data[this->idx + 1] & ~Vtraits::XBIT;
  112. this->idx += 2;
  113. if ((this->c_key & ~Ktraits::XBIT) != Ktraits::FREE &&
  114. this->c_val != Vtraits::FREE && this->c_val != Vtraits::DELT)
  115. {
  116. this->valid = true;
  117. break;
  118. }
  119. }
  120. }
  121. bool operator== (const ht_iter<Ktraits, Vtraits>& right) const
  122. {
  123. return ((!this->valid && !right.valid) ||
  124. (this->vec == right.vec && this->idx == right.idx));
  125. }
  126. bool operator!= (const ht_iter<Ktraits, Vtraits>& right)
  127. {
  128. return (!(*this == right));
  129. }
  130. };
  131. struct ht_inserter
  132. {
  133. uintptr_t value;
  134. ht_inserter (uintptr_t v) : value (v) {}
  135. uintptr_t call0 () const noexcept
  136. {
  137. return (this->value);
  138. }
  139. uintptr_t call1 (uintptr_t) const noexcept
  140. {
  141. return (this->value);
  142. }
  143. void free (uintptr_t) {}
  144. };
  145. } // namespace detail
  146. template <class KeyT, class ValT,
  147. class EqFn = std::equal_to<KeyT>,
  148. class HashFn = std::hash<KeyT> >
  149. struct hash_table
  150. {
  151. typedef detail::wrapped_traits<(sizeof (KeyT) < sizeof (uintptr_t) &&
  152. std::is_integral<KeyT>::value) || (std::is_pointer<KeyT>::value &&
  153. alignof (KeyT) >= 8), KeyT> key_traits;
  154. typedef detail::wrapped_traits<(sizeof (ValT) < sizeof (uintptr_t) &&
  155. std::is_integral<ValT>::value) || (std::is_pointer<ValT>::value &&
  156. alignof (ValT) >= 8), ValT> val_traits;
  157. typedef hash_table<KeyT, ValT, EqFn, HashFn> self_type;
  158. typedef KeyT key_type;
  159. typedef ValT mapped_type;
  160. typedef std::pair<KeyT, ValT> value_type;
  161. typedef EqFn key_equal;
  162. typedef HashFn hasher;
  163. typedef value_type& reference;
  164. typedef const value_type& const_reference;
  165. typedef value_type* pointer;
  166. typedef const value_type* const_pointer;
  167. typedef ptrdiff_t difference_type;
  168. typedef size_t size_type;
  169. detail::ht_vector *vec;
  170. EqFn eqfn;
  171. HashFn hashfn;
  172. float loadf = 0.85f;
  173. std::atomic<intptr_t> grow_limit;
  174. lwlock lock;
  175. void _Set_loadf (float ldf)
  176. {
  177. if (ldf >= 0.4f && ldf <= 0.9f)
  178. this->loadf = ldf;
  179. }
  180. float load_factor (float ldf)
  181. {
  182. this->lock.acquire ();
  183. float ret = this->loadf;
  184. this->_Set_loadf (ldf);
  185. this->lock.release ();
  186. return (ret);
  187. }
  188. float load_factor () const
  189. {
  190. return (this->loadf);
  191. }
  192. void _Init (size_t size, float ldf, EqFn e, HashFn h)
  193. {
  194. this->_Set_loadf (ldf);
  195. size_t pidx, gt = detail::find_hsize (size, this->loadf, pidx);
  196. this->vec = detail::make_htvec (pidx,
  197. key_traits::FREE, val_traits::FREE);
  198. this->eqfn = e;
  199. this->hashfn = h;
  200. this->grow_limit.store (gt, std::memory_order_relaxed);
  201. this->vec->nelems.store (0, std::memory_order_relaxed);
  202. }
  203. hash_table (size_t size = 0, float ldf = 0.85f,
  204. EqFn e = EqFn (), HashFn h = HashFn ())
  205. {
  206. this->_Init (size, ldf, e, h);
  207. }
  208. template <class Iter>
  209. hash_table (Iter first, Iter last, float ldf = 0.85f,
  210. EqFn e = EqFn (), HashFn h = HashFn ())
  211. {
  212. this->_Init (0, ldf, e, h);
  213. for (; first != last; ++first)
  214. this->insert ((*first).first, (*first).second);
  215. }
  216. hash_table (std::initializer_list<std::pair<KeyT, ValT> > lst,
  217. float ldf = 0.85f, EqFn e = EqFn (), HashFn h = HashFn ()) :
  218. hash_table (lst.begin (), lst.end (), ldf, e, h)
  219. {
  220. }
  221. hash_table (const self_type& right) :
  222. hash_table (right.begin (), right.end ())
  223. {
  224. }
  225. hash_table (self_type&& right)
  226. {
  227. this->vec = right.vec;
  228. this->eqfn = right.eqfn;
  229. this->hashfn = right.hashfn;
  230. this->loadf = right.loadf;
  231. this->grow_limit.store ((intptr_t)(this->loadf * this->size ()),
  232. std::memory_order_relaxed);
  233. right.vec = nullptr;
  234. }
  235. size_t size () const
  236. {
  237. cs_guard g;
  238. return (this->vec->nelems.load (std::memory_order_relaxed));
  239. }
  240. size_t max_size () const
  241. {
  242. size_t out;
  243. return (detail::find_hsize (~(size_t)0, 0.85f, out));
  244. }
  245. bool empty () const
  246. {
  247. return (this->size () == 0);
  248. }
  249. size_t _Probe (const KeyT& key, const detail::ht_vector *vp,
  250. bool put_p, bool& found) const
  251. {
  252. size_t code = this->hashfn (key);
  253. size_t entries = vp->entries;
  254. size_t idx = code % entries;
  255. size_t vidx = detail::table_idx (idx);
  256. found = false;
  257. uintptr_t k = vp->data[vidx];
  258. if (k == key_traits::FREE)
  259. return (put_p ? (found = true, vidx) : (size_t)-1);
  260. else if (k != key_traits::DELT &&
  261. this->eqfn (key_traits::get (k), key))
  262. return (vidx);
  263. for (size_t initial = idx, sec = detail::secondary_hash (code) ; ; )
  264. {
  265. if ((idx += sec) >= entries)
  266. idx -= entries;
  267. if (idx == initial)
  268. return ((size_t)-1);
  269. vidx = detail::table_idx (idx);
  270. k = vp->data[vidx];
  271. if (k == key_traits::FREE)
  272. return (put_p ? (found = true, vidx) : (size_t)-1);
  273. else if (k != key_traits::DELT &&
  274. this->eqfn (key_traits::get (k), key))
  275. return (vidx);
  276. }
  277. }
  278. size_t _Probe (const KeyT& key, const detail::ht_vector *vp, bool put_p) const
  279. {
  280. bool unused;
  281. return (this->_Probe (key, vp, put_p, unused));
  282. }
  283. size_t _Gprobe (uintptr_t key, detail::ht_vector *vp)
  284. {
  285. size_t code = this->hashfn (key_traits::get (key));
  286. size_t entries = vp->entries;
  287. size_t idx = code % entries;
  288. size_t vidx = detail::table_idx (idx);
  289. if (vp->data[vidx] == key_traits::FREE)
  290. return (vidx);
  291. for (size_t sec = detail::secondary_hash (code) ; ; )
  292. {
  293. if ((idx += sec) >= entries)
  294. idx -= entries;
  295. vidx = detail::table_idx (idx);
  296. if (vp->data[vidx] == key_traits::FREE)
  297. return (vidx);
  298. }
  299. }
  300. void _Rehash ()
  301. {
  302. detail::ht_sentry s (&this->lock, val_traits::XBIT);
  303. if (this->grow_limit.load (std::memory_order_relaxed) <= 0)
  304. {
  305. auto old = this->vec;
  306. auto np = detail::make_htvec (old->pidx + 1,
  307. key_traits::FREE, val_traits::FREE);
  308. size_t nelem = 0;
  309. s.vector = old;
  310. for (size_t i = detail::table_idx (0); i < old->size (); i += 2)
  311. {
  312. uintptr_t key = old->data[i];
  313. uintptr_t val = xatomic_or (&old->data[i + 1], val_traits::XBIT);
  314. if (key != key_traits::FREE && key != key_traits::DELT &&
  315. val != val_traits::FREE && val != val_traits::DELT)
  316. {
  317. size_t nidx = this->_Gprobe (key, np);
  318. np->data[nidx + 0] = key;
  319. np->data[nidx + 1] = val;
  320. ++nelem;
  321. }
  322. }
  323. s.vector = nullptr;
  324. np->nelems.store (nelem, std::memory_order_relaxed);
  325. this->grow_limit.store ((intptr_t)(np->entries * this->loadf) -
  326. nelem, std::memory_order_relaxed);
  327. std::atomic_thread_fence (std::memory_order_release);
  328. /* At this point, another thread may decrement the growth limit
  329. * from the wrong vector. That's fine, it just means we'll move
  330. * the table sooner than necessary. */
  331. this->vec = np;
  332. finalize (old);
  333. }
  334. }
  335. uintptr_t _Find (const KeyT& key) const
  336. {
  337. auto vp = this->vec;
  338. size_t idx = this->_Probe (key, vp, false);
  339. return (idx == (size_t)-1 ? val_traits::DELT :
  340. vp->data[idx + 1] & ~val_traits::XBIT);
  341. }
  342. optional<ValT> find (const KeyT& key) const
  343. {
  344. cs_guard g;
  345. uintptr_t val = this->_Find (key);
  346. return (val == val_traits::DELT ? optional<ValT> () :
  347. optional<ValT> (val_traits::get (val)));
  348. }
  349. ValT find (const KeyT& key, const ValT& dfl) const
  350. {
  351. cs_guard g;
  352. uintptr_t val = this->_Find (key);
  353. return (val == val_traits::DELT ? dfl : val_traits::get (val));
  354. }
  355. bool contains (const KeyT& key) const
  356. {
  357. cs_guard g;
  358. return (this->_Find (key) != val_traits::DELT);
  359. }
  360. bool _Decr_limit ()
  361. {
  362. while (true)
  363. {
  364. auto limit = this->grow_limit.load (std::memory_order_relaxed);
  365. if (limit <= 0)
  366. return (false);
  367. else if (this->grow_limit.compare_exchange_weak (limit, limit - 1,
  368. std::memory_order_acq_rel, std::memory_order_relaxed))
  369. return (true);
  370. xatomic_spin_nop ();
  371. }
  372. }
  373. template <class Fn, class ...Args>
  374. bool _Upsert (uintptr_t k, const KeyT& key, Fn f, Args... args)
  375. {
  376. cs_guard g;
  377. while (true)
  378. {
  379. auto vp = this->vec;
  380. uintptr_t *ep = vp->data;
  381. bool found;
  382. size_t idx = this->_Probe (key, vp, true, found);
  383. if (!found)
  384. {
  385. uintptr_t tmp = ep[idx + 1];
  386. if (tmp != val_traits::DELT && tmp != val_traits::FREE &&
  387. (tmp & val_traits::XBIT) == 0)
  388. {
  389. uintptr_t v = f.call1 (tmp, args...);
  390. if (v == tmp ||
  391. xatomic_cas_bool (ep + idx + 1, tmp, v))
  392. {
  393. key_traits::free (k);
  394. if (v != tmp)
  395. val_traits::destroy (tmp);
  396. return (found);
  397. }
  398. f.free (v);
  399. continue;
  400. }
  401. }
  402. else if (this->_Decr_limit ())
  403. {
  404. /* NOTE: If we fail here, then the growth threshold will end up
  405. * too small. This simply means that we may have to rehash sooner
  406. * than absolutely necessary, which is harmless. On the other
  407. * hand, we must NOT try to reincrement the limit back, because
  408. * it risks ending up too big, which can be harmful if, for
  409. * example, a rehash is triggered before the increment. */
  410. uintptr_t v = f.call0 (args...);
  411. #ifdef XRCU_HAVE_XATOMIC_DCAS
  412. if (xatomic_dcas_bool (&ep[idx], key_traits::FREE,
  413. val_traits::FREE, k, v))
  414. #else
  415. if (xatomic_cas_bool (ep + idx + 0, key_traits::FREE, k) &&
  416. xatomic_cas_bool (ep + idx + 1, val_traits::FREE, v))
  417. #endif
  418. {
  419. vp->nelems.fetch_add (1, std::memory_order_acq_rel);
  420. return (found);
  421. }
  422. f.free (v);
  423. continue;
  424. }
  425. // The table was being rehashed - retry.
  426. this->_Rehash ();
  427. }
  428. }
  429. bool insert (const KeyT& key, const ValT& val)
  430. {
  431. uintptr_t k = key_traits::make (key), v = val_traits::XBIT;
  432. try
  433. {
  434. v = val_traits::make (val);
  435. return (this->_Upsert (k, key, detail::ht_inserter (v)));
  436. }
  437. catch (...)
  438. {
  439. key_traits::free (k);
  440. if (v != val_traits::XBIT)
  441. val_traits::free (v);
  442. throw;
  443. }
  444. }
  445. template <class Fn, class Vtraits>
  446. struct _Updater
  447. {
  448. Fn fct;
  449. _Updater (Fn f) : fct (f) {}
  450. template <class ...Args>
  451. uintptr_t call0 (Args ...args)
  452. { // Call function with default-constructed value and arguments.
  453. auto tmp = (typename Vtraits::value_type ());
  454. auto&& rv = this->fct (tmp, args...);
  455. return (Vtraits::make (rv));
  456. }
  457. template <class ...Args>
  458. uintptr_t call1 (uintptr_t x, Args ...args)
  459. { // Call function with stored value and arguments.
  460. auto&& tmp = Vtraits::get (x);
  461. auto&& rv = this->fct (tmp, args...);
  462. return (Vtraits::XBIT == 1 &&
  463. &rv == &tmp ? x : Vtraits::make (rv));
  464. }
  465. void free (uintptr_t x)
  466. {
  467. Vtraits::free (x);
  468. }
  469. };
  470. template <class Fn, class ...Args>
  471. bool update (const KeyT& key, Fn f, Args... args)
  472. {
  473. uintptr_t k = key_traits::make (key);
  474. try
  475. {
  476. return (this->_Upsert (k, key,
  477. _Updater<Fn, val_traits> (f), args...));
  478. }
  479. catch (...)
  480. {
  481. key_traits::free (k);
  482. throw;
  483. }
  484. }
  485. bool _Erase (const KeyT& key, optional<ValT> *outp = nullptr)
  486. {
  487. cs_guard g;
  488. while (true)
  489. {
  490. auto vp = this->vec;
  491. uintptr_t *ep = vp->data;
  492. size_t idx = this->_Probe (key, vp, false);
  493. if (idx == (size_t)-1)
  494. return (false);
  495. uintptr_t oldk = ep[idx], oldv = ep[idx + 1];
  496. if ((oldv & val_traits::XBIT) == 0)
  497. {
  498. if (oldk == key_traits::DELT || oldk == key_traits::FREE ||
  499. oldv == val_traits::DELT)
  500. return (false);
  501. else if (!xatomic_cas_bool (ep + idx + 1,
  502. oldv, val_traits::DELT))
  503. continue;
  504. vp->nelems.fetch_sub (1, std::memory_order_acq_rel);
  505. // Safe to set the key without atomic ops.
  506. ep[idx] = key_traits::DELT;
  507. key_traits::destroy (oldk);
  508. val_traits::destroy (oldv);
  509. if (outp)
  510. *outp = val_traits::get (oldv);
  511. return (true);
  512. }
  513. // The table was being rehashed - retry.
  514. this->_Rehash ();
  515. }
  516. }
  517. bool erase (const KeyT& key)
  518. {
  519. return (this->_Erase (key));
  520. }
  521. optional<ValT> remove (const KeyT& key)
  522. {
  523. optional<ValT> ret;
  524. this->_Erase (key, &ret);
  525. return (ret);
  526. }
  527. struct iterator : public detail::ht_iter<key_traits, val_traits>
  528. {
  529. typedef detail::ht_iter<key_traits, val_traits> base_type;
  530. iterator () : base_type ()
  531. {
  532. }
  533. iterator (const self_type& self) : base_type ()
  534. {
  535. this->_Init (self.vec);
  536. }
  537. iterator (const iterator& right) : base_type (right)
  538. {
  539. }
  540. iterator (iterator&& right) : base_type (std::move (right))
  541. {
  542. }
  543. KeyT key () const
  544. {
  545. return (key_traits::get (this->c_key));
  546. }
  547. ValT value () const
  548. {
  549. return (val_traits::get (this->c_val));
  550. }
  551. iterator& operator++ ()
  552. {
  553. this->_Adv ();
  554. return (*this);
  555. }
  556. iterator operator++ (int)
  557. {
  558. iterator ret = *this;
  559. this->_Adv ();
  560. return (ret);
  561. }
  562. std::pair<KeyT, ValT> operator* () const
  563. {
  564. return (std::pair<KeyT, ValT> (this->key (), this->value ()));
  565. }
  566. };
  567. typedef iterator const_iterator;
  568. iterator begin () const
  569. {
  570. return (iterator (*this));
  571. }
  572. iterator end () const
  573. {
  574. return (iterator ());
  575. }
  576. iterator cbegin () const
  577. {
  578. return (this->begin ());
  579. }
  580. iterator cend () const
  581. {
  582. return (this->end ());
  583. }
  584. void _Assign_vector (detail::ht_vector *nv, intptr_t gt)
  585. {
  586. // First step: Lock the table.
  587. this->lock.acquire ();
  588. auto prev = this->vec;
  589. // Second step: Finalize every valid key/value pair.
  590. for (size_t i = detail::table_idx (0) + 1; i < prev->size (); i += 2)
  591. {
  592. uintptr_t v = xatomic_or (&prev->data[i], val_traits::XBIT);
  593. if (v != val_traits::FREE && v != val_traits::DELT)
  594. {
  595. key_traits::destroy (prev->data[i - 1]);
  596. val_traits::destroy (v);
  597. }
  598. }
  599. // Third step: Set up the new vector and parameters.
  600. this->grow_limit.store (gt, std::memory_order_relaxed);
  601. std::atomic_thread_fence (std::memory_order_release);
  602. this->vec = nv;
  603. this->lock.release ();
  604. finalize (prev);
  605. }
  606. void clear ()
  607. {
  608. this->lock.acquire ();
  609. this->grow_limit.store (0, std::memory_order_release);
  610. for (size_t i = detail::table_idx (0); i < this->vec->size (); i += 2)
  611. {
  612. uintptr_t k = this->vec->data[i];
  613. this->vec->data[i] = key_traits::FREE;
  614. std::atomic_thread_fence (std::memory_order_release);
  615. uintptr_t v = xatomic_swap (&this->vec->data[i + 1],
  616. val_traits::FREE) & ~val_traits::XBIT;
  617. if (k != key_traits::FREE && k != key_traits::DELT)
  618. key_traits::destroy (k);
  619. if (v != val_traits::FREE && v != val_traits::DELT)
  620. val_traits::destroy (v);
  621. }
  622. this->grow_limit.store ((intptr_t)(this->loadf * this->size ()),
  623. std::memory_order_relaxed);
  624. this->vec->nelems.store (0, std::memory_order_release);
  625. this->lock.release ();
  626. }
  627. template <class Iter>
  628. void assign (Iter first, Iter last)
  629. {
  630. self_type tmp (first, last, 0, this->loadf);
  631. this->_Assign_vector (tmp.vec,
  632. tmp.grow_limit.load (std::memory_order_relaxed));
  633. tmp.vec = nullptr;
  634. }
  635. void assign (std::initializer_list<std::pair<KeyT, ValT> > lst)
  636. {
  637. this->assign (lst.begin (), lst.end ());
  638. }
  639. self_type& operator= (const self_type& right)
  640. {
  641. this->assign (right.begin (), right.end ());
  642. return (*this);
  643. }
  644. self_type& operator= (self_type&& right)
  645. {
  646. this->_Assign_vector (right.vec,
  647. right.grow_limit.load (std::memory_order_relaxed));
  648. this->loadf = right.loadf;
  649. right.vec = nullptr;
  650. return (*this);
  651. }
  652. void swap (self_type& right)
  653. {
  654. if (this == &right)
  655. return;
  656. detail::ht_sentry s1 (&this->lock, ~val_traits::XBIT);
  657. detail::ht_sentry s2 (&right.lock, ~val_traits::XBIT);
  658. // Prevent further insertions (still allows deletions).
  659. this->grow_limit.store (0, std::memory_order_release);
  660. right.grow_limit.store (0, std::memory_order_release);
  661. std::swap (this->vec, right.vec);
  662. std::swap (this->eqfn, right.eqfn);
  663. std::swap (this->hashfn, right.hashfn);
  664. std::swap (this->loadf, right.loadf);
  665. this->grow_limit.store ((intptr_t)(this->loadf *
  666. this->vec->entries) - this->size (), std::memory_order_release);
  667. right.grow_limit.store ((intptr_t)(right.loadf *
  668. right.vec->entries) - right.size (), std::memory_order_release);
  669. }
  670. ~hash_table ()
  671. {
  672. if (!this->vec)
  673. return;
  674. for (size_t i = detail::table_idx (0); i < this->vec->size (); i += 2)
  675. {
  676. uintptr_t k = this->vec->data[i] & ~key_traits::XBIT;
  677. if (k == key_traits::FREE || k == key_traits::DELT)
  678. continue;
  679. key_traits::free (k);
  680. val_traits::free (this->vec->data[i + 1] & ~val_traits::XBIT);
  681. }
  682. this->vec->safe_destroy ();
  683. this->vec = nullptr;
  684. }
  685. };
  686. } // namespace xrcu
  687. namespace std
  688. {
  689. template <class KeyT, class ValT, class EqFn, class HashFn>
  690. void swap (xrcu::hash_table<KeyT, ValT, EqFn, HashFn>& left,
  691. xrcu::hash_table<KeyT, ValT, EqFn, HashFn>& right)
  692. {
  693. left.swap (right);
  694. }
  695. } // namespace std
  696. #endif