wxlist.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. //------------------------------------------------------------------------------
  2. // File: WXList.h
  3. //
  4. // Desc: DirectShow base classes - defines a non-MFC generic template list
  5. // class.
  6. //
  7. // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
  8. //------------------------------------------------------------------------------
  9. /* A generic list of pointers to objects.
  10. No storage management or copying is done on the objects pointed to.
  11. Objectives: avoid using MFC libraries in ndm kernel mode and
  12. provide a really useful list type.
  13. The class is thread safe in that separate threads may add and
  14. delete items in the list concurrently although the application
  15. must ensure that constructor and destructor access is suitably
  16. synchronised. An application can cause deadlock with operations
  17. which use two lists by simultaneously calling
  18. list1->Operation(list2) and list2->Operation(list1). So don't!
  19. The names must not conflict with MFC classes as an application
  20. may use both.
  21. */
  22. #ifndef __WXLIST__
  23. #define __WXLIST__
  24. /* A POSITION represents (in some fashion that's opaque) a cursor
  25. on the list that can be set to identify any element. NULL is
  26. a valid value and several operations regard NULL as the position
  27. "one step off the end of the list". (In an n element list there
  28. are n+1 places to insert and NULL is that "n+1-th" value).
  29. The POSITION of an element in the list is only invalidated if
  30. that element is deleted. Move operations may mean that what
  31. was a valid POSITION in one list is now a valid POSITION in
  32. a different list.
  33. Some operations which at first sight are illegal are allowed as
  34. harmless no-ops. For instance RemoveHead is legal on an empty
  35. list and it returns NULL. This allows an atomic way to test if
  36. there is an element there, and if so, get it. The two operations
  37. AddTail and RemoveHead thus implement a MONITOR (See Hoare's paper).
  38. Single element operations return POSITIONs, non-NULL means it worked.
  39. whole list operations return a BOOL. TRUE means it all worked.
  40. This definition is the same as the POSITION type for MFCs, so we must
  41. avoid defining it twice.
  42. */
  43. #ifndef __AFX_H__
  44. struct __POSITION { int unused; };
  45. typedef __POSITION* POSITION;
  46. #endif
  47. const int DEFAULTCACHE = 10; /* Default node object cache size */
  48. /* A class representing one node in a list.
  49. Each node knows a pointer to it's adjacent nodes and also a pointer
  50. to the object that it looks after.
  51. All of these pointers can be retrieved or set through member functions.
  52. */
  53. class CBaseList
  54. #ifdef DEBUG
  55. : public CBaseObject
  56. #endif
  57. {
  58. /* Making these classes inherit from CBaseObject does nothing
  59. functionally but it allows us to check there are no memory
  60. leaks in debug builds.
  61. */
  62. public:
  63. #ifdef DEBUG
  64. class CNode : public CBaseObject {
  65. #else
  66. class CNode {
  67. #endif
  68. CNode *m_pPrev; /* Previous node in the list */
  69. CNode *m_pNext; /* Next node in the list */
  70. void *m_pObject; /* Pointer to the object */
  71. public:
  72. /* Constructor - initialise the object's pointers */
  73. CNode()
  74. #ifdef DEBUG
  75. : CBaseObject(NAME("List node"))
  76. #endif
  77. {
  78. };
  79. /* Return the previous node before this one */
  80. __out CNode *Prev() const { return m_pPrev; };
  81. /* Return the next node after this one */
  82. __out CNode *Next() const { return m_pNext; };
  83. /* Set the previous node before this one */
  84. void SetPrev(__in_opt CNode *p) { m_pPrev = p; };
  85. /* Set the next node after this one */
  86. void SetNext(__in_opt CNode *p) { m_pNext = p; };
  87. /* Get the pointer to the object for this node */
  88. __out void *GetData() const { return m_pObject; };
  89. /* Set the pointer to the object for this node */
  90. void SetData(__in void *p) { m_pObject = p; };
  91. };
  92. class CNodeCache
  93. {
  94. public:
  95. CNodeCache(INT iCacheSize) : m_iCacheSize(iCacheSize),
  96. m_pHead(NULL),
  97. m_iUsed(0)
  98. {};
  99. ~CNodeCache() {
  100. CNode *pNode = m_pHead;
  101. while (pNode) {
  102. CNode *pCurrent = pNode;
  103. pNode = pNode->Next();
  104. delete pCurrent;
  105. }
  106. };
  107. void AddToCache(__inout CNode *pNode)
  108. {
  109. if (m_iUsed < m_iCacheSize) {
  110. pNode->SetNext(m_pHead);
  111. m_pHead = pNode;
  112. m_iUsed++;
  113. } else {
  114. delete pNode;
  115. }
  116. };
  117. CNode *RemoveFromCache()
  118. {
  119. CNode *pNode = m_pHead;
  120. if (pNode != NULL) {
  121. m_pHead = pNode->Next();
  122. m_iUsed--;
  123. ASSERT(m_iUsed >= 0);
  124. } else {
  125. ASSERT(m_iUsed == 0);
  126. }
  127. return pNode;
  128. };
  129. private:
  130. INT m_iCacheSize;
  131. INT m_iUsed;
  132. CNode *m_pHead;
  133. };
  134. protected:
  135. CNode* m_pFirst; /* Pointer to first node in the list */
  136. CNode* m_pLast; /* Pointer to the last node in the list */
  137. LONG m_Count; /* Number of nodes currently in the list */
  138. private:
  139. CNodeCache m_Cache; /* Cache of unused node pointers */
  140. private:
  141. /* These override the default copy constructor and assignment
  142. operator for all list classes. They are in the private class
  143. declaration section so that anybody trying to pass a list
  144. object by value will generate a compile time error of
  145. "cannot access the private member function". If these were
  146. not here then the compiler will create default constructors
  147. and assignment operators which when executed first take a
  148. copy of all member variables and then during destruction
  149. delete them all. This must not be done for any heap
  150. allocated data.
  151. */
  152. CBaseList(const CBaseList &refList);
  153. CBaseList &operator=(const CBaseList &refList);
  154. public:
  155. CBaseList(__in_opt LPCTSTR pName,
  156. INT iItems);
  157. CBaseList(__in_opt LPCTSTR pName);
  158. #ifdef UNICODE
  159. CBaseList(__in_opt LPCSTR pName,
  160. INT iItems);
  161. CBaseList(__in_opt LPCSTR pName);
  162. #endif
  163. ~CBaseList();
  164. /* Remove all the nodes from *this i.e. make the list empty */
  165. void RemoveAll();
  166. /* Return a cursor which identifies the first element of *this */
  167. __out_opt POSITION GetHeadPositionI() const;
  168. /* Return a cursor which identifies the last element of *this */
  169. __out_opt POSITION GetTailPositionI() const;
  170. /* Return the number of objects in *this */
  171. int GetCountI() const;
  172. protected:
  173. /* Return the pointer to the object at rp,
  174. Update rp to the next node in *this
  175. but make it NULL if it was at the end of *this.
  176. This is a wart retained for backwards compatibility.
  177. GetPrev is not implemented.
  178. Use Next, Prev and Get separately.
  179. */
  180. __out void *GetNextI(__inout POSITION& rp) const;
  181. /* Return a pointer to the object at p
  182. Asking for the object at NULL will return NULL harmlessly.
  183. */
  184. __out_opt void *GetI(__in_opt POSITION p) const;
  185. __out void *GetValidI(__in POSITION p) const;
  186. public:
  187. /* return the next / prev position in *this
  188. return NULL when going past the end/start.
  189. Next(NULL) is same as GetHeadPosition()
  190. Prev(NULL) is same as GetTailPosition()
  191. An n element list therefore behaves like a n+1 element
  192. cycle with NULL at the start/end.
  193. !!WARNING!! - This handling of NULL is DIFFERENT from GetNext.
  194. Some reasons are:
  195. 1. For a list of n items there are n+1 positions to insert
  196. These are conveniently encoded as the n POSITIONs and NULL.
  197. 2. If you are keeping a list sorted (fairly common) and you
  198. search forward for an element to insert before and don't
  199. find it you finish up with NULL as the element before which
  200. to insert. You then want that NULL to be a valid POSITION
  201. so that you can insert before it and you want that insertion
  202. point to mean the (n+1)-th one that doesn't have a POSITION.
  203. (symmetrically if you are working backwards through the list).
  204. 3. It simplifies the algebra which the methods generate.
  205. e.g. AddBefore(p,x) is identical to AddAfter(Prev(p),x)
  206. in ALL cases. All the other arguments probably are reflections
  207. of the algebraic point.
  208. */
  209. __out_opt POSITION Next(__in_opt POSITION pos) const
  210. {
  211. if (pos == NULL) {
  212. return (POSITION) m_pFirst;
  213. }
  214. CNode *pn = (CNode *) pos;
  215. return (POSITION) pn->Next();
  216. } //Next
  217. // See Next
  218. __out_opt POSITION Prev(__in_opt POSITION pos) const
  219. {
  220. if (pos == NULL) {
  221. return (POSITION) m_pLast;
  222. }
  223. CNode *pn = (CNode *) pos;
  224. return (POSITION) pn->Prev();
  225. } //Prev
  226. /* Return the first position in *this which holds the given
  227. pointer. Return NULL if the pointer was not not found.
  228. */
  229. protected:
  230. __out_opt POSITION FindI( __in void * pObj) const;
  231. // ??? Should there be (or even should there be only)
  232. // ??? POSITION FindNextAfter(void * pObj, POSITION p)
  233. // ??? And of course FindPrevBefore too.
  234. // ??? List.Find(&Obj) then becomes List.FindNextAfter(&Obj, NULL)
  235. /* Remove the first node in *this (deletes the pointer to its
  236. object from the list, does not free the object itself).
  237. Return the pointer to its object.
  238. If *this was already empty it will harmlessly return NULL.
  239. */
  240. __out_opt void *RemoveHeadI();
  241. /* Remove the last node in *this (deletes the pointer to its
  242. object from the list, does not free the object itself).
  243. Return the pointer to its object.
  244. If *this was already empty it will harmlessly return NULL.
  245. */
  246. __out_opt void *RemoveTailI();
  247. /* Remove the node identified by p from the list (deletes the pointer
  248. to its object from the list, does not free the object itself).
  249. Asking to Remove the object at NULL will harmlessly return NULL.
  250. Return the pointer to the object removed.
  251. */
  252. __out_opt void *RemoveI(__in_opt POSITION p);
  253. /* Add single object *pObj to become a new last element of the list.
  254. Return the new _tail position, NULL if it fails.
  255. If you are adding a COM objects, you might want AddRef it first.
  256. Other existing POSITIONs in *this are still valid
  257. */
  258. __out_opt POSITION AddTailI(__in void * pObj);
  259. public:
  260. /* Add all the elements in *pList to the _tail of *this.
  261. This duplicates all the nodes in *pList (i.e. duplicates
  262. all its pointers to objects). It does not duplicate the objects.
  263. If you are adding a list of pointers to a COM object into the list
  264. it's a good idea to AddRef them all it when you AddTail it.
  265. Return TRUE if it all worked, FALSE if it didn't.
  266. If it fails some elements may have been added.
  267. Existing POSITIONs in *this are still valid
  268. If you actually want to MOVE the elements, use MoveToTail instead.
  269. */
  270. BOOL AddTail(__in CBaseList *pList);
  271. /* Mirror images of AddHead: */
  272. /* Add single object to become a new first element of the list.
  273. Return the new _head position, NULL if it fails.
  274. Existing POSITIONs in *this are still valid
  275. */
  276. protected:
  277. __out_opt POSITION AddHeadI(__in void * pObj);
  278. public:
  279. /* Add all the elements in *pList to the _head of *this.
  280. Same warnings apply as for AddTail.
  281. Return TRUE if it all worked, FALSE if it didn't.
  282. If it fails some of the objects may have been added.
  283. If you actually want to MOVE the elements, use MoveToHead instead.
  284. */
  285. BOOL AddHead(__in CBaseList *pList);
  286. /* Add the object *pObj to *this after position p in *this.
  287. AddAfter(NULL,x) adds x to the start - equivalent to AddHead
  288. Return the position of the object added, NULL if it failed.
  289. Existing POSITIONs in *this are undisturbed, including p.
  290. */
  291. protected:
  292. __out_opt POSITION AddAfterI(__in_opt POSITION p, __in void * pObj);
  293. public:
  294. /* Add the list *pList to *this after position p in *this
  295. AddAfter(NULL,x) adds x to the start - equivalent to AddHead
  296. Return TRUE if it all worked, FALSE if it didn't.
  297. If it fails, some of the objects may be added
  298. Existing POSITIONs in *this are undisturbed, including p.
  299. */
  300. BOOL AddAfter(__in_opt POSITION p, __in CBaseList *pList);
  301. /* Mirror images:
  302. Add the object *pObj to this-List after position p in *this.
  303. AddBefore(NULL,x) adds x to the end - equivalent to AddTail
  304. Return the position of the new object, NULL if it fails
  305. Existing POSITIONs in *this are undisturbed, including p.
  306. */
  307. protected:
  308. __out_opt POSITION AddBeforeI(__in_opt POSITION p, __in void * pObj);
  309. public:
  310. /* Add the list *pList to *this before position p in *this
  311. AddAfter(NULL,x) adds x to the start - equivalent to AddHead
  312. Return TRUE if it all worked, FALSE if it didn't.
  313. If it fails, some of the objects may be added
  314. Existing POSITIONs in *this are undisturbed, including p.
  315. */
  316. BOOL AddBefore(__in_opt POSITION p, __in CBaseList *pList);
  317. /* Note that AddAfter(p,x) is equivalent to AddBefore(Next(p),x)
  318. even in cases where p is NULL or Next(p) is NULL.
  319. Similarly for mirror images etc.
  320. This may make it easier to argue about programs.
  321. */
  322. /* The following operations do not copy any elements.
  323. They move existing blocks of elements around by switching pointers.
  324. They are fairly efficient for long lists as for short lists.
  325. (Alas, the Count slows things down).
  326. They split the list into two parts.
  327. One part remains as the original list, the other part
  328. is appended to the second list. There are eight possible
  329. variations:
  330. Split the list {after/before} a given element
  331. keep the {_head/_tail} portion in the original list
  332. append the rest to the {_head/_tail} of the new list.
  333. Since After is strictly equivalent to Before Next
  334. we are not in serious need of the Before/After variants.
  335. That leaves only four.
  336. If you are processing a list left to right and dumping
  337. the bits that you have processed into another list as
  338. you go, the Tail/Tail variant gives the most natural result.
  339. If you are processing in reverse order, Head/Head is best.
  340. By using NULL positions and empty lists judiciously either
  341. of the other two can be built up in two operations.
  342. The definition of NULL (see Next/Prev etc) means that
  343. degenerate cases include
  344. "move all elements to new list"
  345. "Split a list into two lists"
  346. "Concatenate two lists"
  347. (and quite a few no-ops)
  348. !!WARNING!! The type checking won't buy you much if you get list
  349. positions muddled up - e.g. use a POSITION that's in a different
  350. list and see what a mess you get!
  351. */
  352. /* Split *this after position p in *this
  353. Retain as *this the _tail portion of the original *this
  354. Add the _head portion to the _tail end of *pList
  355. Return TRUE if it all worked, FALSE if it didn't.
  356. e.g.
  357. foo->MoveToTail(foo->GetHeadPosition(), bar);
  358. moves one element from the _head of foo to the _tail of bar
  359. foo->MoveToTail(NULL, bar);
  360. is a no-op, returns NULL
  361. foo->MoveToTail(foo->GetTailPosition, bar);
  362. concatenates foo onto the end of bar and empties foo.
  363. A better, except excessively long name might be
  364. MoveElementsFromHeadThroughPositionToOtherTail
  365. */
  366. BOOL MoveToTail(__in_opt POSITION pos, __in CBaseList *pList);
  367. /* Mirror image:
  368. Split *this before position p in *this.
  369. Retain in *this the _head portion of the original *this
  370. Add the _tail portion to the start (i.e. _head) of *pList
  371. e.g.
  372. foo->MoveToHead(foo->GetTailPosition(), bar);
  373. moves one element from the _tail of foo to the _head of bar
  374. foo->MoveToHead(NULL, bar);
  375. is a no-op, returns NULL
  376. foo->MoveToHead(foo->GetHeadPosition, bar);
  377. concatenates foo onto the start of bar and empties foo.
  378. */
  379. BOOL MoveToHead(__in_opt POSITION pos, __in CBaseList *pList);
  380. /* Reverse the order of the [pointers to] objects in *this
  381. */
  382. void Reverse();
  383. /* set cursor to the position of each element of list in turn */
  384. #define TRAVERSELIST(list, cursor) \
  385. for ( cursor = (list).GetHeadPosition() \
  386. ; cursor!=NULL \
  387. ; cursor = (list).Next(cursor) \
  388. )
  389. /* set cursor to the position of each element of list in turn
  390. in reverse order
  391. */
  392. #define REVERSETRAVERSELIST(list, cursor) \
  393. for ( cursor = (list).GetTailPosition() \
  394. ; cursor!=NULL \
  395. ; cursor = (list).Prev(cursor) \
  396. )
  397. }; // end of class declaration
  398. template<class OBJECT> class CGenericList : public CBaseList
  399. {
  400. public:
  401. CGenericList(__in_opt LPCTSTR pName,
  402. INT iItems,
  403. BOOL bLock = TRUE,
  404. BOOL bAlert = FALSE) :
  405. CBaseList(pName, iItems) {
  406. UNREFERENCED_PARAMETER(bAlert);
  407. UNREFERENCED_PARAMETER(bLock);
  408. };
  409. CGenericList(__in_opt LPCTSTR pName) :
  410. CBaseList(pName) {
  411. };
  412. __out_opt POSITION GetHeadPosition() const { return (POSITION)m_pFirst; }
  413. __out_opt POSITION GetTailPosition() const { return (POSITION)m_pLast; }
  414. int GetCount() const { return m_Count; }
  415. __out OBJECT *GetNext(__inout POSITION& rp) const { return (OBJECT *) GetNextI(rp); }
  416. __out_opt OBJECT *Get(__in_opt POSITION p) const { return (OBJECT *) GetI(p); }
  417. __out OBJECT *GetValid(__in POSITION p) const { return (OBJECT *) GetValidI(p); }
  418. __out_opt OBJECT *GetHead() const { return Get(GetHeadPosition()); }
  419. __out_opt OBJECT *RemoveHead() { return (OBJECT *) RemoveHeadI(); }
  420. __out_opt OBJECT *RemoveTail() { return (OBJECT *) RemoveTailI(); }
  421. __out_opt OBJECT *Remove(__in_opt POSITION p) { return (OBJECT *) RemoveI(p); }
  422. __out_opt POSITION AddBefore(__in_opt POSITION p, __in OBJECT * pObj) { return AddBeforeI(p, pObj); }
  423. __out_opt POSITION AddAfter(__in_opt POSITION p, __in OBJECT * pObj) { return AddAfterI(p, pObj); }
  424. __out_opt POSITION AddHead(__in OBJECT * pObj) { return AddHeadI(pObj); }
  425. __out_opt POSITION AddTail(__in OBJECT * pObj) { return AddTailI(pObj); }
  426. BOOL AddTail(__in CGenericList<OBJECT> *pList)
  427. { return CBaseList::AddTail((CBaseList *) pList); }
  428. BOOL AddHead(__in CGenericList<OBJECT> *pList)
  429. { return CBaseList::AddHead((CBaseList *) pList); }
  430. BOOL AddAfter(__in_opt POSITION p, __in CGenericList<OBJECT> *pList)
  431. { return CBaseList::AddAfter(p, (CBaseList *) pList); };
  432. BOOL AddBefore(__in_opt POSITION p, __in CGenericList<OBJECT> *pList)
  433. { return CBaseList::AddBefore(p, (CBaseList *) pList); };
  434. __out_opt POSITION Find( __in OBJECT * pObj) const { return FindI(pObj); }
  435. }; // end of class declaration
  436. /* These define the standard list types */
  437. typedef CGenericList<CBaseObject> CBaseObjectList;
  438. typedef CGenericList<IUnknown> CBaseInterfaceList;
  439. #endif /* __WXLIST__ */