hash_table.h 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484
  1. #pragma once
  2. #include "fwd.h"
  3. #include "mapfindptr.h"
  4. #include <util/memory/alloc.h>
  5. #include <util/system/compiler.h>
  6. #include <util/system/type_name.h>
  7. #include <util/system/yassert.h>
  8. #include <util/str_stl.h>
  9. #include "yexception.h"
  10. #include "typetraits.h"
  11. #include "utility.h"
  12. #include <algorithm>
  13. #include <initializer_list>
  14. #include <memory>
  15. #include <tuple>
  16. #include <utility>
  17. #include <cstdlib>
  18. #include "hash_primes.h"
  19. struct TSelect1st {
  20. template <class TPair>
  21. inline const typename TPair::first_type& operator()(const TPair& x) const {
  22. return x.first;
  23. }
  24. };
  25. template <class Value>
  26. struct __yhashtable_node {
  27. /** If the first bit is not set, then this is a pointer to the next node in
  28. * the list of nodes for the current bucket. Otherwise this is a pointer of
  29. * type __yhashtable_node**, pointing back into the buckets array.
  30. *
  31. * This trick makes it possible to use only one node pointer in a hash table
  32. * iterator. */
  33. __yhashtable_node* next;
  34. /** Value stored in a node. */
  35. Value val;
  36. __yhashtable_node& operator=(const __yhashtable_node&) = delete;
  37. };
  38. template <class Value, class Key, class HashFcn,
  39. class ExtractKey, class EqualKey, class Alloc>
  40. class THashTable;
  41. template <class Key, class T, class HashFcn,
  42. class EqualKey, typename size_type_f>
  43. class sthash;
  44. template <class Value>
  45. struct __yhashtable_iterator;
  46. template <class Value>
  47. struct __yhashtable_const_iterator;
  48. template <class Value>
  49. struct __yhashtable_iterator {
  50. using iterator = __yhashtable_iterator<Value>;
  51. using const_iterator = __yhashtable_const_iterator<Value>;
  52. using node = __yhashtable_node<Value>;
  53. using iterator_category = std::forward_iterator_tag;
  54. using value_type = Value;
  55. using difference_type = ptrdiff_t;
  56. using size_type = size_t;
  57. using reference = Value&;
  58. using pointer = Value*;
  59. node* cur;
  60. explicit __yhashtable_iterator(node* n)
  61. : cur(n)
  62. {
  63. } /*y*/
  64. __yhashtable_iterator() = default;
  65. reference operator*() const {
  66. return cur->val;
  67. }
  68. pointer operator->() const {
  69. return &(operator*());
  70. }
  71. iterator& operator++();
  72. iterator operator++(int);
  73. friend bool operator==(const iterator& l, const iterator& r) {
  74. return l.cur == r.cur;
  75. }
  76. friend bool operator!=(const iterator& l, const iterator& r) {
  77. return l.cur != r.cur;
  78. }
  79. bool IsEnd() const {
  80. return !cur;
  81. }
  82. Y_FORCE_INLINE explicit operator bool() const noexcept {
  83. return cur != nullptr;
  84. }
  85. };
  86. template <class Value>
  87. struct __yhashtable_const_iterator {
  88. using iterator = __yhashtable_iterator<Value>;
  89. using const_iterator = __yhashtable_const_iterator<Value>;
  90. using node = __yhashtable_node<Value>;
  91. using iterator_category = std::forward_iterator_tag;
  92. using value_type = Value;
  93. using difference_type = ptrdiff_t;
  94. using size_type = size_t;
  95. using reference = const Value&;
  96. using pointer = const Value*;
  97. const node* cur;
  98. explicit __yhashtable_const_iterator(const node* n)
  99. : cur(n)
  100. {
  101. }
  102. __yhashtable_const_iterator() {
  103. }
  104. __yhashtable_const_iterator(const iterator& it)
  105. : cur(it.cur)
  106. {
  107. }
  108. reference operator*() const {
  109. return cur->val;
  110. }
  111. pointer operator->() const {
  112. return &(operator*());
  113. }
  114. const_iterator& operator++();
  115. const_iterator operator++(int);
  116. friend bool operator==(const const_iterator& l, const const_iterator& r) {
  117. return l.cur == r.cur;
  118. }
  119. friend bool operator!=(const const_iterator& l, const const_iterator& r) {
  120. return l.cur != r.cur;
  121. }
  122. bool IsEnd() const {
  123. return !cur;
  124. }
  125. Y_FORCE_INLINE explicit operator bool() const noexcept {
  126. return cur != nullptr;
  127. }
  128. };
  129. /**
  130. * This class saves some space in allocator-based containers for the most common
  131. * use case of empty allocators. This is achieved thanks to the application of
  132. * empty base class optimization (aka EBCO).
  133. */
  134. template <class Alloc>
  135. class _allocator_base: private Alloc {
  136. public:
  137. _allocator_base(const Alloc& other)
  138. : Alloc(other)
  139. {
  140. }
  141. Alloc& _get_alloc() {
  142. return static_cast<Alloc&>(*this);
  143. }
  144. const Alloc& _get_alloc() const {
  145. return static_cast<const Alloc&>(*this);
  146. }
  147. void _set_alloc(const Alloc& allocator) {
  148. _get_alloc() = allocator;
  149. }
  150. void swap(_allocator_base& other) {
  151. DoSwap(_get_alloc(), other._get_alloc());
  152. }
  153. };
  154. /**
  155. * Wrapper for an array of THashTable buckets.
  156. *
  157. * Is better than vector for this particular use case. Main differences:
  158. * - Occupies one less word on stack.
  159. * - Doesn't even try to initialize its elements. It is THashTable's responsibility.
  160. * - Presents a better interface in relation to THashTable's marker element trick.
  161. *
  162. * Internally this class is just a pointer-size pair, and the data on the heap
  163. * has the following structure:
  164. *
  165. * +----------+----------------------+----------+-------------------------+
  166. * | raw_size | elements ... | marker | unused space [optional] |
  167. * +----------+----------------------+----------+-------------------------+
  168. * ^ ^
  169. * | |
  170. * Data points here end() points here
  171. *
  172. * `raw_size` stores the size of the allocated memory block. It is used to
  173. * support resizing without reallocation.
  174. *
  175. * `marker` is a special marker element that is set by the THashTable that is
  176. * then used in iterator implementation to know when the end is reached.
  177. *
  178. * Unused space at the end of the memory block may not be present.
  179. */
  180. template <class T, class Alloc>
  181. class _yhashtable_buckets: private _allocator_base<Alloc> {
  182. using base_type = _allocator_base<Alloc>;
  183. static_assert(sizeof(T) == sizeof(size_t), "T is expected to be the same size as size_t.");
  184. public:
  185. using allocator_type = Alloc;
  186. using value_type = T;
  187. using pointer = T*;
  188. using const_pointer = const T*;
  189. using reference = T&;
  190. using const_reference = const T&;
  191. using iterator = pointer;
  192. using const_iterator = const_pointer;
  193. using size_type = size_t;
  194. using difference_type = ptrdiff_t;
  195. using TBucketDivisor = ::NPrivate::THashDivisor;
  196. _yhashtable_buckets(const Alloc& other)
  197. : base_type(other)
  198. , Data(nullptr)
  199. , Size()
  200. {
  201. }
  202. ~_yhashtable_buckets() {
  203. Y_ASSERT(!Data);
  204. }
  205. void initialize_dynamic(TBucketDivisor size) {
  206. Y_ASSERT(!Data);
  207. Data = this->_get_alloc().allocate(size() + 2) + 1;
  208. Size = size;
  209. *reinterpret_cast<size_type*>(Data - 1) = size() + 2;
  210. }
  211. void deinitialize_dynamic() {
  212. Y_ASSERT(Data);
  213. this->_get_alloc().deallocate(Data - 1, *reinterpret_cast<size_type*>(Data - 1));
  214. Data = pointer();
  215. Size = TBucketDivisor();
  216. }
  217. void initialize_static(pointer data, TBucketDivisor size) {
  218. Y_ASSERT(!Data && data && size() >= 1);
  219. Data = data;
  220. Size = size;
  221. }
  222. void deinitialize_static() {
  223. Y_ASSERT(Data);
  224. Data = pointer();
  225. Size = TBucketDivisor();
  226. }
  227. void resize_noallocate(TBucketDivisor size) {
  228. Y_ASSERT(size() <= capacity());
  229. Size = size;
  230. }
  231. iterator begin() {
  232. return Data;
  233. }
  234. const_iterator begin() const {
  235. return Data;
  236. }
  237. iterator end() {
  238. return Data + Size();
  239. }
  240. const_iterator end() const {
  241. return Data + Size();
  242. }
  243. pointer data() {
  244. return Data;
  245. }
  246. const_pointer data() const {
  247. return Data;
  248. }
  249. size_type size() const {
  250. return Size();
  251. }
  252. size_type capacity() const {
  253. return *reinterpret_cast<size_type*>(Data - 1);
  254. }
  255. TBucketDivisor ExtSize() const {
  256. return Size;
  257. }
  258. int BucketDivisorHint() const {
  259. return +Size.Hint;
  260. }
  261. allocator_type get_allocator() const {
  262. return this->_get_alloc();
  263. }
  264. const_reference operator[](size_type index) const {
  265. Y_ASSERT(index <= Size());
  266. return *(Data + index);
  267. }
  268. reference operator[](size_type index) {
  269. Y_ASSERT(index <= Size());
  270. return *(Data + index);
  271. }
  272. void swap(_yhashtable_buckets& other) {
  273. base_type::swap(other);
  274. DoSwap(Data, other.Data);
  275. DoSwap(Size, other.Size);
  276. }
  277. private:
  278. /** Pointer to the first element of the buckets array. */
  279. pointer Data;
  280. /** Size of the buckets array. Doesn't take the marker element at the end into account. */
  281. TBucketDivisor Size;
  282. };
  283. /**
  284. * This class saves one word in THashTable for the most common use case of empty
  285. * functors. The exact implementation picks a specialization with storage allocated
  286. * for the functors if those are non-empty, and another specialization that creates
  287. * functors on the fly if they are empty. It is expected that empty functors have
  288. * trivial constructors.
  289. *
  290. * Note that this is basically the only way to do it portably. Another option is
  291. * multiple inheritance from empty functors, but MSVC's empty base class
  292. * optimization chokes up on multiple empty bases, and we're already using
  293. * EBCO in _allocator_base.
  294. *
  295. * Note that there are no specializations for the case when only one or two
  296. * of the functors are empty as this is a case that's just way too rare.
  297. */
  298. template <class HashFcn, class ExtractKey, class EqualKey, class Alloc, bool IsEmpty = std::is_empty<HashFcn>::value && std::is_empty<ExtractKey>::value && std::is_empty<EqualKey>::value>
  299. class _yhashtable_base: public _allocator_base<Alloc> {
  300. using base_type = _allocator_base<Alloc>;
  301. public:
  302. _yhashtable_base(const HashFcn& hash, const ExtractKey& extract, const EqualKey& equals, const Alloc& alloc)
  303. : base_type(alloc)
  304. , hash_(hash)
  305. , extract_(extract)
  306. , equals_(equals)
  307. {
  308. }
  309. const EqualKey& _get_key_eq() const {
  310. return equals_;
  311. }
  312. EqualKey& _get_key_eq() {
  313. return equals_;
  314. }
  315. void _set_key_eq(const EqualKey& equals) {
  316. this->equals_ = equals;
  317. }
  318. const ExtractKey& _get_key_extract() const {
  319. return extract_;
  320. }
  321. ExtractKey& _get_key_extract() {
  322. return extract_;
  323. }
  324. void _set_key_extract(const ExtractKey& extract) {
  325. this->extract_ = extract;
  326. }
  327. const HashFcn& _get_hash_fun() const {
  328. return hash_;
  329. }
  330. HashFcn& _get_hash_fun() {
  331. return hash_;
  332. }
  333. void _set_hash_fun(const HashFcn& hash) {
  334. this->hash_ = hash;
  335. }
  336. void swap(_yhashtable_base& other) {
  337. base_type::swap(other);
  338. DoSwap(equals_, other.equals_);
  339. DoSwap(extract_, other.extract_);
  340. DoSwap(hash_, other.hash_);
  341. }
  342. private:
  343. HashFcn hash_;
  344. ExtractKey extract_;
  345. EqualKey equals_;
  346. };
  347. template <class HashFcn, class ExtractKey, class EqualKey, class Alloc>
  348. class _yhashtable_base<HashFcn, ExtractKey, EqualKey, Alloc, true>: public _allocator_base<Alloc> {
  349. using base_type = _allocator_base<Alloc>;
  350. public:
  351. _yhashtable_base(const HashFcn&, const ExtractKey&, const EqualKey&, const Alloc& alloc)
  352. : base_type(alloc)
  353. {
  354. }
  355. EqualKey _get_key_eq() const {
  356. return EqualKey();
  357. }
  358. void _set_key_eq(const EqualKey&) {
  359. }
  360. ExtractKey _get_key_extract() const {
  361. return ExtractKey();
  362. }
  363. void _set_key_extract(const ExtractKey&) {
  364. }
  365. HashFcn _get_hash_fun() const {
  366. return HashFcn();
  367. }
  368. void _set_hash_fun(const HashFcn&) {
  369. }
  370. void swap(_yhashtable_base& other) {
  371. base_type::swap(other);
  372. }
  373. };
  374. template <class Value, class Key, class HashFcn, class ExtractKey, class EqualKey, class Alloc>
  375. struct _yhashtable_traits {
  376. using node = __yhashtable_node<Value>;
  377. using node_allocator_type = TReboundAllocator<Alloc, node>;
  378. using nodep_allocator_type = TReboundAllocator<Alloc, node*>;
  379. using base_type = _yhashtable_base<HashFcn, ExtractKey, EqualKey, node_allocator_type>;
  380. };
  381. extern const void* const _yhashtable_empty_data[];
  382. template <class Value, class Key, class HashFcn, class ExtractKey, class EqualKey, class Alloc>
  383. class THashTable: private _yhashtable_traits<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>::base_type {
  384. using traits_type = _yhashtable_traits<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>;
  385. using base_type = typename traits_type::base_type;
  386. using node = typename traits_type::node;
  387. using nodep_allocator_type = typename traits_type::nodep_allocator_type;
  388. using buckets_type = _yhashtable_buckets<node*, nodep_allocator_type>;
  389. using TBucketDivisor = ::NPrivate::THashDivisor;
  390. public:
  391. using key_type = Key;
  392. using value_type = Value;
  393. using hasher = HashFcn;
  394. using key_equal = EqualKey;
  395. using key_extract = ExtractKey;
  396. using allocator_type = Alloc;
  397. using node_allocator_type = typename traits_type::node_allocator_type;
  398. using size_type = size_t;
  399. using difference_type = ptrdiff_t;
  400. using pointer = value_type*;
  401. using const_pointer = const value_type*;
  402. using reference = value_type&;
  403. using const_reference = const value_type&;
  404. node_allocator_type& GetNodeAllocator() {
  405. return this->_get_alloc();
  406. }
  407. const node_allocator_type& GetNodeAllocator() const {
  408. return this->_get_alloc();
  409. }
  410. key_equal key_eq() const {
  411. return this->_get_key_eq();
  412. }
  413. hasher hash_function() const {
  414. return this->_get_hash_fun();
  415. }
  416. private:
  417. template <class KeyL, class KeyR>
  418. bool equals(const KeyL& l, const KeyR& r) const {
  419. return this->_get_key_eq()(l, r);
  420. }
  421. /* This method is templated to postpone instantiation of key extraction functor. */
  422. template <class ValueL>
  423. auto get_key(const ValueL& value) const -> decltype(ExtractKey()(value)) {
  424. return this->_get_key_extract()(value);
  425. }
  426. node* get_node() {
  427. node* result = this->_get_alloc().allocate(1);
  428. Y_ASSERT((reinterpret_cast<uintptr_t>(result) & 1) == 0); /* We're using the last bit of the node pointer. */
  429. return result;
  430. }
  431. void put_node(node* p) {
  432. this->_get_alloc().deallocate(p, 1);
  433. }
  434. buckets_type buckets;
  435. size_type num_elements;
  436. public:
  437. using iterator = __yhashtable_iterator<Value>;
  438. using const_iterator = __yhashtable_const_iterator<Value>;
  439. using insert_ctx = node**;
  440. friend struct __yhashtable_iterator<Value>;
  441. friend struct __yhashtable_const_iterator<Value>;
  442. public:
  443. THashTable()
  444. : base_type(HashFcn(), ExtractKey(), EqualKey(), node_allocator_type())
  445. , buckets(nodep_allocator_type())
  446. , num_elements(0)
  447. {
  448. initialize_buckets(buckets, 0);
  449. }
  450. THashTable(size_type n, const HashFcn& hf, const EqualKey& eql, const ExtractKey& ext)
  451. : base_type(hf, ext, eql, node_allocator_type())
  452. , buckets(nodep_allocator_type())
  453. , num_elements(0)
  454. {
  455. initialize_buckets(buckets, n);
  456. }
  457. THashTable(size_type n, const HashFcn& hf, const EqualKey& eql)
  458. : base_type(hf, ExtractKey(), eql, node_allocator_type())
  459. , buckets(nodep_allocator_type())
  460. , num_elements(0)
  461. {
  462. initialize_buckets(buckets, n);
  463. }
  464. template <class TAllocParam>
  465. THashTable(size_type n, const HashFcn& hf, const EqualKey& eql, TAllocParam* allocParam)
  466. : base_type(hf, ExtractKey(), eql, allocParam)
  467. , buckets(allocParam)
  468. , num_elements(0)
  469. {
  470. initialize_buckets(buckets, n);
  471. }
  472. THashTable(const THashTable& ht)
  473. : base_type(ht._get_hash_fun(), ht._get_key_extract(), ht._get_key_eq(), ht._get_alloc())
  474. , buckets(ht.buckets.get_allocator())
  475. , num_elements(0)
  476. {
  477. if (ht.empty()) {
  478. initialize_buckets(buckets, 0);
  479. } else {
  480. initialize_buckets_dynamic(buckets, ht.buckets.ExtSize());
  481. copy_from_dynamic(ht);
  482. }
  483. }
  484. THashTable(THashTable&& ht) noexcept
  485. : base_type(ht._get_hash_fun(), ht._get_key_extract(), ht._get_key_eq(), ht._get_alloc())
  486. , buckets(ht.buckets.get_allocator())
  487. , num_elements(0)
  488. {
  489. initialize_buckets(buckets, 0);
  490. this->swap(ht);
  491. }
  492. THashTable& operator=(const THashTable& ht) {
  493. if (&ht != this) {
  494. basic_clear();
  495. this->_set_hash_fun(ht._get_hash_fun());
  496. this->_set_key_eq(ht._get_key_eq());
  497. this->_set_key_extract(ht._get_key_extract());
  498. /* We don't copy allocator for a reason. */
  499. if (ht.empty()) {
  500. /* Some of the old code in Arcadia works around the behavior in
  501. * clear() by invoking operator= with empty hash as an argument.
  502. * It's expected that this will deallocate the buckets array, so
  503. * this is what we have to do here. */
  504. deinitialize_buckets(buckets);
  505. initialize_buckets(buckets, 0);
  506. } else {
  507. if (buckets.capacity() > ht.buckets.size()) {
  508. buckets.resize_noallocate(ht.buckets.ExtSize());
  509. } else {
  510. deinitialize_buckets(buckets);
  511. initialize_buckets_dynamic(buckets, ht.buckets.ExtSize());
  512. }
  513. copy_from_dynamic(ht);
  514. }
  515. }
  516. return *this;
  517. }
  518. THashTable& operator=(THashTable&& ht) noexcept {
  519. basic_clear();
  520. swap(ht);
  521. return *this;
  522. }
  523. ~THashTable() {
  524. basic_clear();
  525. deinitialize_buckets(buckets);
  526. }
  527. size_type size() const noexcept {
  528. return num_elements;
  529. }
  530. size_type max_size() const noexcept {
  531. return size_type(-1);
  532. }
  533. Y_PURE_FUNCTION bool empty() const noexcept {
  534. return size() == 0;
  535. }
  536. void swap(THashTable& ht) {
  537. base_type::swap(ht);
  538. buckets.swap(ht.buckets);
  539. DoSwap(num_elements, ht.num_elements);
  540. }
  541. iterator begin() {
  542. for (size_type n = 0; n < buckets.size(); ++n) { /*y*/
  543. if (buckets[n]) {
  544. return iterator(buckets[n]); /*y*/
  545. }
  546. }
  547. return end();
  548. }
  549. iterator end() {
  550. return iterator(nullptr);
  551. } /*y*/
  552. const_iterator begin() const {
  553. for (size_type n = 0; n < buckets.size(); ++n) { /*y*/
  554. if (buckets[n]) {
  555. return const_iterator(buckets[n]); /*y*/
  556. }
  557. }
  558. return end();
  559. }
  560. const_iterator end() const {
  561. return const_iterator(nullptr);
  562. } /*y*/
  563. public:
  564. size_type bucket_count() const {
  565. return buckets.size();
  566. } /*y*/
  567. size_type bucket_size(size_type bucket) const {
  568. size_type result = 0;
  569. if (const node* cur = buckets[bucket]) {
  570. for (; !((uintptr_t)cur & 1); cur = cur->next) {
  571. result += 1;
  572. }
  573. }
  574. return result;
  575. }
  576. template <class OtherValue>
  577. std::pair<iterator, bool> insert_unique(const OtherValue& obj) {
  578. reserve(num_elements + 1);
  579. return insert_unique_noresize(obj);
  580. }
  581. template <class OtherValue>
  582. iterator insert_equal(const OtherValue& obj) {
  583. reserve(num_elements + 1);
  584. return emplace_equal_noresize(obj);
  585. }
  586. template <typename... Args>
  587. iterator emplace_equal(Args&&... args) {
  588. reserve(num_elements + 1);
  589. return emplace_equal_noresize(std::forward<Args>(args)...);
  590. }
  591. template <class OtherValue>
  592. iterator insert_direct(const OtherValue& obj, insert_ctx ins) {
  593. return emplace_direct(ins, obj);
  594. }
  595. template <typename... Args>
  596. iterator emplace_direct(insert_ctx ins, Args&&... args) {
  597. bool resized = reserve(num_elements + 1);
  598. node* tmp = new_node(std::forward<Args>(args)...);
  599. if (resized) {
  600. find_i(get_key(tmp->val), ins);
  601. }
  602. tmp->next = *ins ? *ins : (node*)((uintptr_t)(ins + 1) | 1);
  603. *ins = tmp;
  604. ++num_elements;
  605. return iterator(tmp);
  606. }
  607. template <typename... Args>
  608. std::pair<iterator, bool> emplace_unique(Args&&... args) {
  609. reserve(num_elements + 1);
  610. return emplace_unique_noresize(std::forward<Args>(args)...);
  611. }
  612. template <typename... Args>
  613. std::pair<iterator, bool> emplace_unique_noresize(Args&&... args);
  614. template <class OtherValue>
  615. std::pair<iterator, bool> insert_unique_noresize(const OtherValue& obj);
  616. template <typename... Args>
  617. iterator emplace_equal_noresize(Args&&... args);
  618. template <class InputIterator>
  619. void insert_unique(InputIterator f, InputIterator l) {
  620. insert_unique(f, l, typename std::iterator_traits<InputIterator>::iterator_category());
  621. }
  622. template <class InputIterator>
  623. void insert_equal(InputIterator f, InputIterator l) {
  624. insert_equal(f, l, typename std::iterator_traits<InputIterator>::iterator_category());
  625. }
  626. template <class InputIterator>
  627. void insert_unique(InputIterator f, InputIterator l, std::input_iterator_tag) {
  628. for (; f != l; ++f) {
  629. insert_unique(*f);
  630. }
  631. }
  632. template <class InputIterator>
  633. void insert_equal(InputIterator f, InputIterator l, std::input_iterator_tag) {
  634. for (; f != l; ++f) {
  635. insert_equal(*f);
  636. }
  637. }
  638. template <class ForwardIterator>
  639. void insert_unique(ForwardIterator f, ForwardIterator l, std::forward_iterator_tag) {
  640. difference_type n = std::distance(f, l);
  641. reserve(num_elements + n);
  642. for (; n > 0; --n, ++f) {
  643. insert_unique_noresize(*f);
  644. }
  645. }
  646. template <class ForwardIterator>
  647. void insert_equal(ForwardIterator f, ForwardIterator l, std::forward_iterator_tag) {
  648. difference_type n = std::distance(f, l);
  649. reserve(num_elements + n);
  650. for (; n > 0; --n, ++f) {
  651. emplace_equal_noresize(*f);
  652. }
  653. }
  654. template <class OtherValue>
  655. reference find_or_insert(const OtherValue& v);
  656. template <class OtherKey>
  657. iterator find(const OtherKey& key) {
  658. size_type n = bkt_num_key(key);
  659. node* first;
  660. for (first = buckets[n];
  661. first && !equals(get_key(first->val), key);
  662. first = ((uintptr_t)first->next & 1) ? nullptr : first->next) /*y*/
  663. {
  664. }
  665. return iterator(first); /*y*/
  666. }
  667. template <class OtherKey>
  668. const_iterator find(const OtherKey& key) const {
  669. size_type n = bkt_num_key(key);
  670. const node* first;
  671. for (first = buckets[n];
  672. first && !equals(get_key(first->val), key);
  673. first = ((uintptr_t)first->next & 1) ? nullptr : first->next) /*y*/
  674. {
  675. }
  676. return const_iterator(first); /*y*/
  677. }
  678. template <class OtherKey>
  679. iterator find_i(const OtherKey& key, insert_ctx& ins);
  680. template <class OtherKey>
  681. size_type count(const OtherKey& key) const {
  682. const size_type n = bkt_num_key(key);
  683. size_type result = 0;
  684. if (const node* cur = buckets[n]) {
  685. for (; !((uintptr_t)cur & 1); cur = cur->next) {
  686. if (equals(get_key(cur->val), key)) {
  687. ++result;
  688. }
  689. }
  690. }
  691. return result;
  692. }
  693. template <class OtherKey>
  694. std::pair<iterator, iterator> equal_range(const OtherKey& key);
  695. template <class OtherKey>
  696. std::pair<const_iterator, const_iterator> equal_range(const OtherKey& key) const;
  697. template <class OtherKey>
  698. std::pair<iterator, iterator> equal_range_i(const OtherKey& key, insert_ctx& ins);
  699. template <class OtherKey>
  700. size_type erase(const OtherKey& key);
  701. template <class OtherKey>
  702. size_type erase_one(const OtherKey& key);
  703. // void (instead of iterator) is intended, see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2023.pdf
  704. void erase(const iterator& it);
  705. void erase(iterator first, iterator last);
  706. void erase(const const_iterator& it);
  707. void erase(const_iterator first, const_iterator last);
  708. bool reserve(size_type num_elements_hint);
  709. Y_REINITIALIZES_OBJECT void basic_clear();
  710. /**
  711. * Clears the hashtable without deallocating the nodes.
  712. *
  713. * This might come in handy with non-standard allocators, e.g. a pool
  714. * allocator with a pool that is then cleared manually, thus releasing all
  715. * the nodes at once.
  716. */
  717. void release_nodes() {
  718. if (empty()) {
  719. return; /* Need this check because empty buckets may reside in read-only memory. */
  720. }
  721. clear_buckets(buckets);
  722. num_elements = 0;
  723. }
  724. // implemented in save_stl.h
  725. template <class KeySaver>
  726. int save_for_st(IOutputStream* stream, KeySaver& ks, sthash<int, int, THash<int>, TEqualTo<int>, typename KeySaver::TSizeType>* stHash = nullptr) const;
  727. Y_REINITIALIZES_OBJECT void clear(size_type downsize) {
  728. basic_clear();
  729. if (downsize < buckets.size()) {
  730. const TBucketDivisor newSize = HashBucketCountExt(downsize);
  731. if (newSize() < buckets.size()) {
  732. Y_ASSERT(newSize() >= 7); /* We cannot downsize static buckets. */
  733. buckets.resize_noallocate(newSize);
  734. }
  735. }
  736. }
  737. /**
  738. * Clears the hashtable and tries to reasonably downsize it. Note that
  739. * downsizing is mainly for the following use case:
  740. *
  741. * THashTable hash;
  742. * for(...) {
  743. * if (someCond())
  744. * hash.clear();
  745. * hash.insert(...);
  746. * }
  747. *
  748. * Here if at some point `hash` gets really big, then all the following calls
  749. * to `clear` become really slow as they have to iterate through all the the
  750. * empty buckets. This is worked around by squeezing the buckets array a little
  751. * bit with every `clear` call.
  752. *
  753. * Alternatively, the user can call `basic_clear`, which doesn't do the
  754. * downsizing.
  755. */
  756. Y_REINITIALIZES_OBJECT void clear() {
  757. if (num_elements) {
  758. clear((num_elements * 2 + buckets.size()) / 3);
  759. }
  760. }
  761. private:
  762. static void initialize_buckets(buckets_type& buckets, size_type sizeHint) {
  763. if (sizeHint == 0) {
  764. buckets.initialize_static(reinterpret_cast<node**>(const_cast<void**>(_yhashtable_empty_data)) + 1, TBucketDivisor::One());
  765. } else {
  766. TBucketDivisor size = HashBucketCountExt(sizeHint);
  767. Y_ASSERT(size() >= 7);
  768. initialize_buckets_dynamic(buckets, size);
  769. }
  770. }
  771. static void initialize_buckets_dynamic(buckets_type& buckets, TBucketDivisor size) {
  772. buckets.initialize_dynamic(size);
  773. memset(buckets.data(), 0, size() * sizeof(*buckets.data()));
  774. buckets[size()] = (node*)1;
  775. }
  776. static void deinitialize_buckets(buckets_type& buckets) {
  777. if (buckets.size() == 1) {
  778. buckets.deinitialize_static();
  779. } else {
  780. buckets.deinitialize_dynamic();
  781. }
  782. }
  783. static void clear_buckets(buckets_type& buckets) {
  784. memset(buckets.data(), 0, buckets.size() * sizeof(*buckets.data()));
  785. }
  786. template <class OtherKey>
  787. size_type bkt_num_key(const OtherKey& key) const {
  788. return bkt_num_key(key, buckets.ExtSize());
  789. }
  790. template <class OtherValue>
  791. size_type bkt_num(const OtherValue& obj) const {
  792. return bkt_num_key(get_key(obj));
  793. }
  794. template <class OtherKey>
  795. size_type bkt_num_key(const OtherKey& key, TBucketDivisor n) const {
  796. const size_type bucket = n.Remainder(this->_get_hash_fun()(key));
  797. Y_ASSERT((0 <= bucket) && (bucket < n()));
  798. return bucket;
  799. }
  800. template <class OtherValue>
  801. size_type bkt_num(const OtherValue& obj, TBucketDivisor n) const {
  802. return bkt_num_key(get_key(obj), n);
  803. }
  804. template <typename... Args>
  805. node* new_node(Args&&... val) {
  806. node* n = get_node();
  807. n->next = (node*)1; /*y*/ // just for a case
  808. try {
  809. new (static_cast<void*>(&n->val)) Value(std::forward<Args>(val)...);
  810. } catch (...) {
  811. put_node(n);
  812. throw;
  813. }
  814. return n;
  815. }
  816. void delete_node(node* n) {
  817. n->val.~Value();
  818. // n->next = (node*) 0xDeadBeeful;
  819. put_node(n);
  820. }
  821. void erase_bucket(const size_type n, node* first, node* last);
  822. void erase_bucket(const size_type n, node* last);
  823. void copy_from_dynamic(const THashTable& ht);
  824. };
  825. template <class V>
  826. __yhashtable_iterator<V>& __yhashtable_iterator<V>::operator++() {
  827. Y_ASSERT(cur);
  828. cur = cur->next;
  829. if ((uintptr_t)cur & 1) {
  830. node** bucket = (node**)((uintptr_t)cur & ~1);
  831. while (*bucket == nullptr) {
  832. ++bucket;
  833. }
  834. Y_ASSERT(*bucket != nullptr);
  835. cur = (node*)((uintptr_t)*bucket & ~1);
  836. }
  837. return *this;
  838. }
  839. template <class V>
  840. inline __yhashtable_iterator<V> __yhashtable_iterator<V>::operator++(int) {
  841. iterator tmp = *this;
  842. ++*this;
  843. return tmp;
  844. }
  845. template <class V>
  846. __yhashtable_const_iterator<V>& __yhashtable_const_iterator<V>::operator++() {
  847. Y_ASSERT(cur);
  848. cur = cur->next;
  849. if ((uintptr_t)cur & 1) {
  850. node** bucket = (node**)((uintptr_t)cur & ~1);
  851. while (*bucket == nullptr) {
  852. ++bucket;
  853. }
  854. Y_ASSERT(*bucket != nullptr);
  855. cur = (node*)((uintptr_t)*bucket & ~1);
  856. }
  857. return *this;
  858. }
  859. template <class V>
  860. inline __yhashtable_const_iterator<V> __yhashtable_const_iterator<V>::operator++(int) {
  861. const_iterator tmp = *this;
  862. ++*this;
  863. return tmp;
  864. }
  865. template <class V, class K, class HF, class Ex, class Eq, class A>
  866. template <typename... Args>
  867. std::pair<typename THashTable<V, K, HF, Ex, Eq, A>::iterator, bool> THashTable<V, K, HF, Ex, Eq, A>::emplace_unique_noresize(Args&&... args) {
  868. auto deleter = [&](node* tmp) { delete_node(tmp); };
  869. node* tmp = new_node(std::forward<Args>(args)...);
  870. std::unique_ptr<node, decltype(deleter)> guard(tmp, deleter);
  871. const size_type n = bkt_num(tmp->val);
  872. node* first = buckets[n];
  873. if (first) { /*y*/
  874. for (node* cur = first; !((uintptr_t)cur & 1); cur = cur->next) { /*y*/
  875. if (equals(get_key(cur->val), get_key(tmp->val))) {
  876. return std::pair<iterator, bool>(iterator(cur), false); /*y*/
  877. }
  878. }
  879. }
  880. guard.release();
  881. tmp->next = first ? first : (node*)((uintptr_t)&buckets[n + 1] | 1); /*y*/
  882. buckets[n] = tmp;
  883. ++num_elements;
  884. return std::pair<iterator, bool>(iterator(tmp), true); /*y*/
  885. }
  886. template <class V, class K, class HF, class Ex, class Eq, class A>
  887. template <class OtherValue>
  888. std::pair<typename THashTable<V, K, HF, Ex, Eq, A>::iterator, bool> THashTable<V, K, HF, Ex, Eq, A>::insert_unique_noresize(const OtherValue& obj) {
  889. const size_type n = bkt_num(obj);
  890. node* first = buckets[n];
  891. if (first) { /*y*/
  892. for (node* cur = first; !((uintptr_t)cur & 1); cur = cur->next) { /*y*/
  893. if (equals(get_key(cur->val), get_key(obj))) {
  894. return std::pair<iterator, bool>(iterator(cur), false); /*y*/
  895. }
  896. }
  897. }
  898. node* tmp = new_node(obj);
  899. tmp->next = first ? first : (node*)((uintptr_t)&buckets[n + 1] | 1); /*y*/
  900. buckets[n] = tmp;
  901. ++num_elements;
  902. return std::pair<iterator, bool>(iterator(tmp), true); /*y*/
  903. }
  904. template <class V, class K, class HF, class Ex, class Eq, class A>
  905. template <typename... Args>
  906. __yhashtable_iterator<V> THashTable<V, K, HF, Ex, Eq, A>::emplace_equal_noresize(Args&&... args) {
  907. auto deleter = [&](node* tmp) { delete_node(tmp); };
  908. node* tmp = new_node(std::forward<Args>(args)...);
  909. std::unique_ptr<node, decltype(deleter)> guard(tmp, deleter);
  910. const size_type n = bkt_num(tmp->val);
  911. node* first = buckets[n];
  912. if (first) { /*y*/
  913. for (node* cur = first; !((uintptr_t)cur & 1); cur = cur->next) { /*y*/
  914. if (equals(get_key(cur->val), get_key(tmp->val))) {
  915. guard.release();
  916. tmp->next = cur->next;
  917. cur->next = tmp;
  918. ++num_elements;
  919. return iterator(tmp); /*y*/
  920. }
  921. }
  922. }
  923. guard.release();
  924. tmp->next = first ? first : (node*)((uintptr_t)&buckets[n + 1] | 1); /*y*/
  925. buckets[n] = tmp;
  926. ++num_elements;
  927. return iterator(tmp); /*y*/
  928. }
  929. template <class V, class K, class HF, class Ex, class Eq, class A>
  930. template <class OtherValue>
  931. typename THashTable<V, K, HF, Ex, Eq, A>::reference THashTable<V, K, HF, Ex, Eq, A>::find_or_insert(const OtherValue& v) {
  932. reserve(num_elements + 1);
  933. size_type n = bkt_num_key(get_key(v));
  934. node* first = buckets[n];
  935. if (first) { /*y*/
  936. for (node* cur = first; !((uintptr_t)cur & 1); cur = cur->next) { /*y*/
  937. if (equals(get_key(cur->val), get_key(v))) {
  938. return cur->val;
  939. }
  940. }
  941. }
  942. node* tmp = new_node(v);
  943. tmp->next = first ? first : (node*)((uintptr_t)&buckets[n + 1] | 1); /*y*/
  944. buckets[n] = tmp;
  945. ++num_elements;
  946. return tmp->val;
  947. }
  948. template <class V, class K, class HF, class Ex, class Eq, class A>
  949. template <class OtherKey>
  950. __yhashtable_iterator<V> THashTable<V, K, HF, Ex, Eq, A>::find_i(const OtherKey& key, insert_ctx& ins) {
  951. size_type n = bkt_num_key(key);
  952. ins = &buckets[n];
  953. node* first = buckets[n];
  954. if (first) { /*y*/
  955. for (node* cur = first; !((uintptr_t)cur & 1); cur = cur->next) { /*y*/
  956. if (equals(get_key(cur->val), key)) {
  957. return iterator(cur); /*y*/
  958. }
  959. }
  960. }
  961. return end();
  962. }
  963. template <class V, class K, class HF, class Ex, class Eq, class A>
  964. template <class OtherKey>
  965. std::pair<__yhashtable_iterator<V>, __yhashtable_iterator<V>> THashTable<V, K, HF, Ex, Eq, A>::equal_range(const OtherKey& key) {
  966. insert_ctx ctx;
  967. return equal_range_i(key, ctx);
  968. }
  969. template <class V, class K, class HF, class Ex, class Eq, class A>
  970. template <class OtherKey>
  971. std::pair<__yhashtable_iterator<V>, __yhashtable_iterator<V>> THashTable<V, K, HF, Ex, Eq, A>::equal_range_i(const OtherKey& key, insert_ctx& ins) {
  972. using pii = std::pair<iterator, iterator>;
  973. const size_type n = bkt_num_key(key);
  974. ins = &buckets[n];
  975. node* first = buckets[n];
  976. if (first) { /*y*/
  977. for (; !((uintptr_t)first & 1); first = first->next) { /*y*/
  978. if (equals(get_key(first->val), key)) {
  979. for (node* cur = first->next; !((uintptr_t)cur & 1); cur = cur->next) {
  980. if (!equals(get_key(cur->val), key)) {
  981. return pii(iterator(first), iterator(cur)); /*y*/
  982. }
  983. }
  984. for (size_type m = n + 1; m < buckets.size(); ++m) { /*y*/
  985. if (buckets[m]) {
  986. return pii(iterator(first), /*y*/
  987. iterator(buckets[m])); /*y*/
  988. }
  989. }
  990. return pii(iterator(first), end()); /*y*/
  991. }
  992. }
  993. }
  994. return pii(end(), end());
  995. }
  996. template <class V, class K, class HF, class Ex, class Eq, class A>
  997. template <class OtherKey>
  998. std::pair<__yhashtable_const_iterator<V>, __yhashtable_const_iterator<V>> THashTable<V, K, HF, Ex, Eq, A>::equal_range(const OtherKey& key) const {
  999. using pii = std::pair<const_iterator, const_iterator>;
  1000. const size_type n = bkt_num_key(key);
  1001. const node* first = buckets[n];
  1002. if (first) { /*y*/
  1003. for (; !((uintptr_t)first & 1); first = first->next) { /*y*/
  1004. if (equals(get_key(first->val), key)) {
  1005. for (const node* cur = first->next; !((uintptr_t)cur & 1); cur = cur->next) {
  1006. if (!equals(get_key(cur->val), key)) {
  1007. return pii(const_iterator(first), /*y*/
  1008. const_iterator(cur)); /*y*/
  1009. }
  1010. }
  1011. for (size_type m = n + 1; m < buckets.size(); ++m) { /*y*/
  1012. if (buckets[m]) {
  1013. return pii(const_iterator(first /*y*/),
  1014. const_iterator(buckets[m] /*y*/));
  1015. }
  1016. }
  1017. return pii(const_iterator(first /*y*/), end());
  1018. }
  1019. }
  1020. }
  1021. return pii(end(), end());
  1022. }
  1023. template <class V, class K, class HF, class Ex, class Eq, class A>
  1024. template <class OtherKey>
  1025. typename THashTable<V, K, HF, Ex, Eq, A>::size_type THashTable<V, K, HF, Ex, Eq, A>::erase(const OtherKey& key) {
  1026. const size_type n = bkt_num_key(key);
  1027. node* first = buckets[n];
  1028. size_type erased = 0;
  1029. if (first) {
  1030. node* cur = first;
  1031. node* next = cur->next;
  1032. while (!((uintptr_t)next & 1)) { /*y*/
  1033. if (equals(get_key(next->val), key)) {
  1034. cur->next = next->next;
  1035. ++erased;
  1036. --num_elements;
  1037. delete_node(next);
  1038. next = cur->next;
  1039. } else {
  1040. cur = next;
  1041. next = cur->next;
  1042. }
  1043. }
  1044. if (equals(get_key(first->val), key)) {
  1045. buckets[n] = ((uintptr_t)first->next & 1) ? nullptr : first->next; /*y*/
  1046. ++erased;
  1047. --num_elements;
  1048. delete_node(first);
  1049. }
  1050. }
  1051. return erased;
  1052. }
  1053. template <class V, class K, class HF, class Ex, class Eq, class A>
  1054. template <class OtherKey>
  1055. typename THashTable<V, K, HF, Ex, Eq, A>::size_type THashTable<V, K, HF, Ex, Eq, A>::erase_one(const OtherKey& key) {
  1056. const size_type n = bkt_num_key(key);
  1057. node* first = buckets[n];
  1058. if (first) {
  1059. node* cur = first;
  1060. node* next = cur->next;
  1061. while (!((uintptr_t)next & 1)) { /*y*/
  1062. if (equals(get_key(next->val), key)) {
  1063. cur->next = next->next;
  1064. --num_elements;
  1065. delete_node(next);
  1066. return 1;
  1067. } else {
  1068. cur = next;
  1069. next = cur->next;
  1070. }
  1071. }
  1072. if (equals(get_key(first->val), key)) {
  1073. buckets[n] = ((uintptr_t)first->next & 1) ? nullptr : first->next; /*y*/
  1074. --num_elements;
  1075. delete_node(first);
  1076. return 1;
  1077. }
  1078. }
  1079. return 0;
  1080. }
  1081. template <class V, class K, class HF, class Ex, class Eq, class A>
  1082. void THashTable<V, K, HF, Ex, Eq, A>::erase(const iterator& it) {
  1083. if (node* const p = it.cur) {
  1084. const size_type n = bkt_num(p->val);
  1085. node* cur = buckets[n];
  1086. if (cur == p) {
  1087. buckets[n] = ((uintptr_t)cur->next & 1) ? nullptr : cur->next; /*y*/
  1088. delete_node(cur);
  1089. --num_elements;
  1090. } else {
  1091. node* next = cur->next;
  1092. while (!((uintptr_t)next & 1)) {
  1093. if (next == p) {
  1094. cur->next = next->next;
  1095. delete_node(next);
  1096. --num_elements;
  1097. break;
  1098. } else {
  1099. cur = next;
  1100. next = cur->next;
  1101. }
  1102. }
  1103. }
  1104. }
  1105. }
  1106. template <class V, class K, class HF, class Ex, class Eq, class A>
  1107. void THashTable<V, K, HF, Ex, Eq, A>::erase(iterator first, iterator last) {
  1108. size_type f_bucket = first.cur ? bkt_num(first.cur->val) : buckets.size(); /*y*/
  1109. size_type l_bucket = last.cur ? bkt_num(last.cur->val) : buckets.size(); /*y*/
  1110. if (first.cur == last.cur) {
  1111. return;
  1112. } else if (f_bucket == l_bucket) {
  1113. erase_bucket(f_bucket, first.cur, last.cur);
  1114. } else {
  1115. erase_bucket(f_bucket, first.cur, nullptr);
  1116. for (size_type n = f_bucket + 1; n < l_bucket; ++n) {
  1117. erase_bucket(n, nullptr);
  1118. }
  1119. if (l_bucket != buckets.size()) { /*y*/
  1120. erase_bucket(l_bucket, last.cur);
  1121. }
  1122. }
  1123. }
  1124. template <class V, class K, class HF, class Ex, class Eq, class A>
  1125. inline void
  1126. THashTable<V, K, HF, Ex, Eq, A>::erase(const_iterator first, const_iterator last) {
  1127. erase(iterator(const_cast<node*>(first.cur)), iterator(const_cast<node*>(last.cur)));
  1128. }
  1129. template <class V, class K, class HF, class Ex, class Eq, class A>
  1130. inline void THashTable<V, K, HF, Ex, Eq, A>::erase(const const_iterator& it) {
  1131. erase(iterator(const_cast<node*>(it.cur)));
  1132. }
  1133. template <class V, class K, class HF, class Ex, class Eq, class A>
  1134. bool THashTable<V, K, HF, Ex, Eq, A>::reserve(size_type num_elements_hint) {
  1135. const size_type old_n = buckets.size(); /*y*/
  1136. if (num_elements_hint + 1 > old_n) {
  1137. if (old_n != 1 && num_elements_hint <= old_n) { // TODO: this if is for backwards compatibility down to order-in-buckets level. Can be safely removed.
  1138. return false;
  1139. }
  1140. const TBucketDivisor n = HashBucketCountExt(num_elements_hint + 1, buckets.BucketDivisorHint() + 1);
  1141. if (n() > old_n) {
  1142. buckets_type tmp(buckets.get_allocator());
  1143. initialize_buckets_dynamic(tmp, n);
  1144. #ifdef __STL_USE_EXCEPTIONS
  1145. try {
  1146. #endif /* __STL_USE_EXCEPTIONS */
  1147. for (size_type bucket = 0; bucket < old_n; ++bucket) {
  1148. node* first = buckets[bucket];
  1149. while (first) {
  1150. size_type new_bucket = bkt_num(first->val, n);
  1151. node* next = first->next;
  1152. buckets[bucket] = ((uintptr_t)next & 1) ? nullptr : next; /*y*/
  1153. next = tmp[new_bucket];
  1154. first->next = next ? next : (node*)((uintptr_t) & (tmp[new_bucket + 1]) | 1); /*y*/
  1155. tmp[new_bucket] = first;
  1156. first = buckets[bucket];
  1157. }
  1158. }
  1159. buckets.swap(tmp);
  1160. deinitialize_buckets(tmp);
  1161. return true;
  1162. #ifdef __STL_USE_EXCEPTIONS
  1163. } catch (...) {
  1164. for (size_type bucket = 0; bucket < tmp.size() - 1; ++bucket) {
  1165. while (tmp[bucket]) {
  1166. node* next = tmp[bucket]->next;
  1167. delete_node(tmp[bucket]);
  1168. tmp[bucket] = ((uintptr_t)next & 1) ? nullptr : next /*y*/;
  1169. }
  1170. }
  1171. throw;
  1172. }
  1173. #endif /* __STL_USE_EXCEPTIONS */
  1174. }
  1175. }
  1176. return false;
  1177. }
  1178. template <class V, class K, class HF, class Ex, class Eq, class A>
  1179. void THashTable<V, K, HF, Ex, Eq, A>::erase_bucket(const size_type n, node* first, node* last) {
  1180. node* cur = buckets[n];
  1181. if (cur == first) {
  1182. erase_bucket(n, last);
  1183. } else {
  1184. node* next;
  1185. for (next = cur->next; next != first; cur = next, next = cur->next)
  1186. ;
  1187. while (next != last) { /*y; 3.1*/
  1188. cur->next = next->next;
  1189. delete_node(next);
  1190. next = ((uintptr_t)cur->next & 1) ? nullptr : cur->next; /*y*/
  1191. --num_elements;
  1192. }
  1193. }
  1194. }
  1195. template <class V, class K, class HF, class Ex, class Eq, class A>
  1196. void THashTable<V, K, HF, Ex, Eq, A>::erase_bucket(const size_type n, node* last) {
  1197. node* cur = buckets[n];
  1198. while (cur != last) {
  1199. node* next = cur->next;
  1200. delete_node(cur);
  1201. cur = ((uintptr_t)next & 1) ? nullptr : next; /*y*/
  1202. buckets[n] = cur;
  1203. --num_elements;
  1204. }
  1205. }
  1206. template <class V, class K, class HF, class Ex, class Eq, class A>
  1207. void THashTable<V, K, HF, Ex, Eq, A>::basic_clear() {
  1208. if (!num_elements) {
  1209. return;
  1210. }
  1211. node** first = buckets.begin();
  1212. node** last = buckets.end();
  1213. for (; first < last; ++first) {
  1214. node* cur = *first;
  1215. if (cur) { /*y*/
  1216. while (!((uintptr_t)cur & 1)) { /*y*/
  1217. node* next = cur->next;
  1218. delete_node(cur);
  1219. cur = next;
  1220. }
  1221. *first = nullptr;
  1222. }
  1223. }
  1224. num_elements = 0;
  1225. }
  1226. template <class V, class K, class HF, class Ex, class Eq, class A>
  1227. void THashTable<V, K, HF, Ex, Eq, A>::copy_from_dynamic(const THashTable& ht) {
  1228. Y_ASSERT(buckets.size() == ht.buckets.size() && !ht.empty());
  1229. #ifdef __STL_USE_EXCEPTIONS
  1230. try {
  1231. #endif /* __STL_USE_EXCEPTIONS */
  1232. for (size_type i = 0; i < ht.buckets.size(); ++i) { /*y*/
  1233. if (const node* cur = ht.buckets[i]) {
  1234. node* copy = new_node(cur->val);
  1235. buckets[i] = copy;
  1236. for (node* next = cur->next; !((uintptr_t)next & 1); cur = next, next = cur->next) {
  1237. copy->next = new_node(next->val);
  1238. copy = copy->next;
  1239. }
  1240. copy->next = (node*)((uintptr_t)&buckets[i + 1] | 1); /*y*/
  1241. }
  1242. }
  1243. num_elements = ht.num_elements;
  1244. #ifdef __STL_USE_EXCEPTIONS
  1245. } catch (...) {
  1246. basic_clear();
  1247. throw;
  1248. }
  1249. #endif /* __STL_USE_EXCEPTIONS */
  1250. }
  1251. namespace NPrivate {
  1252. template <class Key>
  1253. inline TString MapKeyToString(const Key&) {
  1254. return TypeName<Key>();
  1255. }
  1256. TString MapKeyToString(TStringBuf key);
  1257. TString MapKeyToString(unsigned short key);
  1258. TString MapKeyToString(short key);
  1259. TString MapKeyToString(unsigned int key);
  1260. TString MapKeyToString(int key);
  1261. TString MapKeyToString(unsigned long key);
  1262. TString MapKeyToString(long key);
  1263. TString MapKeyToString(unsigned long long key);
  1264. TString MapKeyToString(long long key);
  1265. inline TString MapKeyToString(const TString& key) {
  1266. return MapKeyToString(TStringBuf(key));
  1267. }
  1268. inline TString MapKeyToString(const char* key) {
  1269. return MapKeyToString(TStringBuf(key));
  1270. }
  1271. inline TString MapKeyToString(char* key) {
  1272. return MapKeyToString(TStringBuf(key));
  1273. }
  1274. [[noreturn]] void ThrowKeyNotFoundInHashTableException(const TStringBuf keyRepresentation);
  1275. } // namespace NPrivate
  1276. // Cannot name it just 'Hash' because it clashes with too many class members in the code.
  1277. template <class T>
  1278. size_t ComputeHash(const T& value) {
  1279. return THash<T>{}(value);
  1280. }