BaseDictionary.h 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. //////////////////////////////////////////////////////////////////////////
  7. // Template implementation of dictionary based on .NET BCL implementation.
  8. //
  9. // Buckets and entries are allocated as contiguous arrays to maintain good locality of reference.
  10. //
  11. // COLLISION STRATEGY
  12. // This dictionary uses a chaining collision resolution strategy. Chains are implemented using indexes to the 'buckets' array.
  13. //
  14. // STORAGE (TAllocator)
  15. // This dictionary works for both arena and recycler based allocation using TAllocator template parameter.
  16. // It supports storing of both value and pointer types. Using template specialization, value types (built-in fundamental
  17. // types and structs) are stored as leaf nodes by default.
  18. //
  19. // INITIAL SIZE and BUCKET MAPPING (SizePolicy)
  20. // This can be specified using TSizePolicy template parameter. There are 2 implementations:
  21. // - PrimeSizePolicy (Better distribution): Initial size is a prime number. Mapping to bucket is done using modulus operation (costlier).
  22. // - PowerOf2SizePolicy (faster): Initial size is a power of 2. Mapping to bucket is done by a fast truncating the MSB bits up to the size of the table.
  23. //
  24. // COMPARISONS AND HASHCODE (Comparer)
  25. // Enables custom comparisons for TKey and TValue. For example, for strings we use string comparison instead of comparing pointers.
  26. //
  27. #if PROFILE_DICTIONARY
  28. #include "DictionaryStats.h"
  29. #endif
  30. #pragma warning(push)
  31. #pragma warning(disable:__WARNING_CALLER_FAILING_TO_HOLD_MEDIUM_CONFIDENCE)
  32. #pragma warning(disable:__WARNING_FAILING_TO_RELEASE_MEDIUM_CONFIDENCE)
  33. #pragma warning(disable:__WARNING_FAILING_TO_ACQUIRE_MEDIUM_CONFIDENCE)
  34. #pragma warning(disable:__WARNING_RELEASING_UNHELD_LOCK_MEDIUM_CONFIDENCE)
  35. namespace Js
  36. {
  37. template <class TDictionary>
  38. class RemoteDictionary;
  39. }
  40. namespace JsDiag
  41. {
  42. template <class TDictionary>
  43. struct RemoteDictionary;
  44. }
  45. namespace JsUtil
  46. {
  47. class NoResizeLock
  48. {
  49. public:
  50. void BeginResize() {}
  51. void EndResize() {}
  52. };
  53. class AsymetricResizeLock
  54. {
  55. public:
  56. void _Acquires_lock_(cs.cs) BeginResize() { cs.Enter(); }
  57. void _Releases_lock_(cs.cs) EndResize() { cs.Leave(); }
  58. void _Acquires_lock_(cs.cs) LockResize() { cs.Enter(); }
  59. void _Releases_lock_(cs.cs) UnlockResize() { cs.Leave(); }
  60. private:
  61. CriticalSection cs;
  62. };
  63. template <class TKey, class TValue> class SimpleDictionaryEntry;
  64. template <
  65. class TKey,
  66. class TValue,
  67. class TAllocator,
  68. class SizePolicy = PowerOf2SizePolicy,
  69. template <typename ValueOrKey> class Comparer = DefaultComparer,
  70. template <typename K, typename V> class Entry = SimpleDictionaryEntry,
  71. typename Lock = NoResizeLock
  72. >
  73. class BaseDictionary : protected Lock
  74. {
  75. public:
  76. typedef TKey KeyType;
  77. typedef TValue ValueType;
  78. typedef typename AllocatorInfo<TAllocator, TValue>::AllocatorType AllocatorType;
  79. typedef SizePolicy CurrentSizePolicy;
  80. typedef Entry<
  81. Field(TKey, TAllocator),
  82. Field(TValue, TAllocator)> EntryType;
  83. template<class TDictionary> class EntryIterator;
  84. template<class TDictionary> class BucketEntryIterator;
  85. protected:
  86. typedef typename AllocatorInfo<TAllocator, TValue>::AllocatorFunc EntryAllocatorFuncType;
  87. friend class Js::RemoteDictionary<BaseDictionary>;
  88. template <typename ValueOrKey> struct ComparerType { typedef Comparer<ValueOrKey> Type; }; // Used by diagnostics to access Comparer type
  89. Field(int*, TAllocator) buckets;
  90. Field(EntryType*, TAllocator) entries;
  91. FieldNoBarrier(AllocatorType*) alloc;
  92. Field(int) size;
  93. Field(uint) bucketCount;
  94. Field(int) count;
  95. Field(int) freeList;
  96. Field(int) freeCount;
  97. Field(int) modFunctionIndex;
  98. static const int FreeListSentinel = -2;
  99. #if PROFILE_DICTIONARY
  100. FieldNoBarrier(DictionaryStats*) stats;
  101. #endif
  102. enum InsertOperations
  103. {
  104. Insert_Add , // FatalInternalError if the item already exist in debug build
  105. Insert_AddNew, // Ignore add if the item already exist
  106. Insert_Item // Replace the item if it already exist
  107. };
  108. class AutoDoResize
  109. {
  110. public:
  111. AutoDoResize(Lock& lock) : lock(lock) { this->lock.BeginResize(); };
  112. ~AutoDoResize() { this->lock.EndResize(); };
  113. private:
  114. Lock& lock;
  115. };
  116. public:
  117. BaseDictionary(AllocatorType* allocator, int capacity = 0)
  118. : buckets (nullptr),
  119. size(0),
  120. bucketCount(0),
  121. entries(nullptr),
  122. count(0),
  123. freeCount(0),
  124. alloc(allocator),
  125. modFunctionIndex(UNKNOWN_MOD_INDEX)
  126. {
  127. Assert(allocator);
  128. #if PROFILE_DICTIONARY
  129. stats = nullptr;
  130. #endif
  131. // If initial capacity is negative or 0, lazy initialization on
  132. // the first insert operation is performed.
  133. if (capacity > 0)
  134. {
  135. Initialize(capacity);
  136. }
  137. }
  138. BaseDictionary(const BaseDictionary &other) :
  139. alloc(other.alloc)
  140. {
  141. if(other.Count() == 0)
  142. {
  143. size = 0;
  144. bucketCount = 0;
  145. buckets = nullptr;
  146. entries = nullptr;
  147. count = 0;
  148. freeCount = 0;
  149. modFunctionIndex = UNKNOWN_MOD_INDEX;
  150. #if PROFILE_DICTIONARY
  151. stats = nullptr;
  152. #endif
  153. return;
  154. }
  155. Assert(other.bucketCount != 0);
  156. Assert(other.size != 0);
  157. buckets = AllocateBuckets(other.bucketCount);
  158. Assert(buckets); // no-throw allocators are currently not supported
  159. try
  160. {
  161. entries = AllocateEntries(other.size, false /* zeroAllocate */);
  162. Assert(entries); // no-throw allocators are currently not supported
  163. }
  164. catch(...)
  165. {
  166. DeleteBuckets(buckets, other.bucketCount);
  167. throw;
  168. }
  169. size = other.size;
  170. bucketCount = other.bucketCount;
  171. count = other.count;
  172. freeList = other.freeList;
  173. freeCount = other.freeCount;
  174. modFunctionIndex = other.modFunctionIndex;
  175. CopyArray(buckets, bucketCount, other.buckets, bucketCount);
  176. CopyArray<EntryType, Field(ValueType, TAllocator), TAllocator>(
  177. entries, size, other.entries, size);
  178. #if PROFILE_DICTIONARY
  179. stats = DictionaryStats::Create(typeid(this).name(), size);
  180. #endif
  181. }
  182. ~BaseDictionary()
  183. {
  184. if (buckets)
  185. {
  186. DeleteBuckets(buckets, bucketCount);
  187. }
  188. if (entries)
  189. {
  190. DeleteEntries(entries, size);
  191. }
  192. }
  193. AllocatorType *GetAllocator() const
  194. {
  195. return alloc;
  196. }
  197. inline int Capacity() const
  198. {
  199. return size;
  200. }
  201. inline int Count() const
  202. {
  203. return count - freeCount;
  204. }
  205. TValue Item(const TKey& key)
  206. {
  207. int i = FindEntry(key);
  208. Assert(i >= 0);
  209. return entries[i].Value();
  210. }
  211. TValue Item(const TKey& key) const
  212. {
  213. int i = FindEntry(key);
  214. Assert(i >= 0);
  215. return entries[i].Value();
  216. }
  217. int Add(const TKey& key, const TValue& value)
  218. {
  219. return Insert<Insert_Add>(key, value);
  220. }
  221. // Returns -1 if the key is already in the dictionary
  222. int AddNew(const TKey& key, const TValue& value)
  223. {
  224. return Insert<Insert_AddNew>(key, value);
  225. }
  226. int Item(const TKey& key, const TValue& value)
  227. {
  228. return Insert<Insert_Item>(key, value);
  229. }
  230. bool Contains(KeyValuePair<TKey, TValue> keyValuePair)
  231. {
  232. int i = FindEntry(keyValuePair.Key());
  233. if( i >= 0 && Comparer<TValue>::Equals(entries[i].Value(), keyValuePair.Value()))
  234. {
  235. return true;
  236. }
  237. return false;
  238. }
  239. bool Remove(KeyValuePair<TKey, TValue> keyValuePair)
  240. {
  241. int i, last;
  242. uint targetBucket;
  243. if(FindEntryWithKey(keyValuePair.Key(), &i, &last, &targetBucket))
  244. {
  245. const TValue &value = entries[i].Value();
  246. if(Comparer<TValue>::Equals(value, keyValuePair.Value()))
  247. {
  248. RemoveAt(i, last, targetBucket);
  249. return true;
  250. }
  251. }
  252. return false;
  253. }
  254. void Clear()
  255. {
  256. if (count > 0)
  257. {
  258. memset(buckets, -1, bucketCount * sizeof(buckets[0]));
  259. memset(entries, 0, sizeof(EntryType) * size);
  260. count = 0;
  261. freeCount = 0;
  262. #if PROFILE_DICTIONARY
  263. // To not loose previously collected data, we will treat cleared dictionary as a separate instance for stats tracking purpose
  264. stats = DictionaryStats::Create(typeid(this).name(), size);
  265. #endif
  266. }
  267. }
  268. void ResetNoDelete()
  269. {
  270. this->size = 0;
  271. this->bucketCount = 0;
  272. this->buckets = nullptr;
  273. this->entries = nullptr;
  274. this->count = 0;
  275. this->freeCount = 0;
  276. this->modFunctionIndex = UNKNOWN_MOD_INDEX;
  277. }
  278. void Reset()
  279. {
  280. if(bucketCount != 0)
  281. {
  282. DeleteBuckets(buckets, bucketCount);
  283. buckets = nullptr;
  284. bucketCount = 0;
  285. this->modFunctionIndex = UNKNOWN_MOD_INDEX;
  286. }
  287. else
  288. {
  289. Assert(!buckets);
  290. }
  291. if(size != 0)
  292. {
  293. DeleteEntries(entries, size);
  294. entries = nullptr;
  295. freeCount = count = size = 0;
  296. this->modFunctionIndex = UNKNOWN_MOD_INDEX;
  297. }
  298. else
  299. {
  300. Assert(!entries);
  301. Assert(count == 0);
  302. Assert(freeCount == 0);
  303. }
  304. }
  305. bool ContainsKey(const TKey& key) const
  306. {
  307. return FindEntry(key) >= 0;
  308. }
  309. template <typename TLookup>
  310. inline const TValue& LookupWithKey(const TLookup& key, const TValue& defaultValue) const
  311. {
  312. int i = FindEntryWithKey(key);
  313. if (i >= 0)
  314. {
  315. return entries[i].Value();
  316. }
  317. return defaultValue;
  318. }
  319. inline const TValue& Lookup(const TKey& key, const TValue& defaultValue) const
  320. {
  321. return LookupWithKey<TKey>(key, defaultValue);
  322. }
  323. template <typename TLookup>
  324. bool TryGetValue(const TLookup& key, TValue* value) const
  325. {
  326. int i = FindEntryWithKey(key);
  327. if (i >= 0)
  328. {
  329. *value = entries[i].Value();
  330. return true;
  331. }
  332. return false;
  333. }
  334. bool TryGetValueAndRemove(const TKey& key, TValue* value)
  335. {
  336. int i, last;
  337. uint targetBucket;
  338. if (FindEntryWithKey(key, &i, &last, &targetBucket))
  339. {
  340. *value = entries[i].Value();
  341. RemoveAt(i, last, targetBucket);
  342. return true;
  343. }
  344. return false;
  345. }
  346. template <typename TLookup>
  347. bool TryGetReference(const TLookup& key, const TValue** value) const
  348. {
  349. int i;
  350. return TryGetReference(key, value, &i);
  351. }
  352. template <typename TLookup>
  353. bool TryGetReference(const TLookup& key, TValue** value) const
  354. {
  355. int i;
  356. return TryGetReference(key, value, &i);
  357. }
  358. template <typename TLookup>
  359. bool TryGetReference(const TLookup& key, const TValue** value, int* index) const
  360. {
  361. int i = FindEntryWithKey(key);
  362. if (i >= 0)
  363. {
  364. *value = AddressOf(entries[i].Value());
  365. *index = i;
  366. return true;
  367. }
  368. return false;
  369. }
  370. template <typename TLookup>
  371. bool TryGetReference(const TLookup& key, TValue** value, int* index) const
  372. {
  373. int i = FindEntryWithKey(key);
  374. if (i >= 0)
  375. {
  376. *value = &entries[i].Value();
  377. *index = i;
  378. return true;
  379. }
  380. return false;
  381. }
  382. const TValue& GetValueAt(const int index) const
  383. {
  384. Assert(index >= 0);
  385. Assert(index < count);
  386. return entries[index].Value();
  387. }
  388. TValue* GetReferenceAt(const int index) const
  389. {
  390. Assert(index >= 0);
  391. Assert(index < count);
  392. return &entries[index].Value();
  393. }
  394. TKey const& GetKeyAt(const int index) const
  395. {
  396. Assert(index >= 0);
  397. Assert(index < count);
  398. return entries[index].Key();
  399. }
  400. bool TryGetValueAt(const int index, TValue const ** value) const
  401. {
  402. if (index >= 0 && index < count)
  403. {
  404. *value = &entries[index].Value();
  405. return true;
  406. }
  407. return false;
  408. }
  409. bool TryGetValueAt(int index, TValue * value) const
  410. {
  411. if (index >= 0 && index < count)
  412. {
  413. *value = entries[index].Value();
  414. return true;
  415. }
  416. return false;
  417. }
  418. bool Remove(const TKey& key)
  419. {
  420. int i, last;
  421. uint targetBucket;
  422. if(FindEntryWithKey(key, &i, &last, &targetBucket))
  423. {
  424. RemoveAt(i, last, targetBucket);
  425. return true;
  426. }
  427. return false;
  428. }
  429. EntryIterator<const BaseDictionary> GetIterator() const
  430. {
  431. return EntryIterator<const BaseDictionary>(*this);
  432. }
  433. EntryIterator<BaseDictionary> GetIterator()
  434. {
  435. return EntryIterator<BaseDictionary>(*this);
  436. }
  437. BucketEntryIterator<BaseDictionary> GetIteratorWithRemovalSupport()
  438. {
  439. return BucketEntryIterator<BaseDictionary>(*this);
  440. }
  441. template<class Fn>
  442. bool AnyValue(Fn fn) const
  443. {
  444. for (uint i = 0; i < bucketCount; i++)
  445. {
  446. if(buckets[i] != -1)
  447. {
  448. for (int currentIndex = buckets[i] ; currentIndex != -1 ; currentIndex = entries[currentIndex].next)
  449. {
  450. if (fn(entries[currentIndex].Value()))
  451. {
  452. return true;
  453. }
  454. }
  455. }
  456. }
  457. return false;
  458. }
  459. template<class Fn>
  460. void EachValue(Fn fn) const
  461. {
  462. for (uint i = 0; i < bucketCount; i++)
  463. {
  464. if(buckets[i] != -1)
  465. {
  466. for (int currentIndex = buckets[i] ; currentIndex != -1 ; currentIndex = entries[currentIndex].next)
  467. {
  468. fn(entries[currentIndex].Value());
  469. }
  470. }
  471. }
  472. }
  473. template<class Fn>
  474. void MapReference(Fn fn)
  475. {
  476. MapUntilReference([fn](TKey const& key, TValue& value)
  477. {
  478. fn(key, value);
  479. return false;
  480. });
  481. }
  482. template<class Fn>
  483. bool MapUntilReference(Fn fn) const
  484. {
  485. return MapEntryUntil([fn](EntryType &entry) -> bool
  486. {
  487. return fn(entry.Key(), entry.Value());
  488. });
  489. }
  490. template<class Fn>
  491. void MapAddress(Fn fn) const
  492. {
  493. MapUntilAddress([fn](TKey const& key, TValue * value) -> bool
  494. {
  495. fn(key, value);
  496. return false;
  497. });
  498. }
  499. template<class Fn>
  500. bool MapUntilAddress(Fn fn) const
  501. {
  502. return MapEntryUntil([fn](EntryType &entry) -> bool
  503. {
  504. return fn(entry.Key(), &entry.Value());
  505. });
  506. }
  507. template<class Fn>
  508. void Map(Fn fn) const
  509. {
  510. MapUntil([fn](TKey const& key, TValue const& value) -> bool
  511. {
  512. fn(key, value);
  513. return false;
  514. });
  515. }
  516. template<class Fn>
  517. bool MapUntil(Fn fn) const
  518. {
  519. return MapEntryUntil([fn](EntryType const& entry) -> bool
  520. {
  521. return fn(entry.Key(), entry.Value());
  522. });
  523. }
  524. template<class Fn>
  525. void MapAndRemoveIf(Fn fn)
  526. {
  527. for (uint i = 0; i < bucketCount; i++)
  528. {
  529. if (buckets[i] != -1)
  530. {
  531. for (int currentIndex = buckets[i], lastIndex = -1; currentIndex != -1;)
  532. {
  533. // If the predicate says we should remove this item
  534. if (fn(entries[currentIndex]) == true)
  535. {
  536. const int nextIndex = entries[currentIndex].next;
  537. RemoveAt(currentIndex, lastIndex, i);
  538. currentIndex = nextIndex;
  539. }
  540. else
  541. {
  542. lastIndex = currentIndex;
  543. currentIndex = entries[currentIndex].next;
  544. }
  545. }
  546. }
  547. }
  548. }
  549. template <class Fn>
  550. bool RemoveIf(TKey const& key, Fn fn)
  551. {
  552. return RemoveIfWithKey<TKey>(key, fn);
  553. }
  554. template <typename LookupType, class Fn>
  555. bool RemoveIfWithKey(LookupType const& lookupKey, Fn fn)
  556. {
  557. int i, last;
  558. uint targetBucket;
  559. if (FindEntryWithKey<LookupType>(lookupKey, &i, &last, &targetBucket))
  560. {
  561. if (fn(entries[i].Key(), entries[i].Value()))
  562. {
  563. RemoveAt(i, last, targetBucket);
  564. return true;
  565. }
  566. }
  567. return false;
  568. }
  569. // Returns whether the dictionary was resized or not
  570. bool EnsureCapacity()
  571. {
  572. if (freeCount == 0 && count == size)
  573. {
  574. Resize();
  575. return true;
  576. }
  577. return false;
  578. }
  579. int GetNextIndex()
  580. {
  581. if (freeCount != 0)
  582. {
  583. Assert(freeCount > 0);
  584. Assert(freeList >= 0);
  585. Assert(freeList < count);
  586. return freeList;
  587. }
  588. return count;
  589. }
  590. int GetLastIndex()
  591. {
  592. return count - 1;
  593. }
  594. BaseDictionary *Clone()
  595. {
  596. return AllocatorNew(AllocatorType, alloc, BaseDictionary, *this);
  597. }
  598. void Copy(const BaseDictionary *const other)
  599. {
  600. DoCopy(other);
  601. }
  602. void _Acquires_lock_(this->cs.cs) LockResize()
  603. {
  604. __super::LockResize();
  605. }
  606. void _Releases_lock_(this->cs.cs) UnlockResize()
  607. {
  608. __super::UnlockResize();
  609. }
  610. protected:
  611. template<class T>
  612. void DoCopy(const T *const other)
  613. {
  614. Assert(size == 0);
  615. Assert(bucketCount == 0);
  616. Assert(!buckets);
  617. Assert(!entries);
  618. Assert(count == 0);
  619. Assert(freeCount == 0);
  620. #if PROFILE_DICTIONARY
  621. Assert(!stats);
  622. #endif
  623. if(other->Count() == 0)
  624. {
  625. return;
  626. }
  627. Assert(other->bucketCount != 0);
  628. Assert(other->size != 0);
  629. buckets = AllocateBuckets(other->bucketCount);
  630. Assert(buckets); // no-throw allocators are currently not supported
  631. try
  632. {
  633. entries = AllocateEntries(other->size, false /* zeroAllocate */);
  634. Assert(entries); // no-throw allocators are currently not supported
  635. }
  636. catch(...)
  637. {
  638. DeleteBuckets(buckets, other->bucketCount);
  639. buckets = nullptr;
  640. throw;
  641. }
  642. size = other->size;
  643. bucketCount = other->bucketCount;
  644. count = other->count;
  645. freeList = other->freeList;
  646. freeCount = other->freeCount;
  647. modFunctionIndex = other->modFunctionIndex;
  648. CopyArray(buckets, bucketCount, other->buckets, bucketCount);
  649. CopyArray<EntryType, Field(ValueType, TAllocator), TAllocator>(
  650. entries, size, other->entries, size);
  651. #if PROFILE_DICTIONARY
  652. stats = DictionaryStats::Create(typeid(this).name(), size);
  653. #endif
  654. }
  655. protected:
  656. template<class Fn>
  657. bool MapEntryUntil(Fn fn) const
  658. {
  659. for (uint i = 0; i < bucketCount; i++)
  660. {
  661. if(buckets[i] != -1)
  662. {
  663. int nextIndex = -1;
  664. for (int currentIndex = buckets[i] ; currentIndex != -1 ; currentIndex = nextIndex)
  665. {
  666. nextIndex = entries[currentIndex].next;
  667. if (fn(entries[currentIndex]))
  668. {
  669. return true; // fn condition succeeds
  670. }
  671. }
  672. }
  673. }
  674. return false;
  675. }
  676. private:
  677. template <typename TLookup>
  678. static hash_t GetHashCodeWithKey(const TLookup& key)
  679. {
  680. // set last bit to 1 to avoid false positive to make hash appears to be a valid recycler address.
  681. // In the same line, 0 should be use to indicate a non-existing entry.
  682. return TAGHASH(Comparer<TLookup>::GetHashCode(key));
  683. }
  684. static hash_t GetHashCode(const TKey& key)
  685. {
  686. return GetHashCodeWithKey<TKey>(key);
  687. }
  688. static uint GetBucket(hash_t hashCode, int bucketCount, int modFunctionIndex)
  689. {
  690. return SizePolicy::GetBucket(UNTAGHASH(hashCode), bucketCount, modFunctionIndex);
  691. }
  692. uint GetBucket(hash_t hashCode) const
  693. {
  694. return GetBucket(hashCode, this->bucketCount, modFunctionIndex);
  695. }
  696. static bool IsFreeEntry(const EntryType &entry)
  697. {
  698. // A free entry's next index will be (FreeListSentinel - nextIndex), such that it is always <= FreeListSentinel, for fast entry iteration
  699. // allowing for skipping over free entries. -1 is reserved for the end-of-chain marker for a used entry.
  700. return entry.next <= FreeListSentinel;
  701. }
  702. void SetNextFreeEntryIndex(EntryType &freeEntry, const int nextFreeEntryIndex)
  703. {
  704. Assert(!IsFreeEntry(freeEntry));
  705. Assert(nextFreeEntryIndex >= -1);
  706. Assert(nextFreeEntryIndex < count);
  707. // The last entry in the free list chain will have a next of FreeListSentinel to indicate that it is a free entry. The end of the
  708. // free list chain is identified using freeCount.
  709. freeEntry.next = nextFreeEntryIndex >= 0 ? FreeListSentinel - nextFreeEntryIndex : FreeListSentinel;
  710. }
  711. static int GetNextFreeEntryIndex(const EntryType &freeEntry)
  712. {
  713. Assert(IsFreeEntry(freeEntry));
  714. return FreeListSentinel - freeEntry.next;
  715. }
  716. template <typename LookupType>
  717. inline int FindEntryWithKey(const LookupType& key) const
  718. {
  719. #if PROFILE_DICTIONARY
  720. uint depth = 0;
  721. #endif
  722. int * localBuckets = buckets;
  723. if (localBuckets != nullptr)
  724. {
  725. hash_t hashCode = GetHashCodeWithKey<LookupType>(key);
  726. uint targetBucket = this->GetBucket(hashCode);
  727. EntryType * localEntries = entries;
  728. for (int i = localBuckets[targetBucket]; i >= 0; i = localEntries[i].next)
  729. {
  730. if (localEntries[i].template KeyEquals<Comparer<TKey>>(key, hashCode))
  731. {
  732. #if PROFILE_DICTIONARY
  733. if (stats)
  734. stats->Lookup(depth);
  735. #endif
  736. return i;
  737. }
  738. #if PROFILE_DICTIONARY
  739. depth += 1;
  740. #endif
  741. }
  742. }
  743. #if PROFILE_DICTIONARY
  744. if (stats)
  745. stats->Lookup(depth);
  746. #endif
  747. return -1;
  748. }
  749. inline int FindEntry(const TKey& key) const
  750. {
  751. return FindEntryWithKey<TKey>(key);
  752. }
  753. template <typename LookupType>
  754. inline bool FindEntryWithKey(const LookupType& key, int *const i, int *const last, uint *const targetBucket)
  755. {
  756. #if PROFILE_DICTIONARY
  757. uint depth = 0;
  758. #endif
  759. int * localBuckets = buckets;
  760. if (localBuckets != nullptr)
  761. {
  762. hash_t hashCode = GetHashCodeWithKey<LookupType>(key);
  763. *targetBucket = this->GetBucket(hashCode);
  764. *last = -1;
  765. EntryType * localEntries = entries;
  766. for (*i = localBuckets[*targetBucket]; *i >= 0; *last = *i, *i = localEntries[*i].next)
  767. {
  768. if (localEntries[*i].template KeyEquals<Comparer<TKey>>(key, hashCode))
  769. {
  770. #if PROFILE_DICTIONARY
  771. if (stats)
  772. stats->Lookup(depth);
  773. #endif
  774. return true;
  775. }
  776. #if PROFILE_DICTIONARY
  777. depth += 1;
  778. #endif
  779. }
  780. }
  781. #if PROFILE_DICTIONARY
  782. if (stats)
  783. stats->Lookup(depth);
  784. #endif
  785. return false;
  786. }
  787. void Initialize(int capacity)
  788. {
  789. // minimum capacity is 4
  790. int initSize = max(capacity, 4);
  791. int modIndex = UNKNOWN_MOD_INDEX;
  792. uint initBucketCount = SizePolicy::GetBucketSize(initSize, &modIndex);
  793. AssertMsg(initBucketCount > 0, "Size returned by policy should be greater than 0");
  794. int* newBuckets = nullptr;
  795. EntryType* newEntries = nullptr;
  796. Allocate(&newBuckets, &newEntries, initBucketCount, initSize);
  797. // Allocation can throw - assign only after allocation has succeeded.
  798. this->buckets = newBuckets;
  799. this->entries = newEntries;
  800. this->bucketCount = initBucketCount;
  801. this->size = initSize;
  802. this->modFunctionIndex = modIndex;
  803. Assert(this->freeCount == 0);
  804. #if PROFILE_DICTIONARY
  805. stats = DictionaryStats::Create(typeid(this).name(), size);
  806. #endif
  807. }
  808. template <InsertOperations op>
  809. int Insert(const TKey& key, const TValue& value)
  810. {
  811. int * localBuckets = buckets;
  812. if (localBuckets == nullptr)
  813. {
  814. Initialize(0);
  815. localBuckets = buckets;
  816. }
  817. #if DBG || PROFILE_DICTIONARY
  818. // Always search and verify
  819. const bool needSearch = true;
  820. #else
  821. const bool needSearch = (op != Insert_Add);
  822. #endif
  823. hash_t hashCode = GetHashCode(key);
  824. uint targetBucket = this->GetBucket(hashCode);
  825. if (needSearch)
  826. {
  827. #if PROFILE_DICTIONARY
  828. uint depth = 0;
  829. #endif
  830. EntryType * localEntries = entries;
  831. for (int i = localBuckets[targetBucket]; i >= 0; i = localEntries[i].next)
  832. {
  833. if (localEntries[i].template KeyEquals<Comparer<TKey>>(key, hashCode))
  834. {
  835. #if PROFILE_DICTIONARY
  836. if (stats)
  837. stats->Lookup(depth);
  838. #endif
  839. Assert(op != Insert_Add);
  840. if (op == Insert_Item)
  841. {
  842. localEntries[i].SetValue(value);
  843. return i;
  844. }
  845. return -1;
  846. }
  847. #if PROFILE_DICTIONARY
  848. depth += 1;
  849. #endif
  850. }
  851. #if PROFILE_DICTIONARY
  852. if (stats)
  853. stats->Lookup(depth);
  854. #endif
  855. }
  856. // Ideally we'd do cleanup only if weak references have been collected since the last resize
  857. // but that would require us to use an additional field to store the last recycler cleanup id
  858. // that we saw
  859. // We can add that optimization later if we have to.
  860. if (EntryType::SupportsCleanup() && freeCount == 0 && count == size)
  861. {
  862. this->MapAndRemoveIf([](EntryType& entry)
  863. {
  864. return EntryType::NeedsCleanup(entry);
  865. });
  866. }
  867. int index;
  868. if (freeCount != 0)
  869. {
  870. Assert(freeCount > 0);
  871. Assert(freeList >= 0);
  872. Assert(freeList < count);
  873. index = freeList;
  874. freeCount--;
  875. if(freeCount != 0)
  876. {
  877. freeList = GetNextFreeEntryIndex(entries[index]);
  878. }
  879. }
  880. else
  881. {
  882. // If there's nothing free, then in general, we set index to count, and increment count
  883. // If we resize, we also need to recalculate the target
  884. // However, if cleanup is supported, then before resize, we should try and clean up and see
  885. // if something got freed, and if it did, reuse that index
  886. if (count == size)
  887. {
  888. Resize();
  889. targetBucket = this->GetBucket(hashCode);
  890. index = count;
  891. count++;
  892. }
  893. else
  894. {
  895. index = count;
  896. count++;
  897. }
  898. Assert(count <= size);
  899. Assert(index < size);
  900. }
  901. entries[index].Set(key, value, hashCode);
  902. entries[index].next = buckets[targetBucket];
  903. buckets[targetBucket] = index;
  904. #if PROFILE_DICTIONARY
  905. int profileIndex = index;
  906. uint depth = 1; // need to recalculate depth in case there was a resize (also 1-based for stats->Insert)
  907. while(entries[profileIndex].next != -1)
  908. {
  909. profileIndex = entries[profileIndex].next;
  910. ++depth;
  911. }
  912. if (stats)
  913. stats->Insert(depth);
  914. #endif
  915. return index;
  916. }
  917. void Resize()
  918. {
  919. AutoDoResize autoDoResize(*this);
  920. int newSize = SizePolicy::GetNextSize(count);
  921. int modIndex = UNKNOWN_MOD_INDEX;
  922. uint newBucketCount = SizePolicy::GetBucketSize(newSize, &modIndex);
  923. __analysis_assume(newSize > count);
  924. int* newBuckets = nullptr;
  925. EntryType* newEntries = nullptr;
  926. if (newBucketCount == bucketCount)
  927. {
  928. // no need to rehash
  929. newEntries = AllocateEntries(newSize);
  930. CopyArray<EntryType, Field(ValueType, TAllocator), TAllocator>(
  931. newEntries, newSize, entries, count);
  932. DeleteEntries(entries, size);
  933. this->entries = newEntries;
  934. this->size = newSize;
  935. this->modFunctionIndex = modIndex;
  936. return;
  937. }
  938. Allocate(&newBuckets, &newEntries, newBucketCount, newSize);
  939. CopyArray<EntryType, Field(ValueType, TAllocator), TAllocator>(
  940. newEntries, newSize, entries, count);
  941. // When TAllocator is of type Recycler, it is possible that the Allocate above causes a collection, which
  942. // in turn can cause entries in the dictionary to be removed - i.e. the dictionary contains weak references
  943. // that remove themselves when no longer valid. This means the free list might not be empty anymore.
  944. this->modFunctionIndex = modIndex;
  945. for (int i = 0; i < count; i++)
  946. {
  947. __analysis_assume(i < newSize);
  948. if (!IsFreeEntry(newEntries[i]))
  949. {
  950. hash_t hashCode = newEntries[i].template GetHashCode<Comparer<TKey>>();
  951. int bucket = GetBucket(hashCode, newBucketCount, modFunctionIndex);
  952. newEntries[i].next = newBuckets[bucket];
  953. newBuckets[bucket] = i;
  954. }
  955. }
  956. DeleteBuckets(buckets, bucketCount);
  957. DeleteEntries(entries, size);
  958. #if PROFILE_DICTIONARY
  959. if (stats)
  960. stats->Resize(newSize, /*emptyBuckets=*/ newSize - size);
  961. #endif
  962. this->buckets = newBuckets;
  963. this->entries = newEntries;
  964. bucketCount = newBucketCount;
  965. size = newSize;
  966. }
  967. __ecount(bucketCount) int *AllocateBuckets(DECLSPEC_GUARD_OVERFLOW const uint bucketCount)
  968. {
  969. return
  970. AllocateArray<AllocatorType, int, false>(
  971. TRACK_ALLOC_INFO(alloc, int, AllocatorType, 0, bucketCount),
  972. TypeAllocatorFunc<AllocatorType, int>::GetAllocFunc(),
  973. bucketCount);
  974. }
  975. __ecount(size) EntryType * AllocateEntries(DECLSPEC_GUARD_OVERFLOW int size, const bool zeroAllocate = true)
  976. {
  977. // Note that the choice of leaf/non-leaf node is decided for the EntryType on the basis of TValue. By default, if
  978. // TValue is a pointer, a non-leaf allocation is done. This behavior can be overridden by specializing
  979. // TypeAllocatorFunc for TValue.
  980. return
  981. AllocateArray<AllocatorType, EntryType, false>(
  982. TRACK_ALLOC_INFO(alloc, EntryType, AllocatorType, 0, size),
  983. zeroAllocate ? EntryAllocatorFuncType::GetAllocZeroFunc() : EntryAllocatorFuncType::GetAllocFunc(),
  984. size);
  985. }
  986. void DeleteBuckets(__in_ecount(bucketCount) int *const buckets, const uint bucketCount)
  987. {
  988. Assert(buckets);
  989. Assert(bucketCount != 0);
  990. AllocatorFree(alloc, (TypeAllocatorFunc<AllocatorType, int>::GetFreeFunc()), buckets, bucketCount * sizeof(int));
  991. }
  992. void DeleteEntries(__in_ecount(size) EntryType *const entries, const int size)
  993. {
  994. Assert(entries);
  995. Assert(size != 0);
  996. AllocatorFree(alloc, EntryAllocatorFuncType::GetFreeFunc(), entries, size * sizeof(EntryType));
  997. }
  998. void Allocate(__deref_out_ecount(bucketCount) int** ppBuckets, __deref_out_ecount(size) EntryType** ppEntries, DECLSPEC_GUARD_OVERFLOW uint bucketCount, DECLSPEC_GUARD_OVERFLOW int size)
  999. {
  1000. int *const buckets = AllocateBuckets(bucketCount);
  1001. Assert(buckets); // no-throw allocators are currently not supported
  1002. EntryType *entries;
  1003. try
  1004. {
  1005. entries = AllocateEntries(size);
  1006. Assert(entries); // no-throw allocators are currently not supported
  1007. }
  1008. catch(...)
  1009. {
  1010. DeleteBuckets(buckets, bucketCount);
  1011. throw;
  1012. }
  1013. memset(buckets, -1, bucketCount * sizeof(buckets[0]));
  1014. *ppBuckets = buckets;
  1015. *ppEntries = entries;
  1016. }
  1017. inline void RemoveAt(const int i, const int last, const uint targetBucket)
  1018. {
  1019. if (last < 0)
  1020. {
  1021. buckets[targetBucket] = entries[i].next;
  1022. }
  1023. else
  1024. {
  1025. entries[last].next = entries[i].next;
  1026. }
  1027. entries[i].Clear();
  1028. SetNextFreeEntryIndex(entries[i], freeCount == 0 ? -1 : freeList);
  1029. freeList = i;
  1030. freeCount++;
  1031. #if PROFILE_DICTIONARY
  1032. if (stats)
  1033. stats->Remove(buckets[targetBucket] == -1);
  1034. #endif
  1035. }
  1036. #if DBG_DUMP
  1037. public:
  1038. void Dump()
  1039. {
  1040. Output::Print(_u("Dumping Dictionary\n"));
  1041. Output::Print(_u("-------------------\n"));
  1042. for (uint i = 0; i < bucketCount; i++)
  1043. {
  1044. Output::Print(_u("Bucket value: %d\n"), buckets[i]);
  1045. for (int j = buckets[i]; j >= 0; j = entries[j].next)
  1046. {
  1047. Output::Print(_u("%d => %d Next: %d\n"), entries[j].Key(), entries[j].Value(), entries[j].next);
  1048. }
  1049. }
  1050. }
  1051. #endif
  1052. protected:
  1053. template<class TDictionary, class Leaf>
  1054. class IteratorBase
  1055. {
  1056. IteratorBase() = delete;
  1057. protected:
  1058. EntryType *const entries;
  1059. int entryIndex;
  1060. #if DBG
  1061. protected:
  1062. TDictionary &dictionary;
  1063. private:
  1064. int usedEntryCount;
  1065. #endif
  1066. protected:
  1067. IteratorBase(TDictionary &dictionary, const int entryIndex)
  1068. : entries(dictionary.entries),
  1069. entryIndex(entryIndex)
  1070. #if DBG
  1071. ,
  1072. dictionary(dictionary),
  1073. usedEntryCount(dictionary.Count())
  1074. #endif
  1075. {
  1076. }
  1077. protected:
  1078. void OnEntryRemoved()
  1079. {
  1080. DebugOnly(--usedEntryCount);
  1081. }
  1082. private:
  1083. bool IsValid_Virtual() const
  1084. {
  1085. return static_cast<const Leaf *>(this)->IsValid();
  1086. }
  1087. protected:
  1088. bool IsValid() const
  1089. {
  1090. Assert(dictionary.entries == entries);
  1091. Assert(dictionary.Count() == usedEntryCount);
  1092. return true;
  1093. }
  1094. public:
  1095. EntryType &Current() const
  1096. {
  1097. Assert(IsValid_Virtual());
  1098. Assert(!IsFreeEntry(entries[entryIndex]));
  1099. return entries[entryIndex];
  1100. }
  1101. TKey CurrentKey() const
  1102. {
  1103. return Current().Key();
  1104. }
  1105. const TValue &CurrentValue() const
  1106. {
  1107. return Current().Value();
  1108. }
  1109. TValue &CurrentValueReference() const
  1110. {
  1111. return Current().Value();
  1112. }
  1113. void SetCurrentValue(const TValue &value) const
  1114. {
  1115. #if DBG
  1116. // For BaseHashSet, save the key before changing the value to verify that the key does not change
  1117. const TKey previousKey = CurrentKey();
  1118. const hash_t previousHashCode = GetHashCode(previousKey);
  1119. #endif
  1120. Current().SetValue(value);
  1121. Assert(Current().KeyEquals<Comparer<TKey>>(previousKey, previousHashCode));
  1122. }
  1123. };
  1124. public:
  1125. template<class TDictionary>
  1126. class EntryIterator sealed : public IteratorBase<TDictionary, EntryIterator<TDictionary>>
  1127. {
  1128. private:
  1129. typedef IteratorBase<TDictionary, EntryIterator<TDictionary>> Base;
  1130. private:
  1131. const int entryCount;
  1132. public:
  1133. EntryIterator(TDictionary &dictionary) : Base(dictionary, 0), entryCount(dictionary.count)
  1134. {
  1135. if(IsValid() && IsFreeEntry(this->entries[this->entryIndex]))
  1136. {
  1137. MoveNext();
  1138. }
  1139. }
  1140. public:
  1141. bool IsValid() const
  1142. {
  1143. Assert(this->dictionary.count == this->entryCount);
  1144. Assert(this->entryIndex >= 0);
  1145. Assert(this->entryIndex <= entryCount);
  1146. return Base::IsValid() && this->entryIndex < this->entryCount;
  1147. }
  1148. public:
  1149. void MoveNext()
  1150. {
  1151. Assert(IsValid());
  1152. do
  1153. {
  1154. ++(this->entryIndex);
  1155. } while(IsValid() && IsFreeEntry(this->entries[this->entryIndex]));
  1156. }
  1157. };
  1158. public:
  1159. template<class TDictionary>
  1160. class BucketEntryIterator sealed : public IteratorBase<TDictionary, BucketEntryIterator<TDictionary>>
  1161. {
  1162. private:
  1163. typedef IteratorBase<TDictionary, BucketEntryIterator<TDictionary>> Base;
  1164. private:
  1165. TDictionary &dictionary;
  1166. int *const buckets;
  1167. const uint bucketCount;
  1168. uint bucketIndex;
  1169. int previousEntryIndexInBucket;
  1170. int indexOfEntryAfterRemovedEntry;
  1171. public:
  1172. BucketEntryIterator(TDictionary &dictionary)
  1173. : Base(dictionary, -1),
  1174. dictionary(dictionary),
  1175. buckets(dictionary.buckets),
  1176. bucketCount(dictionary.bucketCount),
  1177. bucketIndex(0u - 1)
  1178. #if DBG
  1179. ,
  1180. previousEntryIndexInBucket(FreeListSentinel),
  1181. indexOfEntryAfterRemovedEntry(FreeListSentinel)
  1182. #endif
  1183. {
  1184. if(dictionary.Count() != 0)
  1185. {
  1186. MoveNextBucket();
  1187. }
  1188. }
  1189. public:
  1190. bool IsValid() const
  1191. {
  1192. Assert(dictionary.buckets == buckets);
  1193. Assert(dictionary.bucketCount == bucketCount);
  1194. Assert(this->entryIndex >= -1);
  1195. Assert(this->entryIndex < dictionary.count);
  1196. Assert(bucketIndex == 0u - 1 || bucketIndex <= bucketCount);
  1197. Assert(previousEntryIndexInBucket >= FreeListSentinel);
  1198. Assert(previousEntryIndexInBucket < dictionary.count);
  1199. Assert(indexOfEntryAfterRemovedEntry >= FreeListSentinel);
  1200. Assert(indexOfEntryAfterRemovedEntry < dictionary.count);
  1201. return Base::IsValid() && this->entryIndex >= 0;
  1202. }
  1203. public:
  1204. void MoveNext()
  1205. {
  1206. if(IsValid())
  1207. {
  1208. previousEntryIndexInBucket = this->entryIndex;
  1209. this->entryIndex = this->Current().next;
  1210. }
  1211. else
  1212. {
  1213. Assert(indexOfEntryAfterRemovedEntry >= -1);
  1214. this->entryIndex = indexOfEntryAfterRemovedEntry;
  1215. }
  1216. if(!IsValid())
  1217. {
  1218. MoveNextBucket();
  1219. }
  1220. }
  1221. private:
  1222. void MoveNextBucket()
  1223. {
  1224. Assert(!IsValid());
  1225. while(++bucketIndex < bucketCount)
  1226. {
  1227. this->entryIndex = buckets[bucketIndex];
  1228. if(IsValid())
  1229. {
  1230. previousEntryIndexInBucket = -1;
  1231. break;
  1232. }
  1233. }
  1234. }
  1235. public:
  1236. void RemoveCurrent()
  1237. {
  1238. Assert(previousEntryIndexInBucket >= -1);
  1239. indexOfEntryAfterRemovedEntry = this->Current().next;
  1240. dictionary.RemoveAt(this->entryIndex, previousEntryIndexInBucket, bucketIndex);
  1241. this->OnEntryRemoved();
  1242. this->entryIndex = -1;
  1243. }
  1244. };
  1245. template<class TDictionary, class Leaf> friend class IteratorBase;
  1246. template<class TDictionary> friend class EntryIterator;
  1247. template<class TDictionary> friend class BucketEntryIterator;
  1248. PREVENT_ASSIGN(BaseDictionary);
  1249. };
  1250. template <class TKey, class TValue> class SimpleHashedEntry;
  1251. template <
  1252. class TElement,
  1253. class TAllocator,
  1254. class SizePolicy = PowerOf2SizePolicy,
  1255. class TKey = TElement,
  1256. template <typename ValueOrKey> class Comparer = DefaultComparer,
  1257. template <typename, typename> class Entry = SimpleHashedEntry,
  1258. typename Lock = NoResizeLock
  1259. >
  1260. class BaseHashSet : protected BaseDictionary<TKey, TElement, TAllocator, SizePolicy, Comparer, Entry, Lock>
  1261. {
  1262. typedef BaseDictionary<TKey, TElement, TAllocator, SizePolicy, Comparer, Entry, Lock> Base;
  1263. typedef typename Base::EntryType EntryType;
  1264. typedef typename Base::AllocatorType AllocatorType;
  1265. friend struct JsDiag::RemoteDictionary<BaseHashSet<TElement, TAllocator, SizePolicy, TKey, Comparer, Entry, Lock>>;
  1266. public:
  1267. BaseHashSet(AllocatorType * allocator, int capacity = 0) : Base(allocator, capacity) {}
  1268. using Base::GetAllocator;
  1269. int Count() const
  1270. {
  1271. return __super::Count();
  1272. }
  1273. int Add(TElement const& element)
  1274. {
  1275. return __super::Add(ValueToKey<TKey, TElement>::ToKey(element), element);
  1276. }
  1277. // Add only if there isn't an existing element
  1278. int AddNew(TElement const& element)
  1279. {
  1280. return __super::AddNew(ValueToKey<TKey, TElement>::ToKey(element), element);
  1281. }
  1282. int Item(TElement const& element)
  1283. {
  1284. return __super::Item(ValueToKey<TKey, TElement>::ToKey(element), element);
  1285. }
  1286. void Clear()
  1287. {
  1288. __super::Clear();
  1289. }
  1290. using Base::Reset;
  1291. TElement const& Lookup(TKey const& key)
  1292. {
  1293. // Use a static to pass the null default value, since the
  1294. // default value may get returned out of the current scope by ref.
  1295. static const TElement nullElement = nullptr;
  1296. return __super::Lookup(key, nullElement);
  1297. }
  1298. template <typename KeyType>
  1299. TElement const& LookupWithKey(KeyType const& key)
  1300. {
  1301. static const TElement nullElement = nullptr;
  1302. return __super::LookupWithKey(key, nullElement);
  1303. }
  1304. bool Contains(TElement const& element) const
  1305. {
  1306. return ContainsKey(ValueToKey<TKey, TElement>::ToKey(element));
  1307. }
  1308. using Base::ContainsKey;
  1309. using Base::TryGetValue;
  1310. using Base::TryGetReference;
  1311. bool RemoveKey(const TKey &key)
  1312. {
  1313. return Base::Remove(key);
  1314. }
  1315. bool Remove(TElement const& element)
  1316. {
  1317. return __super::Remove(ValueToKey<TKey, TElement>::ToKey(element));
  1318. }
  1319. typename Base::template EntryIterator<const BaseHashSet> GetIterator() const
  1320. {
  1321. return typename Base::template EntryIterator<const BaseHashSet>(*this);
  1322. }
  1323. typename Base::template EntryIterator<BaseHashSet> GetIterator()
  1324. {
  1325. return typename Base::template EntryIterator<BaseHashSet>(*this);
  1326. }
  1327. typename Base::template BucketEntryIterator<BaseHashSet> GetIteratorWithRemovalSupport()
  1328. {
  1329. return typename Base::template BucketEntryIterator<BaseHashSet>(*this);
  1330. }
  1331. template<class Fn>
  1332. void Map(Fn fn)
  1333. {
  1334. MapUntil([fn](TElement const& value) -> bool
  1335. {
  1336. fn(value);
  1337. return false;
  1338. });
  1339. }
  1340. template<class Fn>
  1341. void MapAndRemoveIf(Fn fn)
  1342. {
  1343. __super::MapAndRemoveIf([fn](EntryType const& entry) -> bool
  1344. {
  1345. return fn(entry.Value());
  1346. });
  1347. }
  1348. template<class Fn>
  1349. bool MapUntil(Fn fn)
  1350. {
  1351. return __super::MapEntryUntil([fn](EntryType const& entry) -> bool
  1352. {
  1353. return fn(entry.Value());
  1354. });
  1355. }
  1356. bool EnsureCapacity()
  1357. {
  1358. return __super::EnsureCapacity();
  1359. }
  1360. int GetNextIndex()
  1361. {
  1362. return __super::GetNextIndex();
  1363. }
  1364. int GetLastIndex()
  1365. {
  1366. return __super::GetLastIndex();
  1367. }
  1368. using Base::GetValueAt;
  1369. bool TryGetValueAt(int index, TElement * value) const
  1370. {
  1371. return __super::TryGetValueAt(index, value);
  1372. }
  1373. BaseHashSet *Clone()
  1374. {
  1375. return AllocatorNew(AllocatorType, this->alloc, BaseHashSet, *this);
  1376. }
  1377. void Copy(const BaseHashSet *const other)
  1378. {
  1379. this->DoCopy(other);
  1380. }
  1381. void _Acquires_lock_(this->cs.cs) LockResize()
  1382. {
  1383. __super::LockResize();
  1384. }
  1385. void _Releases_lock_(this->cs.cs) UnlockResize()
  1386. {
  1387. __super::UnlockResize();
  1388. }
  1389. friend Base;
  1390. PREVENT_ASSIGN(BaseHashSet);
  1391. };
  1392. template <
  1393. class TKey,
  1394. class TValue,
  1395. class TAllocator,
  1396. class SizePolicy = PowerOf2SizePolicy,
  1397. template <typename ValueOrKey> class Comparer = DefaultComparer,
  1398. template <typename K, typename V> class Entry = SimpleDictionaryEntry,
  1399. class LockPolicy = Js::DefaultContainerLockPolicy, // Controls lock policy for read/map/write/add/remove items
  1400. class SyncObject = CriticalSection
  1401. >
  1402. class SynchronizedDictionary: protected BaseDictionary<TKey, TValue, TAllocator, SizePolicy, Comparer, Entry>
  1403. {
  1404. private:
  1405. FieldNoBarrier(SyncObject*) syncObj;
  1406. typedef BaseDictionary<TKey, TValue, TAllocator, SizePolicy, Comparer, Entry> Base;
  1407. public:
  1408. typedef TKey KeyType;
  1409. typedef TValue ValueType;
  1410. typedef typename Base::AllocatorType AllocatorType;
  1411. typedef typename Base::EntryType EntryType;
  1412. typedef SynchronizedDictionary<TKey, TValue, TAllocator, SizePolicy, Comparer, Entry, LockPolicy, SyncObject> DictionaryType;
  1413. private:
  1414. friend class Js::RemoteDictionary<DictionaryType>;
  1415. public:
  1416. SynchronizedDictionary(AllocatorType * allocator, int capacity, SyncObject* syncObject):
  1417. Base(allocator, capacity),
  1418. syncObj(syncObject)
  1419. {}
  1420. #ifdef DBG
  1421. void Dump()
  1422. {
  1423. typename LockPolicy::ReadLock autoLock(syncObj);
  1424. __super::Dump();
  1425. }
  1426. #endif
  1427. TAllocator *GetAllocator() const
  1428. {
  1429. typename LockPolicy::ReadLock autoLock(syncObj);
  1430. return __super::GetAllocator();
  1431. }
  1432. inline int Count() const
  1433. {
  1434. typename LockPolicy::ReadLock autoLock(syncObj);
  1435. return __super::Count();
  1436. }
  1437. inline int Capacity() const
  1438. {
  1439. typename LockPolicy::ReadLock autoLock(syncObj);
  1440. return __super::Capacity();
  1441. }
  1442. TValue Item(const TKey& key)
  1443. {
  1444. typename LockPolicy::ReadLock autoLock(syncObj);
  1445. return __super::Item(key);
  1446. }
  1447. bool IsInAdd()
  1448. {
  1449. typename LockPolicy::ReadLock autoLock(syncObj);
  1450. return __super::IsInAdd();
  1451. }
  1452. int Add(const TKey& key, const TValue& value)
  1453. {
  1454. typename LockPolicy::AddRemoveLock autoLock(syncObj);
  1455. return __super::Add(key, value);
  1456. }
  1457. int AddNew(const TKey& key, const TValue& value)
  1458. {
  1459. typename LockPolicy::AddRemoveLock autoLock(syncObj);
  1460. return __super::AddNew(key, value);
  1461. }
  1462. int Item(const TKey& key, const TValue& value)
  1463. {
  1464. typename LockPolicy::AddRemoveLock autoLock(syncObj);
  1465. return __super::Item(key, value);
  1466. }
  1467. bool Contains(KeyValuePair<TKey, TValue> keyValuePair)
  1468. {
  1469. typename LockPolicy::ReadLock autoLock(syncObj);
  1470. return __super::Contains(keyValuePair);
  1471. }
  1472. bool Remove(KeyValuePair<TKey, TValue> keyValuePair)
  1473. {
  1474. typename LockPolicy::AddRemoveLock autoLock(syncObj);
  1475. return __super::Remove(keyValuePair);
  1476. }
  1477. void Clear()
  1478. {
  1479. typename LockPolicy::AddRemoveLock autoLock(syncObj);
  1480. return __super::Clear();
  1481. }
  1482. void Reset()
  1483. {
  1484. typename LockPolicy::AddRemoveLock autoLock(syncObj);
  1485. return __super::Reset();
  1486. }
  1487. bool ContainsKey(const TKey& key)
  1488. {
  1489. typename LockPolicy::ReadLock autoLock(syncObj);
  1490. return __super::ContainsKey(key);
  1491. }
  1492. template <typename TLookup>
  1493. inline const TValue& LookupWithKey(const TLookup& key, const TValue& defaultValue)
  1494. {
  1495. typename LockPolicy::ReadLock autoLock(syncObj);
  1496. return __super::LookupWithKey(key, defaultValue);
  1497. }
  1498. inline const TValue& Lookup(const TKey& key, const TValue& defaultValue)
  1499. {
  1500. typename LockPolicy::ReadLock autoLock(syncObj);
  1501. return __super::Lookup(key, defaultValue);
  1502. }
  1503. template <typename TLookup>
  1504. bool TryGetValue(const TLookup& key, TValue* value)
  1505. {
  1506. typename LockPolicy::ReadLock autoLock(syncObj);
  1507. return __super::TryGetValue(key, value);
  1508. }
  1509. bool TryGetValueAndRemove(const TKey& key, TValue* value)
  1510. {
  1511. typename LockPolicy::AddRemoveLock autoLock(syncObj);
  1512. return __super::TryGetValueAndRemove(key, value);
  1513. }
  1514. template <typename TLookup>
  1515. inline bool TryGetReference(const TLookup& key, TValue** value)
  1516. {
  1517. typename LockPolicy::ReadLock autoLock(syncObj);
  1518. return __super::TryGetReference(key, value);
  1519. }
  1520. template <typename TLookup>
  1521. inline bool TryGetReference(const TLookup& key, TValue** value, int* index)
  1522. {
  1523. typename LockPolicy::ReadLock autoLock(syncObj);
  1524. return __super::TryGetReference(key, value, index);
  1525. }
  1526. const TValue& GetValueAt(const int& index) const
  1527. {
  1528. typename LockPolicy::ReadLock autoLock(syncObj);
  1529. return __super::GetValueAt(index);
  1530. }
  1531. TValue* GetReferenceAt(const int& index)
  1532. {
  1533. typename LockPolicy::ReadLock autoLock(syncObj);
  1534. return __super::GetReferenceAt(index);
  1535. }
  1536. TKey const& GetKeyAt(const int& index)
  1537. {
  1538. typename LockPolicy::ReadLock autoLock(syncObj);
  1539. return __super::GetKeyAt(index);
  1540. }
  1541. bool Remove(const TKey& key)
  1542. {
  1543. typename LockPolicy::ReadLock autoLock(syncObj);
  1544. return __super::Remove(key);
  1545. }
  1546. template<class Fn>
  1547. void MapReference(Fn fn)
  1548. {
  1549. // TODO: Verify that Map doesn't actually modify the list
  1550. typename LockPolicy::ReadLock autoLock(syncObj);
  1551. return __super::MapReference(fn);
  1552. }
  1553. template<class Fn>
  1554. bool MapUntilReference(Fn fn) const
  1555. {
  1556. typename LockPolicy::ReadLock autoLock(syncObj);
  1557. return __super::MapUntilReference(fn);
  1558. }
  1559. template<class Fn>
  1560. void MapAddress(Fn fn) const
  1561. {
  1562. typename LockPolicy::ReadLock autoLock(syncObj);
  1563. return __super::MapAddress(fn);
  1564. }
  1565. template<class Fn>
  1566. bool MapUntilAddress(Fn fn) const
  1567. {
  1568. typename LockPolicy::ReadLock autoLock(syncObj);
  1569. return __super::MapUntilAddress(fn);
  1570. }
  1571. template<class Fn>
  1572. void Map(Fn fn) const
  1573. {
  1574. typename LockPolicy::ReadLock autoLock(syncObj);
  1575. return __super::Map(fn);
  1576. }
  1577. template<class Fn>
  1578. bool MapUntil(Fn fn) const
  1579. {
  1580. typename LockPolicy::ReadLock autoLock(syncObj);
  1581. return __super::MapUntil(fn);
  1582. }
  1583. template<class Fn>
  1584. void MapAndRemoveIf(Fn fn)
  1585. {
  1586. typename LockPolicy::AddRemoveLock autoLock(syncObj);
  1587. return __super::MapAndRemoveIf(fn);
  1588. }
  1589. PREVENT_COPY(SynchronizedDictionary);
  1590. };
  1591. }
  1592. #pragma warning(pop)