BaseDictionary.h 56 KB

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