1
//------------------------------------------------------------------------------
4
// Desc: DirectShow base classes - defines a non-MFC generic template list
7
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8
//------------------------------------------------------------------------------
11
/* A generic list of pointers to objects.
12
No storage management or copying is done on the objects pointed to.
13
Objectives: avoid using MFC libraries in ndm kernel mode and
14
provide a really useful list type.
16
The class is thread safe in that separate threads may add and
17
delete items in the list concurrently although the application
18
must ensure that constructor and destructor access is suitably
19
synchronised. An application can cause deadlock with operations
20
which use two lists by simultaneously calling
21
list1->Operation(list2) and list2->Operation(list1). So don't!
23
The names must not conflict with MFC classes as an application
30
/* A POSITION represents (in some fashion that's opaque) a cursor
31
on the list that can be set to identify any element. NULL is
32
a valid value and several operations regard NULL as the position
33
"one step off the end of the list". (In an n element list there
34
are n+1 places to insert and NULL is that "n+1-th" value).
35
The POSITION of an element in the list is only invalidated if
36
that element is deleted. Move operations may mean that what
37
was a valid POSITION in one list is now a valid POSITION in
40
Some operations which at first sight are illegal are allowed as
41
harmless no-ops. For instance RemoveHead is legal on an empty
42
list and it returns NULL. This allows an atomic way to test if
43
there is an element there, and if so, get it. The two operations
44
AddTail and RemoveHead thus implement a MONITOR (See Hoare's paper).
46
Single element operations return POSITIONs, non-NULL means it worked.
47
whole list operations return a BOOL. TRUE means it all worked.
49
This definition is the same as the POSITION type for MFCs, so we must
50
avoid defining it twice.
53
struct __POSITION { int unused; };
54
typedef __POSITION* POSITION;
57
const int DEFAULTCACHE = 10; /* Default node object cache size */
59
/* A class representing one node in a list.
60
Each node knows a pointer to it's adjacent nodes and also a pointer
61
to the object that it looks after.
62
All of these pointers can be retrieved or set through member functions.
69
/* Making these classes inherit from CBaseObject does nothing
70
functionally but it allows us to check there are no memory
71
leaks in debug builds.
77
class CNode : public CBaseObject {
82
CNode *m_pPrev; /* Previous node in the list */
83
CNode *m_pNext; /* Next node in the list */
84
void *m_pObject; /* Pointer to the object */
88
/* Constructor - initialise the object's pointers */
91
: CBaseObject(NAME("List node"))
97
/* Return the previous node before this one */
98
__out CNode *Prev() const { return m_pPrev; };
101
/* Return the next node after this one */
102
__out CNode *Next() const { return m_pNext; };
105
/* Set the previous node before this one */
106
void SetPrev(__in_opt CNode *p) { m_pPrev = p; };
109
/* Set the next node after this one */
110
void SetNext(__in_opt CNode *p) { m_pNext = p; };
113
/* Get the pointer to the object for this node */
114
__out void *GetData() const { return m_pObject; };
117
/* Set the pointer to the object for this node */
118
void SetData(__in void *p) { m_pObject = p; };
124
CNodeCache(INT iCacheSize) : m_iCacheSize(iCacheSize),
129
CNode *pNode = m_pHead;
131
CNode *pCurrent = pNode;
132
pNode = pNode->Next();
136
void AddToCache(__inout CNode *pNode)
138
if (m_iUsed < m_iCacheSize) {
139
pNode->SetNext(m_pHead);
146
CNode *RemoveFromCache()
148
CNode *pNode = m_pHead;
150
m_pHead = pNode->Next();
152
ASSERT(m_iUsed >= 0);
154
ASSERT(m_iUsed == 0);
166
CNode* m_pFirst; /* Pointer to first node in the list */
167
CNode* m_pLast; /* Pointer to the last node in the list */
168
LONG m_Count; /* Number of nodes currently in the list */
172
CNodeCache m_Cache; /* Cache of unused node pointers */
176
/* These override the default copy constructor and assignment
177
operator for all list classes. They are in the private class
178
declaration section so that anybody trying to pass a list
179
object by value will generate a compile time error of
180
"cannot access the private member function". If these were
181
not here then the compiler will create default constructors
182
and assignment operators which when executed first take a
183
copy of all member variables and then during destruction
184
delete them all. This must not be done for any heap
187
CBaseList(const CBaseList &refList);
188
CBaseList &operator=(const CBaseList &refList);
192
CBaseList(__in_opt LPCTSTR pName,
195
CBaseList(__in_opt LPCTSTR pName);
197
CBaseList(__in_opt LPCSTR pName,
200
CBaseList(__in_opt LPCSTR pName);
204
/* Remove all the nodes from *this i.e. make the list empty */
208
/* Return a cursor which identifies the first element of *this */
209
__out_opt POSITION GetHeadPositionI() const;
212
/* Return a cursor which identifies the last element of *this */
213
__out_opt POSITION GetTailPositionI() const;
216
/* Return the number of objects in *this */
217
int GetCountI() const;
220
/* Return the pointer to the object at rp,
221
Update rp to the next node in *this
222
but make it NULL if it was at the end of *this.
223
This is a wart retained for backwards compatibility.
224
GetPrev is not implemented.
225
Use Next, Prev and Get separately.
227
__out void *GetNextI(__inout POSITION& rp) const;
230
/* Return a pointer to the object at p
231
Asking for the object at NULL will return NULL harmlessly.
233
__out_opt void *GetI(__in_opt POSITION p) const;
234
__out void *GetValidI(__in POSITION p) const;
237
/* return the next / prev position in *this
238
return NULL when going past the end/start.
239
Next(NULL) is same as GetHeadPosition()
240
Prev(NULL) is same as GetTailPosition()
241
An n element list therefore behaves like a n+1 element
242
cycle with NULL at the start/end.
244
!!WARNING!! - This handling of NULL is DIFFERENT from GetNext.
247
1. For a list of n items there are n+1 positions to insert
248
These are conveniently encoded as the n POSITIONs and NULL.
249
2. If you are keeping a list sorted (fairly common) and you
250
search forward for an element to insert before and don't
251
find it you finish up with NULL as the element before which
252
to insert. You then want that NULL to be a valid POSITION
253
so that you can insert before it and you want that insertion
254
point to mean the (n+1)-th one that doesn't have a POSITION.
255
(symmetrically if you are working backwards through the list).
256
3. It simplifies the algebra which the methods generate.
257
e.g. AddBefore(p,x) is identical to AddAfter(Prev(p),x)
258
in ALL cases. All the other arguments probably are reflections
259
of the algebraic point.
261
__out_opt POSITION Next(__in_opt POSITION pos) const
264
return (POSITION) m_pFirst;
266
CNode *pn = (CNode *) pos;
267
return (POSITION) pn->Next();
271
__out_opt POSITION Prev(__in_opt POSITION pos) const
274
return (POSITION) m_pLast;
276
CNode *pn = (CNode *) pos;
277
return (POSITION) pn->Prev();
281
/* Return the first position in *this which holds the given
282
pointer. Return NULL if the pointer was not not found.
285
__out_opt POSITION FindI( __in void * pObj) const;
287
// ??? Should there be (or even should there be only)
288
// ??? POSITION FindNextAfter(void * pObj, POSITION p)
289
// ??? And of course FindPrevBefore too.
290
// ??? List.Find(&Obj) then becomes List.FindNextAfter(&Obj, NULL)
293
/* Remove the first node in *this (deletes the pointer to its
294
object from the list, does not free the object itself).
295
Return the pointer to its object.
296
If *this was already empty it will harmlessly return NULL.
298
__out_opt void *RemoveHeadI();
301
/* Remove the last node in *this (deletes the pointer to its
302
object from the list, does not free the object itself).
303
Return the pointer to its object.
304
If *this was already empty it will harmlessly return NULL.
306
__out_opt void *RemoveTailI();
309
/* Remove the node identified by p from the list (deletes the pointer
310
to its object from the list, does not free the object itself).
311
Asking to Remove the object at NULL will harmlessly return NULL.
312
Return the pointer to the object removed.
314
__out_opt void *RemoveI(__in_opt POSITION p);
316
/* Add single object *pObj to become a new last element of the list.
317
Return the new tail position, NULL if it fails.
318
If you are adding a COM objects, you might want AddRef it first.
319
Other existing POSITIONs in *this are still valid
321
__out_opt POSITION AddTailI(__in void * pObj);
325
/* Add all the elements in *pList to the tail of *this.
326
This duplicates all the nodes in *pList (i.e. duplicates
327
all its pointers to objects). It does not duplicate the objects.
328
If you are adding a list of pointers to a COM object into the list
329
it's a good idea to AddRef them all it when you AddTail it.
330
Return TRUE if it all worked, FALSE if it didn't.
331
If it fails some elements may have been added.
332
Existing POSITIONs in *this are still valid
334
If you actually want to MOVE the elements, use MoveToTail instead.
336
BOOL AddTail(__in CBaseList *pList);
339
/* Mirror images of AddHead: */
341
/* Add single object to become a new first element of the list.
342
Return the new head position, NULL if it fails.
343
Existing POSITIONs in *this are still valid
346
__out_opt POSITION AddHeadI(__in void * pObj);
349
/* Add all the elements in *pList to the head of *this.
350
Same warnings apply as for AddTail.
351
Return TRUE if it all worked, FALSE if it didn't.
352
If it fails some of the objects may have been added.
354
If you actually want to MOVE the elements, use MoveToHead instead.
356
BOOL AddHead(__in CBaseList *pList);
359
/* Add the object *pObj to *this after position p in *this.
360
AddAfter(NULL,x) adds x to the start - equivalent to AddHead
361
Return the position of the object added, NULL if it failed.
362
Existing POSITIONs in *this are undisturbed, including p.
365
__out_opt POSITION AddAfterI(__in_opt POSITION p, __in void * pObj);
368
/* Add the list *pList to *this after position p in *this
369
AddAfter(NULL,x) adds x to the start - equivalent to AddHead
370
Return TRUE if it all worked, FALSE if it didn't.
371
If it fails, some of the objects may be added
372
Existing POSITIONs in *this are undisturbed, including p.
374
BOOL AddAfter(__in_opt POSITION p, __in CBaseList *pList);
378
Add the object *pObj to this-List after position p in *this.
379
AddBefore(NULL,x) adds x to the end - equivalent to AddTail
380
Return the position of the new object, NULL if it fails
381
Existing POSITIONs in *this are undisturbed, including p.
384
__out_opt POSITION AddBeforeI(__in_opt POSITION p, __in void * pObj);
387
/* Add the list *pList to *this before position p in *this
388
AddAfter(NULL,x) adds x to the start - equivalent to AddHead
389
Return TRUE if it all worked, FALSE if it didn't.
390
If it fails, some of the objects may be added
391
Existing POSITIONs in *this are undisturbed, including p.
393
BOOL AddBefore(__in_opt POSITION p, __in CBaseList *pList);
396
/* Note that AddAfter(p,x) is equivalent to AddBefore(Next(p),x)
397
even in cases where p is NULL or Next(p) is NULL.
398
Similarly for mirror images etc.
399
This may make it easier to argue about programs.
404
/* The following operations do not copy any elements.
405
They move existing blocks of elements around by switching pointers.
406
They are fairly efficient for long lists as for short lists.
407
(Alas, the Count slows things down).
409
They split the list into two parts.
410
One part remains as the original list, the other part
411
is appended to the second list. There are eight possible
413
Split the list {after/before} a given element
414
keep the {head/tail} portion in the original list
415
append the rest to the {head/tail} of the new list.
417
Since After is strictly equivalent to Before Next
418
we are not in serious need of the Before/After variants.
419
That leaves only four.
421
If you are processing a list left to right and dumping
422
the bits that you have processed into another list as
423
you go, the Tail/Tail variant gives the most natural result.
424
If you are processing in reverse order, Head/Head is best.
426
By using NULL positions and empty lists judiciously either
427
of the other two can be built up in two operations.
429
The definition of NULL (see Next/Prev etc) means that
430
degenerate cases include
431
"move all elements to new list"
432
"Split a list into two lists"
433
"Concatenate two lists"
434
(and quite a few no-ops)
436
!!WARNING!! The type checking won't buy you much if you get list
437
positions muddled up - e.g. use a POSITION that's in a different
438
list and see what a mess you get!
441
/* Split *this after position p in *this
442
Retain as *this the tail portion of the original *this
443
Add the head portion to the tail end of *pList
444
Return TRUE if it all worked, FALSE if it didn't.
447
foo->MoveToTail(foo->GetHeadPosition(), bar);
448
moves one element from the head of foo to the tail of bar
449
foo->MoveToTail(NULL, bar);
450
is a no-op, returns NULL
451
foo->MoveToTail(foo->GetTailPosition, bar);
452
concatenates foo onto the end of bar and empties foo.
454
A better, except excessively long name might be
455
MoveElementsFromHeadThroughPositionToOtherTail
457
BOOL MoveToTail(__in_opt POSITION pos, __in CBaseList *pList);
461
Split *this before position p in *this.
462
Retain in *this the head portion of the original *this
463
Add the tail portion to the start (i.e. head) of *pList
466
foo->MoveToHead(foo->GetTailPosition(), bar);
467
moves one element from the tail of foo to the head of bar
468
foo->MoveToHead(NULL, bar);
469
is a no-op, returns NULL
470
foo->MoveToHead(foo->GetHeadPosition, bar);
471
concatenates foo onto the start of bar and empties foo.
473
BOOL MoveToHead(__in_opt POSITION pos, __in CBaseList *pList);
476
/* Reverse the order of the [pointers to] objects in *this
481
/* set cursor to the position of each element of list in turn */
482
#define TRAVERSELIST(list, cursor) \
483
for ( cursor = (list).GetHeadPosition() \
485
; cursor = (list).Next(cursor) \
489
/* set cursor to the position of each element of list in turn
492
#define REVERSETRAVERSELIST(list, cursor) \
493
for ( cursor = (list).GetTailPosition() \
495
; cursor = (list).Prev(cursor) \
498
}; // end of class declaration
500
template<class OBJECT> class CGenericList : public CBaseList
503
CGenericList(__in_opt LPCTSTR pName,
506
BOOL bAlert = FALSE) :
507
CBaseList(pName, iItems) {
508
UNREFERENCED_PARAMETER(bAlert);
509
UNREFERENCED_PARAMETER(bLock);
511
CGenericList(__in_opt LPCTSTR pName) :
515
__out_opt POSITION GetHeadPosition() const { return (POSITION)m_pFirst; }
516
__out_opt POSITION GetTailPosition() const { return (POSITION)m_pLast; }
517
int GetCount() const { return m_Count; }
519
__out OBJECT *GetNext(__inout POSITION& rp) const { return (OBJECT *) GetNextI(rp); }
521
__out_opt OBJECT *Get(__in_opt POSITION p) const { return (OBJECT *) GetI(p); }
522
__out OBJECT *GetValid(__in POSITION p) const { return (OBJECT *) GetValidI(p); }
523
__out_opt OBJECT *GetHead() const { return Get(GetHeadPosition()); }
525
__out_opt OBJECT *RemoveHead() { return (OBJECT *) RemoveHeadI(); }
527
__out_opt OBJECT *RemoveTail() { return (OBJECT *) RemoveTailI(); }
529
__out_opt OBJECT *Remove(__in_opt POSITION p) { return (OBJECT *) RemoveI(p); }
530
__out_opt POSITION AddBefore(__in_opt POSITION p, __in OBJECT * pObj) { return AddBeforeI(p, pObj); }
531
__out_opt POSITION AddAfter(__in_opt POSITION p, __in OBJECT * pObj) { return AddAfterI(p, pObj); }
532
__out_opt POSITION AddHead(__in OBJECT * pObj) { return AddHeadI(pObj); }
533
__out_opt POSITION AddTail(__in OBJECT * pObj) { return AddTailI(pObj); }
534
BOOL AddTail(__in CGenericList<OBJECT> *pList)
535
{ return CBaseList::AddTail((CBaseList *) pList); }
536
BOOL AddHead(__in CGenericList<OBJECT> *pList)
537
{ return CBaseList::AddHead((CBaseList *) pList); }
538
BOOL AddAfter(__in_opt POSITION p, __in CGenericList<OBJECT> *pList)
539
{ return CBaseList::AddAfter(p, (CBaseList *) pList); };
540
BOOL AddBefore(__in_opt POSITION p, __in CGenericList<OBJECT> *pList)
541
{ return CBaseList::AddBefore(p, (CBaseList *) pList); };
542
__out_opt POSITION Find( __in OBJECT * pObj) const { return FindI(pObj); }
543
}; // end of class declaration
547
/* These define the standard list types */
549
typedef CGenericList<CBaseObject> CBaseObjectList;
550
typedef CGenericList<IUnknown> CBaseInterfaceList;
552
#endif /* __WXLIST__ */