LinkList.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. //-----------------------------------------------------------------------------
  2. // File: Linklist.h
  3. // Desc: Linked list class.
  4. //
  5. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  6. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  7. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  8. // PARTICULAR PURPOSE.
  9. //
  10. // Copyright (C) Microsoft Corporation. All rights reserved.
  11. //-----------------------------------------------------------------------------
  12. #pragma once
  13. // Notes:
  14. //
  15. // The List class template implements a simple double-linked list.
  16. // It uses STL's copy semantics.
  17. // There are two versions of the Clear() method:
  18. // Clear(void) clears the list w/out cleaning up the object.
  19. // Clear(FN fn) takes a functor object that releases the objects, if they need cleanup.
  20. // The List class supports enumeration. Example of usage:
  21. //
  22. // List<T>::POSIITON pos = list.GetFrontPosition();
  23. // while (pos != list.GetEndPosition())
  24. // {
  25. // T item;
  26. // hr = list.GetItemPos(&item);
  27. // pos = list.Next(pos);
  28. // }
  29. // The ComPtrList class template derives from List<> and implements a list of COM pointers.
  30. template <class T>
  31. struct NoOp
  32. {
  33. void operator()(T& t)
  34. {
  35. }
  36. };
  37. template <class T>
  38. class List
  39. {
  40. protected:
  41. // Nodes in the linked list
  42. struct Node
  43. {
  44. Node *prev;
  45. Node *next;
  46. T item;
  47. Node() : prev(nullptr), next(nullptr)
  48. {
  49. }
  50. Node(T item) : prev(nullptr), next(nullptr)
  51. {
  52. this->item = item;
  53. }
  54. T Item() const { return item; }
  55. };
  56. public:
  57. // Object for enumerating the list.
  58. class POSITION
  59. {
  60. friend class List<T>;
  61. public:
  62. POSITION() : pNode(nullptr)
  63. {
  64. }
  65. bool operator==(const POSITION &p) const
  66. {
  67. return pNode == p.pNode;
  68. }
  69. bool operator!=(const POSITION &p) const
  70. {
  71. return pNode != p.pNode;
  72. }
  73. private:
  74. const Node *pNode;
  75. POSITION(Node *p) : pNode(p)
  76. {
  77. }
  78. };
  79. protected:
  80. Node m_anchor; // Anchor node for the linked list.
  81. DWORD m_count; // Number of items in the list.
  82. Node* Front() const
  83. {
  84. return m_anchor.next;
  85. }
  86. Node* Back() const
  87. {
  88. return m_anchor.prev;
  89. }
  90. virtual HRESULT InsertAfter(T item, Node *pBefore)
  91. {
  92. if (pBefore == nullptr)
  93. {
  94. return E_POINTER;
  95. }
  96. Node *pNode = new Node(item);
  97. if (pNode == nullptr)
  98. {
  99. return E_OUTOFMEMORY;
  100. }
  101. Node *pAfter = pBefore->next;
  102. pBefore->next = pNode;
  103. pAfter->prev = pNode;
  104. pNode->prev = pBefore;
  105. pNode->next = pAfter;
  106. m_count++;
  107. return S_OK;
  108. }
  109. virtual HRESULT GetItem(const Node *pNode, T* ppItem)
  110. {
  111. if (pNode == nullptr || ppItem == nullptr)
  112. {
  113. return E_POINTER;
  114. }
  115. *ppItem = pNode->item;
  116. return S_OK;
  117. }
  118. // RemoveItem:
  119. // Removes a node and optionally returns the item.
  120. // ppItem can be nullptr.
  121. virtual HRESULT RemoveItem(Node *pNode, T *ppItem)
  122. {
  123. if (pNode == nullptr)
  124. {
  125. return E_POINTER;
  126. }
  127. assert(pNode != &m_anchor); // We should never try to remove the anchor node.
  128. if (pNode == &m_anchor)
  129. {
  130. return E_INVALIDARG;
  131. }
  132. T item;
  133. // The next node's previous is this node's previous.
  134. pNode->next->prev = pNode->prev;
  135. // The previous node's next is this node's next.
  136. pNode->prev->next = pNode->next;
  137. item = pNode->item;
  138. delete pNode;
  139. m_count--;
  140. if (ppItem)
  141. {
  142. *ppItem = item;
  143. }
  144. return S_OK;
  145. }
  146. public:
  147. List()
  148. {
  149. m_anchor.next = &m_anchor;
  150. m_anchor.prev = &m_anchor;
  151. m_count = 0;
  152. }
  153. virtual ~List()
  154. {
  155. Clear();
  156. }
  157. // Insertion functions
  158. HRESULT InsertBack(T item)
  159. {
  160. return InsertAfter(item, m_anchor.prev);
  161. }
  162. HRESULT InsertFront(T item)
  163. {
  164. return InsertAfter(item, &m_anchor);
  165. }
  166. HRESULT InsertPos(POSITION pos, T item)
  167. {
  168. if (pos.pNode == nullptr)
  169. {
  170. return InsertBack(item);
  171. }
  172. return InsertAfter(item, pos.pNode->prev);
  173. }
  174. // RemoveBack: Removes the tail of the list and returns the value.
  175. // ppItem can be nullptr if you don't want the item back. (But the method does not release the item.)
  176. HRESULT RemoveBack(T *ppItem)
  177. {
  178. if (IsEmpty())
  179. {
  180. return E_FAIL;
  181. }
  182. else
  183. {
  184. return RemoveItem(Back(), ppItem);
  185. }
  186. }
  187. // RemoveFront: Removes the head of the list and returns the value.
  188. // ppItem can be nullptr if you don't want the item back. (But the method does not release the item.)
  189. HRESULT RemoveFront(T *ppItem)
  190. {
  191. if (IsEmpty())
  192. {
  193. return E_FAIL;
  194. }
  195. else
  196. {
  197. return RemoveItem(Front(), ppItem);
  198. }
  199. }
  200. // GetBack: Gets the tail item.
  201. HRESULT GetBack(T *ppItem)
  202. {
  203. if (IsEmpty())
  204. {
  205. return E_FAIL;
  206. }
  207. else
  208. {
  209. return GetItem(Back(), ppItem);
  210. }
  211. }
  212. // GetFront: Gets the front item.
  213. HRESULT GetFront(T *ppItem)
  214. {
  215. if (IsEmpty())
  216. {
  217. return E_FAIL;
  218. }
  219. else
  220. {
  221. return GetItem(Front(), ppItem);
  222. }
  223. }
  224. // GetCount: Returns the number of items in the list.
  225. DWORD GetCount() const { return m_count; }
  226. bool IsEmpty() const
  227. {
  228. return (GetCount() == 0);
  229. }
  230. // Clear: Takes a functor object whose operator()
  231. // frees the object on the list.
  232. template <class FN>
  233. void Clear(FN& clear_fn)
  234. {
  235. Node *n = m_anchor.next;
  236. // Delete the nodes
  237. while (n != &m_anchor)
  238. {
  239. clear_fn(n->item);
  240. Node *tmp = n->next;
  241. delete n;
  242. n = tmp;
  243. }
  244. // Reset the anchor to point at itself
  245. m_anchor.next = &m_anchor;
  246. m_anchor.prev = &m_anchor;
  247. m_count = 0;
  248. }
  249. // Clear: Clears the list. (Does not delete or release the list items.)
  250. virtual void Clear()
  251. {
  252. NoOp<T> clearOp;
  253. Clear<>(clearOp);
  254. }
  255. // Enumerator functions
  256. POSITION FrontPosition()
  257. {
  258. if (IsEmpty())
  259. {
  260. return POSITION(nullptr);
  261. }
  262. else
  263. {
  264. return POSITION(Front());
  265. }
  266. }
  267. POSITION EndPosition() const
  268. {
  269. return POSITION();
  270. }
  271. HRESULT GetItemPos(POSITION pos, T *ppItem)
  272. {
  273. if (pos.pNode)
  274. {
  275. return GetItem(pos.pNode, ppItem);
  276. }
  277. else
  278. {
  279. return E_FAIL;
  280. }
  281. }
  282. POSITION Next(const POSITION pos)
  283. {
  284. if (pos.pNode && (pos.pNode->next != &m_anchor))
  285. {
  286. return POSITION(pos.pNode->next);
  287. }
  288. else
  289. {
  290. return POSITION(nullptr);
  291. }
  292. }
  293. // Remove an item at a position.
  294. // The item is returns in ppItem, unless ppItem is nullptr.
  295. // NOTE: This method invalidates the POSITION object.
  296. HRESULT Remove(POSITION& pos, T *ppItem)
  297. {
  298. if (pos.pNode)
  299. {
  300. // Remove const-ness temporarily...
  301. Node *pNode = const_cast<Node*>(pos.pNode);
  302. pos = POSITION();
  303. return RemoveItem(pNode, ppItem);
  304. }
  305. else
  306. {
  307. return E_INVALIDARG;
  308. }
  309. }
  310. };
  311. // Typical functors for Clear method.
  312. // ComAutoRelease: Releases COM pointers.
  313. // MemDelete: Deletes pointers to new'd memory.
  314. class ComAutoRelease
  315. {
  316. public:
  317. void operator()(IUnknown *p)
  318. {
  319. if (p)
  320. {
  321. p->Release();
  322. }
  323. }
  324. };
  325. class MemDelete
  326. {
  327. public:
  328. void operator()(void *p)
  329. {
  330. if (p)
  331. {
  332. delete p;
  333. }
  334. }
  335. };
  336. // ComPtrList class
  337. // Derived class that makes it safer to store COM pointers in the List<> class.
  338. // It automatically AddRef's the pointers that are inserted onto the list
  339. // (unless the insertion method fails).
  340. //
  341. // T must be a COM interface type.
  342. // example: ComPtrList<IUnknown>
  343. //
  344. // NULLABLE: If true, client can insert nullptr pointers. This means GetItem can
  345. // succeed but return a nullptr pointer. By default, the list does not allow nullptr
  346. // pointers.
  347. template <class T, bool NULLABLE = FALSE>
  348. class ComPtrList : public List<T*>
  349. {
  350. public:
  351. typedef T* Ptr;
  352. void Clear()
  353. {
  354. ComAutoRelease car;
  355. List<Ptr>::Clear(car);
  356. }
  357. ~ComPtrList()
  358. {
  359. Clear();
  360. }
  361. protected:
  362. HRESULT InsertAfter(Ptr item, Node *pBefore)
  363. {
  364. // Do not allow nullptr item pointers unless NULLABLE is true.
  365. if (item == nullptr && !NULLABLE)
  366. {
  367. return E_POINTER;
  368. }
  369. if (item)
  370. {
  371. item->AddRef();
  372. }
  373. HRESULT hr = List<Ptr>::InsertAfter(item, pBefore);
  374. if (FAILED(hr) && item != nullptr)
  375. {
  376. item->Release();
  377. }
  378. return hr;
  379. }
  380. HRESULT GetItem(const Node *pNode, Ptr* ppItem)
  381. {
  382. Ptr pItem = nullptr;
  383. // The base class gives us the pointer without AddRef'ing it.
  384. // If we return the pointer to the caller, we must AddRef().
  385. HRESULT hr = List<Ptr>::GetItem(pNode, &pItem);
  386. if (SUCCEEDED(hr))
  387. {
  388. assert(pItem || NULLABLE);
  389. if (pItem)
  390. {
  391. *ppItem = pItem;
  392. (*ppItem)->AddRef();
  393. }
  394. }
  395. return hr;
  396. }
  397. HRESULT RemoveItem(Node *pNode, Ptr *ppItem)
  398. {
  399. // ppItem can be nullptr, but we need to get the
  400. // item so that we can release it.
  401. // If ppItem is not nullptr, we will AddRef it on the way out.
  402. Ptr pItem = nullptr;
  403. HRESULT hr = List<Ptr>::RemoveItem(pNode, &pItem);
  404. if (SUCCEEDED(hr))
  405. {
  406. assert(pItem || NULLABLE);
  407. if (ppItem && pItem)
  408. {
  409. *ppItem = pItem;
  410. (*ppItem)->AddRef();
  411. }
  412. if (pItem)
  413. {
  414. pItem->Release();
  415. pItem = nullptr;
  416. }
  417. }
  418. return hr;
  419. }
  420. };