List.h 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  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. namespace Js
  7. {
  8. template <class TListType, bool clearOldEntries>
  9. class CopyRemovePolicy;
  10. template <typename TListType, bool clearOldEntries>
  11. class FreeListedRemovePolicy;
  12. template <typename TListType, bool clearOldEntries>
  13. class WeakRefFreeListedRemovePolicy;
  14. };
  15. namespace JsUtil
  16. {
  17. template <
  18. class T,
  19. class TAllocator = Recycler,
  20. template <typename Value> class TComparer = DefaultComparer>
  21. class ReadOnlyList
  22. {
  23. public:
  24. typedef TComparer<T> TComparerType;
  25. protected:
  26. Field(Field(T, TAllocator) *, TAllocator) buffer;
  27. Field(int) count;
  28. FieldNoBarrier(TAllocator*) alloc;
  29. ReadOnlyList(TAllocator* alloc)
  30. : buffer(nullptr),
  31. count(0),
  32. alloc(alloc)
  33. {
  34. }
  35. public:
  36. virtual bool IsReadOnly() const
  37. {
  38. return true;
  39. }
  40. virtual void Delete()
  41. {
  42. AllocatorDelete(TAllocator, alloc, this);
  43. }
  44. const T* GetBuffer() const
  45. {
  46. return AddressOf(this->buffer[0]);
  47. }
  48. template<class TList>
  49. bool Equals(TList list)
  50. {
  51. CompileAssert(sizeof(T) == sizeof(*list->GetBuffer()));
  52. return list->Count() == this->Count()
  53. && memcmp(this->buffer, list->GetBuffer(), sizeof(T)* this->Count()) == 0;
  54. }
  55. template<class TAllocator>
  56. static ReadOnlyList * New(TAllocator* alloc, __in_ecount(count) T* buffer, DECLSPEC_GUARD_OVERFLOW int count)
  57. {
  58. return AllocatorNew(TAllocator, alloc, ReadOnlyList, buffer, count, alloc);
  59. }
  60. ReadOnlyList(__in_ecount(count) T* buffer, int count, TAllocator* alloc)
  61. : buffer(buffer),
  62. count(count),
  63. alloc(alloc)
  64. {
  65. }
  66. virtual ~ReadOnlyList()
  67. {
  68. }
  69. int Count() const
  70. {
  71. return count;
  72. }
  73. bool Empty() const
  74. {
  75. return Count() == 0;
  76. }
  77. // Gets the count of items using the specified criteria for considering an item.
  78. template <typename TConditionalFunction>
  79. int CountWhere(TConditionalFunction function) const
  80. {
  81. int conditionalCount = 0;
  82. for (int i = 0; i < this->count; ++i)
  83. {
  84. if (function(this->buffer[i]))
  85. {
  86. ++conditionalCount;
  87. }
  88. }
  89. return conditionalCount;
  90. }
  91. const T& Item(int index) const
  92. {
  93. Assert(index >= 0 && index < count);
  94. return buffer[index];
  95. }
  96. bool Contains(const T& item) const
  97. {
  98. for (int i = 0; i < count; i++)
  99. {
  100. if (TComparerType::Equals(item, buffer[i]))
  101. {
  102. return true;
  103. }
  104. }
  105. return false;
  106. }
  107. // Checks if any of the elements satisfy the condition in the passed in function.
  108. template <typename TConditionalFunction>
  109. bool Any(TConditionalFunction function)
  110. {
  111. for (int i = 0; i < count; ++i)
  112. {
  113. if (function(this->buffer[i]))
  114. {
  115. return true;
  116. }
  117. }
  118. return false;
  119. }
  120. // Checks if all of the elements satisfy the condition in the passed in function.
  121. template <typename TConditionalFunction>
  122. bool All(TConditionalFunction function)
  123. {
  124. for (int i = 0; i < count; ++i)
  125. {
  126. if (!function(this->buffer[i]))
  127. {
  128. return false;
  129. }
  130. }
  131. return true;
  132. }
  133. // Performs a binary search on a range of elements in the list (assumes the list is sorted).
  134. template <typename TComparisonFunction>
  135. int BinarySearch(TComparisonFunction compare, int fromIndex, int toIndex)
  136. {
  137. AssertMsg(fromIndex >= 0, "Invalid starting index for binary searching.");
  138. AssertMsg(toIndex < this->count, "Invalid ending index for binary searching.");
  139. while (fromIndex <= toIndex)
  140. {
  141. int midIndex = fromIndex + (toIndex - fromIndex) / 2;
  142. T item = this->Item(midIndex);
  143. int compareResult = compare(item, midIndex);
  144. if (compareResult > 0)
  145. {
  146. toIndex = midIndex - 1;
  147. }
  148. else if (compareResult < 0)
  149. {
  150. fromIndex = midIndex + 1;
  151. }
  152. else
  153. {
  154. return midIndex;
  155. }
  156. }
  157. return -1;
  158. }
  159. // Performs a binary search on the elements in the list (assumes the list is sorted).
  160. template <typename TComparisonFunction>
  161. int BinarySearch(TComparisonFunction compare)
  162. {
  163. return BinarySearch<TComparisonFunction>(compare, 0, this->Count() - 1);
  164. }
  165. };
  166. template <
  167. class T,
  168. class TAllocator = Recycler,
  169. bool isLeaf = false,
  170. template <class TListType, bool clearOldEntries> class TRemovePolicy = Js::CopyRemovePolicy,
  171. template <typename Value> class TComparer = DefaultComparer>
  172. class List : public ReadOnlyList<T, TAllocator, TComparer>
  173. {
  174. public:
  175. typedef ReadOnlyList<T, TAllocator, TComparer> ParentType;
  176. typedef typename ParentType::TComparerType TComparerType;
  177. typedef T TElementType; // For TRemovePolicy
  178. static const int DefaultIncrement = 4;
  179. private:
  180. typedef List<T, TAllocator, isLeaf, TRemovePolicy, TComparer> TListType;
  181. friend TRemovePolicy<TListType, true>;
  182. typedef TRemovePolicy<TListType, true /* clearOldEntries */> TRemovePolicyType;
  183. typedef ListTypeAllocatorFunc<TAllocator, isLeaf> AllocatorInfo;
  184. typedef typename AllocatorInfo::EffectiveAllocatorType EffectiveAllocatorType;
  185. Field(int) length;
  186. Field(int) increment;
  187. Field(TRemovePolicyType) removePolicy;
  188. Field(T, TAllocator) * AllocArray(DECLSPEC_GUARD_OVERFLOW int size)
  189. {
  190. typedef Field(T, TAllocator) TField;
  191. return AllocatorNewArrayBaseFuncPtr(TAllocator, this->alloc, AllocatorInfo::GetAllocFunc(), TField, size);
  192. }
  193. void FreeArray(Field(T, TAllocator) * oldBuffer, int oldBufferSize)
  194. {
  195. AllocatorFree(this->alloc, AllocatorInfo::GetFreeFunc(), oldBuffer, oldBufferSize);
  196. }
  197. PREVENT_COPY(List); // Disable copy constructor and operator=
  198. public:
  199. virtual bool IsReadOnly() const override
  200. {
  201. return false;
  202. }
  203. virtual void Delete() override
  204. {
  205. AllocatorDelete(TAllocator, this->alloc, this);
  206. }
  207. void EnsureArray()
  208. {
  209. EnsureArray(0);
  210. }
  211. void EnsureArray(DECLSPEC_GUARD_OVERFLOW int32 requiredCapacity)
  212. {
  213. if (this->buffer == nullptr)
  214. {
  215. int32 newSize = max(requiredCapacity, increment);
  216. this->buffer = AllocArray(newSize);
  217. this->count = 0;
  218. this->length = newSize;
  219. }
  220. else if (this->count == length || requiredCapacity > this->length)
  221. {
  222. int32 newLength = 0, newBufferSize = 0, oldBufferSize = 0;
  223. if (Int32Math::Add(length, 1u, &newLength)
  224. || Int32Math::Shl(newLength, 1u, &newLength))
  225. {
  226. JsUtil::ExternalApi::RaiseOnIntOverflow();
  227. }
  228. newLength = max(requiredCapacity, newLength);
  229. if (Int32Math::Mul(sizeof(T), newLength, &newBufferSize)
  230. || Int32Math::Mul(sizeof(T), length, &oldBufferSize))
  231. {
  232. JsUtil::ExternalApi::RaiseOnIntOverflow();
  233. }
  234. Field(T, TAllocator)* newbuffer = AllocArray(newLength);
  235. Field(T, TAllocator)* oldbuffer = this->buffer;
  236. CopyArray<Field(T, TAllocator), Field(T, TAllocator), EffectiveAllocatorType>(
  237. newbuffer, newLength, oldbuffer, length);
  238. FreeArray(oldbuffer, oldBufferSize);
  239. this->length = newLength;
  240. this->buffer = newbuffer;
  241. }
  242. }
  243. template<class T>
  244. void Copy(const T* list)
  245. {
  246. CompileAssert(sizeof(TElementType) == sizeof(typename T::TElementType));
  247. if (list->Count() > 0)
  248. {
  249. this->EnsureArray(list->Count());
  250. js_memcpy_s(this->buffer, UInt32Math::Mul(sizeof(TElementType), this->length), list->GetBuffer(), UInt32Math::Mul(sizeof(TElementType), list->Count()));
  251. }
  252. this->count = list->Count();
  253. }
  254. static List * New(TAllocator * alloc, int increment = DefaultIncrement)
  255. {
  256. return AllocatorNew(TAllocator, alloc, List, alloc, increment);
  257. }
  258. List(TAllocator* alloc, int increment = DefaultIncrement) :
  259. increment(increment), removePolicy(this), ParentType(alloc)
  260. {
  261. this->buffer = nullptr;
  262. this->count = 0;
  263. length = 0;
  264. }
  265. virtual ~List() override
  266. {
  267. this->Reset();
  268. }
  269. TAllocator * GetAllocator() const
  270. {
  271. return this->alloc;
  272. }
  273. const T& Item(int index) const
  274. {
  275. return ParentType::Item(index);
  276. }
  277. Field(T, TAllocator)& Item(int index)
  278. {
  279. Assert(index >= 0 && index < this->count);
  280. return this->buffer[index];
  281. }
  282. T& Last()
  283. {
  284. Assert(this->count >= 1);
  285. return this->Item(this->count - 1);
  286. }
  287. // Finds the last element that satisfies the condition in the passed in function.
  288. // Returns true if the element was found; false otherwise.
  289. template <typename TConditionalFunction>
  290. bool Last(TConditionalFunction function, T& outElement)
  291. {
  292. for (int i = this->count - 1; i >= 0; --i)
  293. {
  294. if (function(this->buffer[i]))
  295. {
  296. outElement = this->buffer[i];
  297. return true;
  298. }
  299. }
  300. return false;
  301. }
  302. void Item(int index, const T& item)
  303. {
  304. Assert(index >= 0 && index < this->count);
  305. this->buffer[index] = item;
  306. }
  307. void SetItem(int index, const T& item)
  308. {
  309. EnsureArray(index + 1);
  310. // TODO: (SWB)(leish) find a way to force user defined copy constructor
  311. this->buffer[index] = item;
  312. this->count = max(this->count, index + 1);
  313. }
  314. void SetExistingItem(int index, const T& item)
  315. {
  316. Item(index, item);
  317. }
  318. bool IsItemValid(int index)
  319. {
  320. return removePolicy.IsItemValid(this, index);
  321. }
  322. int SetAtFirstFreeSpot(const T& item)
  323. {
  324. int indexToSetAt = removePolicy.GetFreeItemIndex(this);
  325. if (indexToSetAt == -1)
  326. {
  327. return Add(item);
  328. }
  329. this->buffer[indexToSetAt] = item;
  330. return indexToSetAt;
  331. }
  332. int Add(const T& item)
  333. {
  334. EnsureArray();
  335. this->buffer[this->count] = item;
  336. int pos = this->count;
  337. this->count++;
  338. return pos;
  339. }
  340. int32 AddRange(__readonly _In_reads_(count) T const * items, int32 count)
  341. {
  342. Assert(items != nullptr);
  343. Assert(count > 0);
  344. int32 requiredSize = 0, availableByteSpace = 0, givenBufferSize = 0;
  345. if (Int32Math::Add(this->count, count, &requiredSize))
  346. {
  347. JsUtil::ExternalApi::RaiseOnIntOverflow();
  348. }
  349. EnsureArray(requiredSize);
  350. if (Int32Math::Sub(this->length, this->count, &availableByteSpace)
  351. || Int32Math::Mul(sizeof(T), availableByteSpace, &availableByteSpace)
  352. || Int32Math::Mul(sizeof(T), count, &givenBufferSize))
  353. {
  354. JsUtil::ExternalApi::RaiseOnIntOverflow();
  355. }
  356. js_memcpy_s(this->buffer + this->count, availableByteSpace, items, givenBufferSize);
  357. this->count = requiredSize;
  358. return requiredSize; //Returns count
  359. }
  360. void AddRange(TListType const& list)
  361. {
  362. list.Map([this](int index, T const& item)
  363. {
  364. this->Add(item);
  365. });
  366. }
  367. // Trims the end of the list
  368. template <bool weaklyRefItems>
  369. T CompactEnd()
  370. {
  371. while (this->count != 0)
  372. {
  373. AnalysisAssert(!weaklyRefItems || (this->buffer[this->count - 1] != nullptr));
  374. if (weaklyRefItems ?
  375. this->buffer[this->count - 1]->Get() != nullptr :
  376. this->buffer[this->count - 1] != nullptr)
  377. {
  378. return this->buffer[this->count - 1];
  379. }
  380. this->count--;
  381. this->buffer[this->count] = nullptr;
  382. }
  383. return nullptr;
  384. }
  385. void Remove(const T& item)
  386. {
  387. removePolicy.Remove(this, item);
  388. }
  389. T RemoveAtEnd()
  390. {
  391. Assert(this->count >= 1);
  392. T item = this->Item(this->count - 1);
  393. RemoveAt(this->count - 1);
  394. return item;
  395. }
  396. void RemoveAt(int index)
  397. {
  398. removePolicy.RemoveAt(this, index);
  399. }
  400. void Clear()
  401. {
  402. this->count = 0;
  403. }
  404. void ClearAndZero()
  405. {
  406. if(this->count == 0)
  407. {
  408. return;
  409. }
  410. ClearArray(this->buffer, this->count);
  411. Clear();
  412. }
  413. void Sort()
  414. {
  415. Sort([](void *, const void * a, const void * b) {
  416. return TComparerType::Compare(*(T*)a, *(T*)b);
  417. }, nullptr);
  418. }
  419. void Sort(int(__cdecl * _PtFuncCompare)(void *, const void *, const void *), void *_Context)
  420. {
  421. // We can call QSort only if the remove policy for this list is CopyRemovePolicy
  422. CompileAssert((IsSame<TRemovePolicyType, Js::CopyRemovePolicy<TListType, false> >::IsTrue) ||
  423. (IsSame<TRemovePolicyType, Js::CopyRemovePolicy<TListType, true> >::IsTrue));
  424. if (this->count)
  425. {
  426. qsort_s<Field(T, TAllocator), Field(T, TAllocator), EffectiveAllocatorType>(
  427. this->buffer, this->count, _PtFuncCompare, _Context);
  428. }
  429. }
  430. template<class DebugSite, class TMapFunction>
  431. HRESULT Map(DebugSite site, TMapFunction map) const // external debugging version
  432. {
  433. return Js::Map(site, PointerValue(this->buffer), this->count, map);
  434. }
  435. template<class TMapFunction>
  436. bool MapUntil(TMapFunction map) const
  437. {
  438. return MapUntilFrom(0, map);
  439. }
  440. template<class TMapFunction>
  441. bool MapUntilFrom(int start, TMapFunction map) const
  442. {
  443. for (int i = start; i < this->count; i++)
  444. {
  445. if (TRemovePolicyType::IsItemValid(this->buffer[i]))
  446. {
  447. if (map(i, this->buffer[i]))
  448. {
  449. return true;
  450. }
  451. }
  452. }
  453. return false;
  454. }
  455. template<class TMapFunction>
  456. void Map(TMapFunction map) const
  457. {
  458. MapFrom(0, map);
  459. }
  460. template<class TMapFunction>
  461. void MapAddress(TMapFunction map) const
  462. {
  463. for (int i = 0; i < this->count; i++)
  464. {
  465. if (TRemovePolicyType::IsItemValid(this->buffer[i]))
  466. {
  467. map(i, &this->buffer[i]);
  468. }
  469. }
  470. }
  471. template<class TMapFunction>
  472. void MapFrom(int start, TMapFunction map) const
  473. {
  474. for (int i = start; i < this->count; i++)
  475. {
  476. if (TRemovePolicyType::IsItemValid(this->buffer[i]))
  477. {
  478. map(i, this->buffer[i]);
  479. }
  480. }
  481. }
  482. template<class TMapFunction>
  483. void ReverseMap(TMapFunction map)
  484. {
  485. for (int i = this->count - 1; i >= 0; i--)
  486. {
  487. if (TRemovePolicyType::IsItemValid(this->buffer[i]))
  488. {
  489. map(i, this->buffer[i]);
  490. }
  491. }
  492. }
  493. void Reset()
  494. {
  495. if (this->buffer != nullptr)
  496. {
  497. auto freeFunc = AllocatorInfo::GetFreeFunc();
  498. AllocatorFree(this->alloc, freeFunc, this->buffer, sizeof(T) * length); // TODO: Better version of DeleteArray?
  499. this->buffer = nullptr;
  500. this->count = 0;
  501. length = 0;
  502. }
  503. }
  504. };
  505. }
  506. namespace Js
  507. {
  508. //
  509. // A simple wrapper on List to synchronize access.
  510. // Note that this wrapper class only exposes a few methods of List (through "private" inheritance).
  511. // It applies proper lock policy to exposed methods.
  512. //
  513. template <
  514. class T, // Item type in the list
  515. class ListType,
  516. class LockPolicy = DefaultContainerLockPolicy, // Controls lock policy for read/map/write/add/remove items
  517. class SyncObject = CriticalSection
  518. >
  519. class SynchronizableList sealed: private ListType // Make base class private to lock down exposed methods
  520. {
  521. private:
  522. FieldNoBarrier(SyncObject*) syncObj;
  523. public:
  524. template <class Arg1>
  525. SynchronizableList(Arg1 arg1, SyncObject* syncObj)
  526. : ListType(arg1), syncObj(syncObj)
  527. {
  528. }
  529. template <class Arg1, class Arg2>
  530. SynchronizableList(Arg1 arg1, Arg2 arg2, SyncObject* syncObj)
  531. : ListType(arg1, arg2), syncObj(syncObj)
  532. {
  533. }
  534. template <class Arg1, class Arg2, class Arg3>
  535. SynchronizableList(Arg1 arg1, Arg2 arg2, Arg3 arg3, SyncObject* syncObj)
  536. : ListType(arg1, arg2, arg3), syncObj(syncObj)
  537. {
  538. }
  539. int Count() const
  540. {
  541. typename LockPolicy::ReadLock autoLock(syncObj);
  542. return __super::Count();
  543. }
  544. const T& Item(int index) const
  545. {
  546. typename LockPolicy::ReadLock autoLock(syncObj);
  547. return __super::Item(index);
  548. }
  549. void Item(int index, const T& item)
  550. {
  551. typename LockPolicy::WriteLock autoLock(syncObj);
  552. __super::Item(index, item);
  553. }
  554. void SetExistingItem(int index, const T& item)
  555. {
  556. typename LockPolicy::WriteLock autoLock(syncObj);
  557. __super::SetExistingItem(index, item);
  558. }
  559. bool IsItemValid(int index)
  560. {
  561. typename LockPolicy::ReadLock autoLock(syncObj);
  562. return __super::IsItemValid(index);
  563. }
  564. int SetAtFirstFreeSpot(const T& item)
  565. {
  566. typename LockPolicy::WriteLock autoLock(syncObj);
  567. return __super::SetAtFirstFreeSpot(item);
  568. }
  569. void ClearAndZero()
  570. {
  571. typename LockPolicy::WriteLock autoLock(syncObj);
  572. __super::ClearAndZero();
  573. }
  574. void RemoveAt(int index)
  575. {
  576. typename LockPolicy::AddRemoveLock autoLock(syncObj);
  577. return __super::RemoveAt(index);
  578. }
  579. int Add(const T& item)
  580. {
  581. typename LockPolicy::AddRemoveLock autoLock(syncObj);
  582. return __super::Add(item);
  583. }
  584. template<class TMapFunction>
  585. void Map(TMapFunction map) const
  586. {
  587. typename LockPolicy::ReadLock autoLock(syncObj);
  588. __super::Map(map);
  589. }
  590. template<class TMapFunction>
  591. bool MapUntil(TMapFunction map) const
  592. {
  593. typename LockPolicy::ReadLock autoLock(syncObj);
  594. return __super::MapUntil(map);
  595. }
  596. template<class DebugSite, class TMapFunction>
  597. HRESULT Map(DebugSite site, TMapFunction map) const // external debugging version
  598. {
  599. // No lock needed. Threads are suspended during external debugging.
  600. return __super::Map(site, map);
  601. }
  602. };
  603. template <typename TListType, bool clearOldEntries = false>
  604. class CopyRemovePolicy
  605. {
  606. typedef typename TListType::TElementType TElementType;
  607. typedef typename TListType::TComparerType TComparerType;
  608. public:
  609. CopyRemovePolicy(TListType * list) {};
  610. void Remove(TListType* list, const TElementType& item)
  611. {
  612. TElementType* buffer = list->buffer;
  613. int& count = list->count;
  614. for (int i = 0; i < count; i++)
  615. {
  616. if (TComparerType::Equals(buffer[i], item))
  617. {
  618. for (int j = i + 1; j < count; i++, j++)
  619. {
  620. buffer[i] = buffer[j];
  621. }
  622. count--;
  623. if (clearOldEntries)
  624. {
  625. ClearArray(buffer + count, 1);
  626. }
  627. break;
  628. }
  629. }
  630. }
  631. int GetFreeItemIndex(TListType* list)
  632. {
  633. return -1;
  634. }
  635. void RemoveAt(TListType* list, int index)
  636. {
  637. Assert(index >= 0 && index < list->count);
  638. for (int j = index + 1; j < list->count; index++, j++)
  639. {
  640. list->buffer[index] = list->buffer[j];
  641. }
  642. list->count--;
  643. if (clearOldEntries)
  644. {
  645. ClearArray(list->buffer + list->count, 1);
  646. }
  647. }
  648. static bool IsItemValid(const TElementType& item)
  649. {
  650. return true;
  651. }
  652. bool IsItemValid(TListType* list, int index)
  653. {
  654. Assert(index >= 0 && index < list->count);
  655. return true;
  656. }
  657. };
  658. template <typename TListType, bool clearOldEntries = false>
  659. class FreeListedRemovePolicy
  660. {
  661. protected:
  662. typedef typename TListType::TElementType TElementType;
  663. typedef typename TListType::TComparerType TComparerType;
  664. Field(int) freeItemIndex;
  665. public:
  666. FreeListedRemovePolicy(TListType * list):
  667. freeItemIndex(-1)
  668. {
  669. CompileAssert(IsPointer<TElementType>::IsTrue);
  670. }
  671. static bool IsItemValid(const TElementType& item)
  672. {
  673. return (item != nullptr && (::Math::PointerCastToIntegralTruncate<unsigned int>(item) & 1) == 0);
  674. }
  675. bool IsItemValid(TListType* list, int index)
  676. {
  677. const TElementType& item = list->Item(index);
  678. return IsItemValid(item);
  679. }
  680. void Remove(TListType* list, const TElementType& item)
  681. {
  682. TElementType* buffer = list->buffer;
  683. int& count = list->count;
  684. for (int i = 0; i < count; i++)
  685. {
  686. if (TComparerType::Equals(buffer[i], item))
  687. {
  688. RemoveAt(list, i);
  689. break;
  690. }
  691. }
  692. }
  693. int GetFreeItemIndex(TListType* list)
  694. {
  695. int currentFreeIndex = this->freeItemIndex;
  696. if (currentFreeIndex != -1)
  697. {
  698. unsigned int nextFreeIndex = ::Math::PointerCastToIntegralTruncate<unsigned int>(list->Item(currentFreeIndex));
  699. if (nextFreeIndex != ((unsigned int) -1))
  700. {
  701. // Since this is an unsigned shift, the sign bit is 0, which is what we want
  702. this->freeItemIndex = (int) ((nextFreeIndex) >> 1);
  703. }
  704. else
  705. {
  706. this->freeItemIndex = -1;
  707. }
  708. return currentFreeIndex;
  709. }
  710. return -1;
  711. }
  712. void RemoveAt(TListType* list, int index)
  713. {
  714. Assert(index >= 0 && index < list->Count());
  715. Assert(IsItemValid(list, index));
  716. unsigned int storedIndex = (unsigned int) this->freeItemIndex;
  717. // Sentinel value, so leave that as is
  718. // Otherwise, this has the range of all +ve integers
  719. if (this->freeItemIndex != -1)
  720. {
  721. // Set a tag bit to indicate this is a free list index, rather than a list value
  722. // Pointers will be aligned anyway
  723. storedIndex = (storedIndex << 1) | 1;
  724. }
  725. list->SetExistingItem(index, (TElementType) (storedIndex));
  726. this->freeItemIndex = index;
  727. }
  728. };
  729. template <typename TListType, bool clearOldEntries = false>
  730. class WeakRefFreeListedRemovePolicy : public FreeListedRemovePolicy<TListType, clearOldEntries>
  731. {
  732. typedef FreeListedRemovePolicy<TListType, clearOldEntries> Base;
  733. typedef typename Base::TElementType TElementType;
  734. private:
  735. Field(uint) lastWeakReferenceCleanupId;
  736. void CleanupWeakReference(TListType * list)
  737. {
  738. list->Map([list](int i, TElementType weakRef)
  739. {
  740. if (weakRef->Get() == nullptr)
  741. {
  742. list->RemoveAt(i);
  743. }
  744. });
  745. this->lastWeakReferenceCleanupId = list->alloc->GetWeakReferenceCleanupId();
  746. }
  747. public:
  748. WeakRefFreeListedRemovePolicy(TListType * list) : Base(list)
  749. {
  750. this->lastWeakReferenceCleanupId = list->alloc->GetWeakReferenceCleanupId();
  751. }
  752. int GetFreeItemIndex(TListType * list)
  753. {
  754. if (list->alloc->GetWeakReferenceCleanupId() != this->lastWeakReferenceCleanupId)
  755. {
  756. CleanupWeakReference(list);
  757. }
  758. return __super::GetFreeItemIndex(list);
  759. }
  760. };
  761. }