DList.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  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. //----------------------------------------------------------------------------
  6. //
  7. // File: DList.h
  8. //
  9. // Template for Doubly Linked List
  10. //----------------------------------------------------------------------------
  11. template <typename TData, typename TCount = DefaultCount> class DListBase;
  12. template <typename TData> class DListNode;
  13. template <typename TData>
  14. class DListNodeBase
  15. {
  16. public:
  17. DListNodeBase<TData> * Next() const { return next.base; }
  18. DListNodeBase<TData> *& Next() { return next.base; }
  19. DListNodeBase<TData> * Prev() const { return prev.base; }
  20. DListNodeBase<TData> *& Prev() { return prev.base; }
  21. private:
  22. // The next node can be a real node with data, or it point back to the start of the list
  23. // Use a union to show it in the debugger (instead of casting everywhere)
  24. union
  25. {
  26. DListNodeBase<TData> * base;
  27. DListNode<TData> * node;
  28. DListBase<TData> * list;
  29. } next;
  30. union
  31. {
  32. DListNodeBase<TData> * base;
  33. DListNode<TData> * node;
  34. DListBase<TData> * list;
  35. } prev;
  36. };
  37. template <typename TData>
  38. class DListNode : public DListNodeBase<TData>
  39. {
  40. public:
  41. DListNode() : data() {}
  42. // Constructing with parameter
  43. template <typename TParam1>
  44. DListNode(TParam1 param1) : data(param1) {}
  45. // Constructing with parameter
  46. template <typename TParam1, typename TParam2>
  47. DListNode(TParam1 param1, TParam2 param2) : data(param1, param2) {}
  48. // Constructing with parameter
  49. template <typename TParam1, typename TParam2, typename TParam3>
  50. DListNode(TParam1 param1, TParam2 param2, TParam3 param3) : data(param1, param2, param3) {}
  51. // Constructing with parameter
  52. template <typename TParam1, typename TParam2, typename TParam3, typename TParam4>
  53. DListNode(TParam1 param1, TParam2 param2, TParam3 param3, TParam4 param4) : data(param1, param2, param3, param4) {}
  54. // Constructing using copy constructor
  55. DListNode(TData const& data) : data(data) {};
  56. TData data;
  57. };
  58. template<typename TData, typename TCount>
  59. class DListBase : protected DListNodeBase<TData>, public TCount
  60. {
  61. private:
  62. typedef DListNodeBase<TData> NodeBase;
  63. typedef DListNode<TData> Node;
  64. bool IsHead(NodeBase const * node) const
  65. {
  66. return (node == this);
  67. }
  68. public:
  69. class Iterator
  70. {
  71. public:
  72. Iterator() : list(nullptr), current(nullptr) {}
  73. Iterator(DListBase const * list) : list(list), current(list) {};
  74. bool IsValid() const
  75. {
  76. return (current != nullptr && !list->IsHead(current));
  77. }
  78. void Reset()
  79. {
  80. current = list;
  81. }
  82. // TODO: only need inline for DListBase<Segment, FakeCount>::Iterator::Next
  83. __forceinline
  84. bool Next()
  85. {
  86. Assert(current != nullptr);
  87. if (list->IsHead(current->Next()))
  88. {
  89. current = nullptr;
  90. return false;
  91. }
  92. current = current->Next();
  93. return true;
  94. }
  95. TData const& Data() const
  96. {
  97. Assert(this->IsValid());
  98. return ((Node *)current)->data;
  99. }
  100. TData& Data()
  101. {
  102. Assert(this->IsValid());
  103. return ((Node *)current)->data;
  104. }
  105. protected:
  106. DListBase const * list;
  107. NodeBase const * current;
  108. };
  109. class EditingIterator : public Iterator
  110. {
  111. public:
  112. EditingIterator() : Iterator() {};
  113. EditingIterator(DListBase * list) : Iterator(list) {};
  114. template <typename TAllocator>
  115. void RemoveCurrent(TAllocator * allocator)
  116. {
  117. Assert(current != nullptr);
  118. Assert(!list->IsHead(current));
  119. NodeBase * last = current->Prev();
  120. NodeBase * node = const_cast<NodeBase *>(current);
  121. DListBase::RemoveNode(node);
  122. AllocatorDelete(TAllocator, allocator, (Node *)node);
  123. current = last;
  124. const_cast<DListBase *>(list)->DecrementCount();
  125. }
  126. template <typename TAllocator>
  127. TData * InsertNodeBefore(TAllocator * allocator)
  128. {
  129. Node * newNode = AllocatorNew(TAllocator, allocator, Node);
  130. if (newNode)
  131. {
  132. NodeBase * node = const_cast<NodeBase *>(current);
  133. DListBase::InsertNodeBefore(node, newNode);
  134. const_cast<DListBase *>(list)->IncrementCount();
  135. return newNode->data;
  136. }
  137. }
  138. template <typename TAllocator>
  139. bool InsertBefore(TAllocator * allocator, TData const& data)
  140. {
  141. Node * newNode = AllocatorNew(TAllocator, allocator, Node, data);
  142. if (newNode)
  143. {
  144. NodeBase * node = const_cast<NodeBase *>(current);
  145. DListBase::InsertNodeBefore(node, newNode);
  146. const_cast<DListBase *>(list)->IncrementCount();
  147. return true;
  148. }
  149. return false;
  150. }
  151. void MoveCurrentTo(DListBase * toList)
  152. {
  153. NodeBase * last = current->Prev();
  154. NodeBase * node = const_cast<NodeBase *>(current);
  155. DListBase::RemoveNode(node);
  156. DListBase::InsertNodeBefore(toList->Next(), node);
  157. current = last;
  158. const_cast<DListBase *>(list)->DecrementCount();
  159. toList->IncrementCount();
  160. }
  161. };
  162. explicit DListBase()
  163. {
  164. Reset();
  165. }
  166. ~DListBase()
  167. {
  168. AssertMsg(this->Empty(), "DListBase need to be cleared explicitly with an allocator");
  169. }
  170. void Reset()
  171. {
  172. this->Next() = this;
  173. this->Prev() = this;
  174. this->SetCount(0);
  175. }
  176. template <typename TAllocator>
  177. void Clear(TAllocator * allocator)
  178. {
  179. NodeBase * current = this->Next();
  180. while (!this->IsHead(current))
  181. {
  182. NodeBase * next = current->Next();
  183. AllocatorDelete(TAllocator, allocator, (Node *)current);
  184. current = next;
  185. }
  186. this->Next() = this;
  187. this->Prev() = this;
  188. this->SetCount(0);
  189. }
  190. bool Empty() const { return this->IsHead(this->Next()); }
  191. bool HasOne() const { return !Empty() && this->IsHead(this->Next()->Next()); }
  192. TData const& Head() const { Assert(!Empty()); return ((Node *)this->Next())->data; }
  193. TData& Head() { Assert(!Empty()); return ((Node *)this->Next())->data; }
  194. TData const& Tail() const { Assert(!Empty()); return ((Node *)this->Prev())->data; }
  195. TData & Tail() { Assert(!Empty()); return ((Node *)this->Prev())->data; }
  196. template <typename TAllocator>
  197. bool Append(TAllocator * allocator, TData const& data)
  198. {
  199. Node * newNode = AllocatorNew(TAllocator, allocator, Node, data);
  200. if (newNode)
  201. {
  202. DListBase::InsertNodeAfter(this->Prev(), newNode);
  203. this->IncrementCount();
  204. return true;
  205. }
  206. return false;
  207. }
  208. template <typename TAllocator>
  209. bool Prepend(TAllocator * allocator, TData const& data)
  210. {
  211. Node * newNode = AllocatorNew(TAllocator, allocator, Node, data);
  212. if (newNode)
  213. {
  214. DListBase::InsertNodeBefore(this->Next(), newNode);
  215. this->IncrementCount();
  216. return true;
  217. }
  218. return false;
  219. }
  220. template <typename TAllocator>
  221. TData * PrependNode(TAllocator * allocator)
  222. {
  223. Node * newNode = AllocatorNew(TAllocator, allocator, Node);
  224. if (newNode)
  225. {
  226. DListBase::InsertNodeBefore(this->Next(), newNode);
  227. this->IncrementCount();
  228. return &newNode->data;
  229. }
  230. return nullptr;
  231. }
  232. template <typename TAllocator, typename TParam1>
  233. TData * PrependNode(TAllocator * allocator, TParam1 param1)
  234. {
  235. Node * newNode = AllocatorNew(TAllocator, allocator, Node, param1);
  236. if (newNode)
  237. {
  238. DListBase::InsertNodeBefore(this->Next(), newNode);
  239. this->IncrementCount();
  240. return &newNode->data;
  241. }
  242. return nullptr;
  243. }
  244. template <typename TAllocator, typename TParam1, typename TParam2>
  245. TData * PrependNode(TAllocator * allocator, TParam1 param1, TParam2 param2)
  246. {
  247. Node * newNode = AllocatorNew(TAllocator, allocator, Node, param1, param2);
  248. if (newNode)
  249. {
  250. DListBase::InsertNodeBefore(this->Next(), newNode);
  251. this->IncrementCount();
  252. return &newNode->data;
  253. }
  254. return nullptr;
  255. }
  256. template <typename TAllocator, typename TParam1, typename TParam2, typename TParam3>
  257. TData * PrependNode(TAllocator * allocator, TParam1 param1, TParam2 param2, TParam3 param3)
  258. {
  259. Node * newNode = AllocatorNew(TAllocator, allocator, Node, param1, param2, param3);
  260. if (newNode)
  261. {
  262. DListBase::InsertNodeBefore(this->Next(), newNode);
  263. this->IncrementCount();
  264. return &newNode->data;
  265. }
  266. return nullptr;
  267. }
  268. template <typename TAllocator, typename TParam1, typename TParam2, typename TParam3, typename TParam4>
  269. TData * PrependNode(TAllocator * allocator, TParam1 param1, TParam2 param2, TParam3 param3, TParam4 param4)
  270. {
  271. Node * newNode = AllocatorNew(TAllocator, allocator, Node, param1, param2, param3, param4);
  272. if (newNode)
  273. {
  274. DListBase::InsertNodeBefore(this->Next(), newNode);
  275. this->IncrementCount();
  276. return &newNode->data;
  277. }
  278. return nullptr;
  279. }
  280. template <typename TAllocator>
  281. void RemoveHead(TAllocator * allocator)
  282. {
  283. Assert(!this->Empty());
  284. NodeBase * node = this->Next();
  285. DListBase::RemoveNode(node);
  286. AllocatorDelete(TAllocator, allocator, (Node *)node);
  287. this->DecrementCount();
  288. }
  289. template <typename TAllocator>
  290. bool Remove(TAllocator * allocator, TData const& data)
  291. {
  292. EditingIterator iter(this);
  293. while (iter.Next())
  294. {
  295. if (iter.Data() == data)
  296. {
  297. iter.RemoveCurrent(allocator);
  298. return true;
  299. }
  300. }
  301. return false;
  302. }
  303. template <typename TAllocator>
  304. void RemoveElement(TAllocator * allocator, TData * element)
  305. {
  306. Node * node = CONTAINING_RECORD(element, Node, data);
  307. #if DBG_DUMP
  308. Assert(HasNode(node));
  309. #endif
  310. DListBase::RemoveNode(node);
  311. AllocatorDelete(TAllocator, allocator, node);
  312. this->DecrementCount();
  313. }
  314. bool Has(TData data) const
  315. {
  316. Iterator iter(this);
  317. while (iter.Next())
  318. {
  319. if (iter.Data() == data)
  320. {
  321. return true;
  322. }
  323. }
  324. return false;
  325. }
  326. void MoveTo(DListBase * list)
  327. {
  328. list->Prev()->Next() = this->Next();
  329. this->Next()->Prev() = list->Prev();
  330. list->Prev() = this->Prev();
  331. this->Prev()->Next() = list;
  332. this->Prev() = this;
  333. this->Next() = this;
  334. list->AddCount(*this);
  335. this->SetCount(0);
  336. }
  337. void MoveHeadTo(DListBase * list)
  338. {
  339. Assert(!this->Empty());
  340. NodeBase * node = this->Next();
  341. DListBase::RemoveNode(node);
  342. DListBase::InsertNodeBefore(list->Next(), node);
  343. this->DecrementCount();
  344. list->IncrementCount();
  345. }
  346. void MoveElementTo(TData * element, DListBase * list)
  347. {
  348. Node * node = CONTAINING_RECORD(element, Node, data);
  349. #if DBG_DUMP
  350. Assert(HasNode(node));
  351. #endif
  352. DListBase::RemoveNode(node);
  353. DListBase::InsertNodeBefore(list->Next(), node);
  354. this->DecrementCount();
  355. list->IncrementCount();
  356. }
  357. #if DBG_DUMP
  358. bool HasElement(TData const * element) const
  359. {
  360. Node * node = CONTAINING_RECORD(element, Node, data);
  361. return HasNode(node);
  362. }
  363. #endif
  364. private:
  365. #if DBG_DUMP
  366. bool HasNode(NodeBase * node) const
  367. {
  368. NodeBase * current = this->Next();
  369. while (!this->IsHead(current))
  370. {
  371. if (node == current)
  372. {
  373. return true;
  374. }
  375. current = current->Next();
  376. }
  377. return false;
  378. }
  379. #endif
  380. // disable copy constructor
  381. DListBase(DListBase const& list);
  382. static void InsertNodeAfter(NodeBase * node, NodeBase * newNode)
  383. {
  384. newNode->Prev() = node;
  385. newNode->Next() = node->Next();
  386. node->Next()->Prev() = newNode;
  387. node->Next() = newNode;
  388. }
  389. static void InsertNodeBefore(NodeBase * node, NodeBase * newNode)
  390. {
  391. newNode->Prev() = node->Prev();
  392. newNode->Next() = node;
  393. node->Prev()->Next() = newNode;
  394. node->Prev() = newNode;
  395. }
  396. static void RemoveNode(NodeBase * node)
  397. {
  398. node->Prev()->Next() = node->Next();
  399. node->Next()->Prev() = node->Prev();
  400. }
  401. };
  402. #define FOREACH_DLISTBASE_ENTRY(T, data, list) \
  403. { \
  404. DListBase<T>::Iterator __iter(list); \
  405. while (__iter.Next()) \
  406. { \
  407. T& data = __iter.Data();
  408. #define NEXT_DLISTBASE_ENTRY \
  409. } \
  410. }
  411. #define FOREACH_DLISTBASE_ENTRY_EDITING(T, data, list, iter) \
  412. DListBase<T>::EditingIterator iter(list); \
  413. while (iter.Next()) \
  414. { \
  415. T& data = iter.Data();
  416. #define NEXT_DLISTBASE_ENTRY_EDITING \
  417. }
  418. template <typename TData, typename TAllocator, typename TCount = DefaultCount>
  419. class DList : public DListBase<TData, TCount>
  420. {
  421. public:
  422. class EditingIterator : public DListBase::EditingIterator
  423. {
  424. public:
  425. EditingIterator() : DListBase::EditingIterator() {}
  426. EditingIterator(DList * list) : DListBase::EditingIterator(list) {}
  427. void RemoveCurrent()
  428. {
  429. __super::RemoveCurrent(Allocator());
  430. }
  431. TData& InsertNodeBefore()
  432. {
  433. return __super::InsertNodeBefore(Allocator());
  434. }
  435. void InsertBefore(TData const& data)
  436. {
  437. __super::InsertBefore(Allocator(), data);
  438. }
  439. private:
  440. TAllocator * Allocator() const
  441. {
  442. return ((DList const *)list)->allocator;
  443. }
  444. };
  445. explicit DList(TAllocator * allocator) : allocator(allocator) {}
  446. ~DList()
  447. {
  448. Clear();
  449. }
  450. void Clear()
  451. {
  452. __super::Clear(allocator);
  453. }
  454. bool Append(TData const& data)
  455. {
  456. return __super::Append(allocator, data);
  457. }
  458. bool Prepend(TData const& data)
  459. {
  460. return __super::Prepend(allocator, data);
  461. }
  462. TData * PrependNode()
  463. {
  464. return __super::PrependNode(allocator);
  465. }
  466. template <typename TParam1>
  467. TData * PrependNode(TParam1 param1)
  468. {
  469. return __super::PrependNode(allocator, param1);
  470. }
  471. template <typename TParam1, typename TParam2>
  472. TData * PrependNode(TParam1 param1, TParam2 param2)
  473. {
  474. return __super::PrependNode(allocator, param1, param2);
  475. }
  476. template <typename TParam1, typename TParam2, typename TParam3>
  477. TData * PrependNode(TParam1 param1, TParam2 param2, TParam3 param3)
  478. {
  479. return __super::PrependNode(allocator, param1, param2, param3);
  480. }
  481. template <typename TParam1, typename TParam2, typename TParam3, typename TParam4>
  482. TData * PrependNode(TParam1 param1, TParam2 param2, TParam3 param3, TParam4 param4)
  483. {
  484. return __super::PrependNode(allocator, param1, param2, param3, param4);
  485. }
  486. void RemoveHead()
  487. {
  488. __super::RemoveHead(allocator);
  489. }
  490. bool Remove(TData const& data)
  491. {
  492. return __super::Remove(allocator, data);
  493. }
  494. void RemoveElement(TData * data)
  495. {
  496. return __super::RemoveElement(allocator, data);
  497. }
  498. private:
  499. TAllocator * allocator;
  500. };
  501. template <typename TData, typename TAllocator = ArenaAllocator>
  502. class DListCounted : public DList<TData, TAllocator, RealCount>
  503. {
  504. public:
  505. explicit DListCounted(TAllocator * allocator) : DList(allocator) {}
  506. };
  507. #define FOREACH_DLIST_ENTRY(T, alloc, data, list) \
  508. { \
  509. DList<T, alloc>::Iterator __iter(list); \
  510. while (__iter.Next()) \
  511. { \
  512. T& data = __iter.Data();
  513. #define NEXT_DLIST_ENTRY \
  514. } \
  515. }
  516. #define FOREACH_DLIST_ENTRY_EDITING(T, alloc, data, list, iter) \
  517. DList<T, alloc>::EditingIterator iter(list); \
  518. while (iter.Next()) \
  519. { \
  520. T& data = iter.Data();
  521. #define NEXT_DLIST_ENTRY_EDITING \
  522. }