mirror of https://github.com/asterisk/asterisk
				
				
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							554 lines
						
					
					
						
							19 KiB
						
					
					
				
			
		
		
	
	
							554 lines
						
					
					
						
							19 KiB
						
					
					
				| //------------------------------------------------------------------------------
 | |
| // File: WXList.h
 | |
| //
 | |
| // Desc: DirectShow base classes - defines a non-MFC generic template list
 | |
| //       class.
 | |
| //
 | |
| // Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| 
 | |
| /* A generic list of pointers to objects.
 | |
|    No storage management or copying is done on the objects pointed to.
 | |
|    Objectives: avoid using MFC libraries in ndm kernel mode and
 | |
|    provide a really useful list type.
 | |
| 
 | |
|    The class is thread safe in that separate threads may add and
 | |
|    delete items in the list concurrently although the application
 | |
|    must ensure that constructor and destructor access is suitably
 | |
|    synchronised. An application can cause deadlock with operations
 | |
|    which use two lists by simultaneously calling
 | |
|    list1->Operation(list2) and list2->Operation(list1).  So don't!
 | |
| 
 | |
|    The names must not conflict with MFC classes as an application
 | |
|    may use both.
 | |
|    */
 | |
| 
 | |
| #ifndef __WXLIST__
 | |
| #define __WXLIST__
 | |
| 
 | |
|    /* A POSITION represents (in some fashion that's opaque) a cursor
 | |
|       on the list that can be set to identify any element.  NULL is
 | |
|       a valid value and several operations regard NULL as the position
 | |
|       "one step off the end of the list".  (In an n element list there
 | |
|       are n+1 places to insert and NULL is that "n+1-th" value).
 | |
|       The POSITION of an element in the list is only invalidated if
 | |
|       that element is deleted.  Move operations may mean that what
 | |
|       was a valid POSITION in one list is now a valid POSITION in
 | |
|       a different list.
 | |
| 
 | |
|       Some operations which at first sight are illegal are allowed as
 | |
|       harmless no-ops.  For instance RemoveHead is legal on an empty
 | |
|       list and it returns NULL.  This allows an atomic way to test if
 | |
|       there is an element there, and if so, get it.  The two operations
 | |
|       AddTail and RemoveHead thus implement a MONITOR (See Hoare's paper).
 | |
| 
 | |
|       Single element operations return POSITIONs, non-NULL means it worked.
 | |
|       whole list operations return a BOOL.  TRUE means it all worked.
 | |
| 
 | |
|       This definition is the same as the POSITION type for MFCs, so we must
 | |
|       avoid defining it twice.
 | |
|    */
 | |
| #ifndef __AFX_H__
 | |
| struct __POSITION { int unused; };
 | |
| typedef __POSITION* POSITION;
 | |
| #endif
 | |
| 
 | |
| const int DEFAULTCACHE = 10;    /* Default node object cache size */
 | |
| 
 | |
| /* A class representing one node in a list.
 | |
|    Each node knows a pointer to it's adjacent nodes and also a pointer
 | |
|    to the object that it looks after.
 | |
|    All of these pointers can be retrieved or set through member functions.
 | |
| */
 | |
| class CBaseList 
 | |
| #ifdef DEBUG
 | |
|     : public CBaseObject
 | |
| #endif
 | |
| {
 | |
|     /* Making these classes inherit from CBaseObject does nothing
 | |
|        functionally but it allows us to check there are no memory
 | |
|        leaks in debug builds. 
 | |
|     */
 | |
| 
 | |
| public:
 | |
| 
 | |
| #ifdef DEBUG
 | |
|     class CNode : public CBaseObject {
 | |
| #else
 | |
|     class CNode {
 | |
| #endif
 | |
| 
 | |
|         CNode *m_pPrev;         /* Previous node in the list */
 | |
|         CNode *m_pNext;         /* Next node in the list */
 | |
|         void *m_pObject;      /* Pointer to the object */
 | |
| 
 | |
|     public:
 | |
| 
 | |
|         /* Constructor - initialise the object's pointers */
 | |
|         CNode()
 | |
| #ifdef DEBUG
 | |
|             : CBaseObject(NAME("List node"))
 | |
| #endif
 | |
|         {
 | |
|         };
 | |
| 
 | |
| 
 | |
|         /* Return the previous node before this one */
 | |
|         __out CNode *Prev() const { return m_pPrev; };
 | |
| 
 | |
| 
 | |
|         /* Return the next node after this one */
 | |
|         __out CNode *Next() const { return m_pNext; };
 | |
| 
 | |
| 
 | |
|         /* Set the previous node before this one */
 | |
|         void SetPrev(__in_opt CNode *p) { m_pPrev = p; };
 | |
| 
 | |
| 
 | |
|         /* Set the next node after this one */
 | |
|         void SetNext(__in_opt CNode *p) { m_pNext = p; };
 | |
| 
 | |
| 
 | |
|         /* Get the pointer to the object for this node */
 | |
|         __out void *GetData() const { return m_pObject; };
 | |
| 
 | |
| 
 | |
|         /* Set the pointer to the object for this node */
 | |
|         void SetData(__in void *p) { m_pObject = p; };
 | |
|     };
 | |
| 
 | |
|     class CNodeCache
 | |
|     {
 | |
|     public:
 | |
|         CNodeCache(INT iCacheSize) : m_iCacheSize(iCacheSize),
 | |
|                                      m_pHead(NULL),
 | |
|                                      m_iUsed(0)
 | |
|                                      {};
 | |
|         ~CNodeCache() {
 | |
|             CNode *pNode = m_pHead;
 | |
|             while (pNode) {
 | |
|                 CNode *pCurrent = pNode;
 | |
|                 pNode = pNode->Next();
 | |
|                 delete pCurrent;
 | |
|             }
 | |
|         };
 | |
|         void AddToCache(__inout CNode *pNode)
 | |
|         {
 | |
|             if (m_iUsed < m_iCacheSize) {
 | |
|                 pNode->SetNext(m_pHead);
 | |
|                 m_pHead = pNode;
 | |
|                 m_iUsed++;
 | |
|             } else {
 | |
|                 delete pNode;
 | |
|             }
 | |
|         };
 | |
|         CNode *RemoveFromCache()
 | |
|         {
 | |
|             CNode *pNode = m_pHead;
 | |
|             if (pNode != NULL) {
 | |
|                 m_pHead = pNode->Next();
 | |
|                 m_iUsed--;
 | |
|                 ASSERT(m_iUsed >= 0);
 | |
|             } else {
 | |
|                 ASSERT(m_iUsed == 0);
 | |
|             }
 | |
|             return pNode;
 | |
|         };
 | |
|     private:
 | |
|         INT m_iCacheSize;
 | |
|         INT m_iUsed;
 | |
|         CNode *m_pHead;
 | |
|     };
 | |
| 
 | |
| protected:
 | |
| 
 | |
|     CNode* m_pFirst;    /* Pointer to first node in the list */
 | |
|     CNode* m_pLast;     /* Pointer to the last node in the list */
 | |
|     LONG m_Count;       /* Number of nodes currently in the list */
 | |
| 
 | |
| private:
 | |
| 
 | |
|     CNodeCache m_Cache; /* Cache of unused node pointers */
 | |
| 
 | |
| private:
 | |
| 
 | |
|     /* These override the default copy constructor and assignment
 | |
|        operator for all list classes. They are in the private class
 | |
|        declaration section so that anybody trying to pass a list
 | |
|        object by value will generate a compile time error of
 | |
|        "cannot access the private member function". If these were
 | |
|        not here then the compiler will create default constructors
 | |
|        and assignment operators which when executed first take a
 | |
|        copy of all member variables and then during destruction
 | |
|        delete them all. This must not be done for any heap
 | |
|        allocated data.
 | |
|     */
 | |
|     CBaseList(const CBaseList &refList);
 | |
|     CBaseList &operator=(const CBaseList &refList);
 | |
| 
 | |
| public:
 | |
| 
 | |
|     CBaseList(__in_opt LPCTSTR pName,
 | |
|               INT iItems);
 | |
| 
 | |
|     CBaseList(__in_opt LPCTSTR pName);
 | |
| #ifdef UNICODE
 | |
|     CBaseList(__in_opt LPCSTR pName,
 | |
|               INT iItems);
 | |
| 
 | |
|     CBaseList(__in_opt LPCSTR pName);
 | |
| #endif
 | |
|     ~CBaseList();
 | |
| 
 | |
|     /* Remove all the nodes from *this i.e. make the list empty */
 | |
|     void RemoveAll();
 | |
| 
 | |
| 
 | |
|     /* Return a cursor which identifies the first element of *this */
 | |
|     __out_opt POSITION GetHeadPositionI() const;
 | |
| 
 | |
| 
 | |
|     /* Return a cursor which identifies the last element of *this */
 | |
|     __out_opt POSITION GetTailPositionI() const;
 | |
| 
 | |
| 
 | |
|     /* Return the number of objects in *this */
 | |
|     int GetCountI() const;
 | |
| 
 | |
| protected:
 | |
|     /* Return the pointer to the object at rp,
 | |
|        Update rp to the next node in *this
 | |
|        but make it NULL if it was at the end of *this.
 | |
|        This is a wart retained for backwards compatibility.
 | |
|        GetPrev is not implemented.
 | |
|        Use Next, Prev and Get separately.
 | |
|     */
 | |
|     __out void *GetNextI(__inout POSITION& rp) const;
 | |
| 
 | |
| 
 | |
|     /* Return a pointer to the object at p
 | |
|        Asking for the object at NULL will return NULL harmlessly.
 | |
|     */
 | |
|     __out_opt void *GetI(__in_opt POSITION p) const;
 | |
|     __out void *GetValidI(__in POSITION p) const;
 | |
| 
 | |
| public:
 | |
|     /* return the next / prev position in *this
 | |
|        return NULL when going past the end/start.
 | |
|        Next(NULL) is same as GetHeadPosition()
 | |
|        Prev(NULL) is same as GetTailPosition()
 | |
|        An n element list therefore behaves like a n+1 element
 | |
|        cycle with NULL at the start/end.
 | |
| 
 | |
|        !!WARNING!! - This handling of NULL is DIFFERENT from GetNext.
 | |
| 
 | |
|        Some reasons are:
 | |
|        1. For a list of n items there are n+1 positions to insert
 | |
|           These are conveniently encoded as the n POSITIONs and NULL.
 | |
|        2. If you are keeping a list sorted (fairly common) and you
 | |
|           search forward for an element to insert before and don't
 | |
|           find it you finish up with NULL as the element before which
 | |
|           to insert.  You then want that NULL to be a valid POSITION
 | |
|           so that you can insert before it and you want that insertion
 | |
|           point to mean the (n+1)-th one that doesn't have a POSITION.
 | |
|           (symmetrically if you are working backwards through the list).
 | |
|        3. It simplifies the algebra which the methods generate.
 | |
|           e.g. AddBefore(p,x) is identical to AddAfter(Prev(p),x)
 | |
|           in ALL cases.  All the other arguments probably are reflections
 | |
|           of the algebraic point.
 | |
|     */
 | |
|     __out_opt POSITION Next(__in_opt POSITION pos) const
 | |
|     {
 | |
|         if (pos == NULL) {
 | |
|             return (POSITION) m_pFirst;
 | |
|         }
 | |
|         CNode *pn = (CNode *) pos;
 | |
|         return (POSITION) pn->Next();
 | |
|     } //Next
 | |
| 
 | |
|     // See Next
 | |
|     __out_opt POSITION Prev(__in_opt POSITION pos) const
 | |
|     {
 | |
|         if (pos == NULL) {
 | |
|             return (POSITION) m_pLast;
 | |
|         }
 | |
|         CNode *pn = (CNode *) pos;
 | |
|         return (POSITION) pn->Prev();
 | |
|     } //Prev
 | |
| 
 | |
| 
 | |
|     /* Return the first position in *this which holds the given
 | |
|        pointer.  Return NULL if the pointer was not not found.
 | |
|     */
 | |
| protected:
 | |
|     __out_opt POSITION FindI( __in void * pObj) const;
 | |
| 
 | |
|     // ??? Should there be (or even should there be only)
 | |
|     // ??? POSITION FindNextAfter(void * pObj, POSITION p)
 | |
|     // ??? And of course FindPrevBefore too.
 | |
|     // ??? List.Find(&Obj) then becomes List.FindNextAfter(&Obj, NULL)
 | |
| 
 | |
| 
 | |
|     /* Remove the first node in *this (deletes the pointer to its
 | |
|        object from the list, does not free the object itself).
 | |
|        Return the pointer to its object.
 | |
|        If *this was already empty it will harmlessly return NULL.
 | |
|     */
 | |
|     __out_opt void *RemoveHeadI();
 | |
| 
 | |
| 
 | |
|     /* Remove the last node in *this (deletes the pointer to its
 | |
|        object from the list, does not free the object itself).
 | |
|        Return the pointer to its object.
 | |
|        If *this was already empty it will harmlessly return NULL.
 | |
|     */
 | |
|     __out_opt void *RemoveTailI();
 | |
| 
 | |
| 
 | |
|     /* Remove the node identified by p from the list (deletes the pointer
 | |
|        to its object from the list, does not free the object itself).
 | |
|        Asking to Remove the object at NULL will harmlessly return NULL.
 | |
|        Return the pointer to the object removed.
 | |
|     */
 | |
|     __out_opt void *RemoveI(__in_opt POSITION p);
 | |
| 
 | |
|     /* Add single object *pObj to become a new last element of the list.
 | |
|        Return the new tail position, NULL if it fails.
 | |
|        If you are adding a COM objects, you might want AddRef it first.
 | |
|        Other existing POSITIONs in *this are still valid
 | |
|     */
 | |
|     __out_opt POSITION AddTailI(__in void * pObj);
 | |
| public:
 | |
| 
 | |
| 
 | |
|     /* Add all the elements in *pList to the tail of *this.
 | |
|        This duplicates all the nodes in *pList (i.e. duplicates
 | |
|        all its pointers to objects).  It does not duplicate the objects.
 | |
|        If you are adding a list of pointers to a COM object into the list
 | |
|        it's a good idea to AddRef them all  it when you AddTail it.
 | |
|        Return TRUE if it all worked, FALSE if it didn't.
 | |
|        If it fails some elements may have been added.
 | |
|        Existing POSITIONs in *this are still valid
 | |
| 
 | |
|        If you actually want to MOVE the elements, use MoveToTail instead.
 | |
|     */
 | |
|     BOOL AddTail(__in CBaseList *pList);
 | |
| 
 | |
| 
 | |
|     /* Mirror images of AddHead: */
 | |
| 
 | |
|     /* Add single object to become a new first element of the list.
 | |
|        Return the new head position, NULL if it fails.
 | |
|        Existing POSITIONs in *this are still valid
 | |
|     */
 | |
| protected:
 | |
|     __out_opt POSITION AddHeadI(__in void * pObj);
 | |
| public:
 | |
| 
 | |
|     /* Add all the elements in *pList to the head of *this.
 | |
|        Same warnings apply as for AddTail.
 | |
|        Return TRUE if it all worked, FALSE if it didn't.
 | |
|        If it fails some of the objects may have been added.
 | |
| 
 | |
|        If you actually want to MOVE the elements, use MoveToHead instead.
 | |
|     */
 | |
|     BOOL AddHead(__in CBaseList *pList);
 | |
| 
 | |
| 
 | |
|     /* Add the object *pObj to *this after position p in *this.
 | |
|        AddAfter(NULL,x) adds x to the start - equivalent to AddHead
 | |
|        Return the position of the object added, NULL if it failed.
 | |
|        Existing POSITIONs in *this are undisturbed, including p.
 | |
|     */
 | |
| protected:
 | |
|     __out_opt POSITION AddAfterI(__in_opt POSITION p, __in void * pObj);
 | |
| public:
 | |
| 
 | |
|     /* Add the list *pList to *this after position p in *this
 | |
|        AddAfter(NULL,x) adds x to the start - equivalent to AddHead
 | |
|        Return TRUE if it all worked, FALSE if it didn't.
 | |
|        If it fails, some of the objects may be added
 | |
|        Existing POSITIONs in *this are undisturbed, including p.
 | |
|     */
 | |
|     BOOL AddAfter(__in_opt POSITION p, __in CBaseList *pList);
 | |
| 
 | |
| 
 | |
|     /* Mirror images:
 | |
|        Add the object *pObj to this-List after position p in *this.
 | |
|        AddBefore(NULL,x) adds x to the end - equivalent to AddTail
 | |
|        Return the position of the new object, NULL if it fails
 | |
|        Existing POSITIONs in *this are undisturbed, including p.
 | |
|     */
 | |
|     protected:
 | |
|     __out_opt POSITION AddBeforeI(__in_opt POSITION p, __in void * pObj);
 | |
|     public:
 | |
| 
 | |
|     /* Add the list *pList to *this before position p in *this
 | |
|        AddAfter(NULL,x) adds x to the start - equivalent to AddHead
 | |
|        Return TRUE if it all worked, FALSE if it didn't.
 | |
|        If it fails, some of the objects may be added
 | |
|        Existing POSITIONs in *this are undisturbed, including p.
 | |
|     */
 | |
|     BOOL AddBefore(__in_opt POSITION p, __in CBaseList *pList);
 | |
| 
 | |
| 
 | |
|     /* Note that AddAfter(p,x) is equivalent to AddBefore(Next(p),x)
 | |
|        even in cases where p is NULL or Next(p) is NULL.
 | |
|        Similarly for mirror images etc.
 | |
|        This may make it easier to argue about programs.
 | |
|     */
 | |
| 
 | |
| 
 | |
| 
 | |
|     /* The following operations do not copy any elements.
 | |
|        They move existing blocks of elements around by switching pointers.
 | |
|        They are fairly efficient for long lists as for short lists.
 | |
|        (Alas, the Count slows things down).
 | |
| 
 | |
|        They split the list into two parts.
 | |
|        One part remains as the original list, the other part
 | |
|        is appended to the second list.  There are eight possible
 | |
|        variations:
 | |
|        Split the list {after/before} a given element
 | |
|        keep the {head/tail} portion in the original list
 | |
|        append the rest to the {head/tail} of the new list.
 | |
| 
 | |
|        Since After is strictly equivalent to Before Next
 | |
|        we are not in serious need of the Before/After variants.
 | |
|        That leaves only four.
 | |
| 
 | |
|        If you are processing a list left to right and dumping
 | |
|        the bits that you have processed into another list as
 | |
|        you go, the Tail/Tail variant gives the most natural result.
 | |
|        If you are processing in reverse order, Head/Head is best.
 | |
| 
 | |
|        By using NULL positions and empty lists judiciously either
 | |
|        of the other two can be built up in two operations.
 | |
| 
 | |
|        The definition of NULL (see Next/Prev etc) means that
 | |
|        degenerate cases include
 | |
|           "move all elements to new list"
 | |
|           "Split a list into two lists"
 | |
|           "Concatenate two lists"
 | |
|           (and quite a few no-ops)
 | |
| 
 | |
|        !!WARNING!! The type checking won't buy you much if you get list
 | |
|        positions muddled up - e.g. use a POSITION that's in a different
 | |
|        list and see what a mess you get!
 | |
|     */
 | |
| 
 | |
|     /* Split *this after position p in *this
 | |
|        Retain as *this the tail portion of the original *this
 | |
|        Add the head portion to the tail end of *pList
 | |
|        Return TRUE if it all worked, FALSE if it didn't.
 | |
| 
 | |
|        e.g.
 | |
|           foo->MoveToTail(foo->GetHeadPosition(), bar);
 | |
|               moves one element from the head of foo to the tail of bar
 | |
|           foo->MoveToTail(NULL, bar);
 | |
|               is a no-op, returns NULL
 | |
|           foo->MoveToTail(foo->GetTailPosition, bar);
 | |
|               concatenates foo onto the end of bar and empties foo.
 | |
| 
 | |
|        A better, except excessively long name might be
 | |
|            MoveElementsFromHeadThroughPositionToOtherTail
 | |
|     */
 | |
|     BOOL MoveToTail(__in_opt POSITION pos, __in CBaseList *pList);
 | |
| 
 | |
| 
 | |
|     /* Mirror image:
 | |
|        Split *this before position p in *this.
 | |
|        Retain in *this the head portion of the original *this
 | |
|        Add the tail portion to the start (i.e. head) of *pList
 | |
| 
 | |
|        e.g.
 | |
|           foo->MoveToHead(foo->GetTailPosition(), bar);
 | |
|               moves one element from the tail of foo to the head of bar
 | |
|           foo->MoveToHead(NULL, bar);
 | |
|               is a no-op, returns NULL
 | |
|           foo->MoveToHead(foo->GetHeadPosition, bar);
 | |
|               concatenates foo onto the start of bar and empties foo.
 | |
|     */
 | |
|     BOOL MoveToHead(__in_opt POSITION pos, __in CBaseList *pList);
 | |
| 
 | |
| 
 | |
|     /* Reverse the order of the [pointers to] objects in *this
 | |
|     */
 | |
|     void Reverse();
 | |
| 
 | |
| 
 | |
|     /* set cursor to the position of each element of list in turn  */
 | |
|     #define TRAVERSELIST(list, cursor)               \
 | |
|     for ( cursor = (list).GetHeadPosition()           \
 | |
|         ; cursor!=NULL                               \
 | |
|         ; cursor = (list).Next(cursor)                \
 | |
|         )
 | |
| 
 | |
| 
 | |
|     /* set cursor to the position of each element of list in turn
 | |
|        in reverse order
 | |
|     */
 | |
|     #define REVERSETRAVERSELIST(list, cursor)        \
 | |
|     for ( cursor = (list).GetTailPosition()           \
 | |
|         ; cursor!=NULL                               \
 | |
|         ; cursor = (list).Prev(cursor)                \
 | |
|         )
 | |
| 
 | |
| }; // end of class declaration
 | |
| 
 | |
| template<class OBJECT> class CGenericList : public CBaseList
 | |
| {
 | |
| public:
 | |
|     CGenericList(__in_opt LPCTSTR pName,
 | |
|                  INT iItems,
 | |
|                  BOOL bLock = TRUE,
 | |
|                  BOOL bAlert = FALSE) :
 | |
|                      CBaseList(pName, iItems) {
 | |
|         UNREFERENCED_PARAMETER(bAlert);
 | |
|         UNREFERENCED_PARAMETER(bLock);
 | |
|     };
 | |
|     CGenericList(__in_opt LPCTSTR pName) :
 | |
|                      CBaseList(pName) {
 | |
|     };
 | |
| 
 | |
|     __out_opt POSITION GetHeadPosition() const { return (POSITION)m_pFirst; }
 | |
|     __out_opt POSITION GetTailPosition() const { return (POSITION)m_pLast; }
 | |
|     int GetCount() const { return m_Count; }
 | |
| 
 | |
|     __out OBJECT *GetNext(__inout POSITION& rp) const { return (OBJECT *) GetNextI(rp); }
 | |
| 
 | |
|     __out_opt OBJECT *Get(__in_opt POSITION p) const { return (OBJECT *) GetI(p); }
 | |
|     __out OBJECT *GetValid(__in POSITION p) const { return (OBJECT *) GetValidI(p); }
 | |
|     __out_opt OBJECT *GetHead() const  { return Get(GetHeadPosition()); }
 | |
| 
 | |
|     __out_opt OBJECT *RemoveHead() { return (OBJECT *) RemoveHeadI(); }
 | |
| 
 | |
|     __out_opt OBJECT *RemoveTail() { return (OBJECT *) RemoveTailI(); }
 | |
| 
 | |
|     __out_opt OBJECT *Remove(__in_opt POSITION p) { return (OBJECT *) RemoveI(p); }
 | |
|     __out_opt POSITION AddBefore(__in_opt POSITION p, __in OBJECT * pObj) { return AddBeforeI(p, pObj); }
 | |
|     __out_opt POSITION AddAfter(__in_opt POSITION p, __in OBJECT * pObj)  { return AddAfterI(p, pObj); }
 | |
|     __out_opt POSITION AddHead(__in OBJECT * pObj) { return AddHeadI(pObj); }
 | |
|     __out_opt POSITION AddTail(__in OBJECT * pObj)  { return AddTailI(pObj); }
 | |
|     BOOL AddTail(__in CGenericList<OBJECT> *pList)
 | |
|             { return CBaseList::AddTail((CBaseList *) pList); }
 | |
|     BOOL AddHead(__in CGenericList<OBJECT> *pList)
 | |
|             { return CBaseList::AddHead((CBaseList *) pList); }
 | |
|     BOOL AddAfter(__in_opt POSITION p, __in CGenericList<OBJECT> *pList)
 | |
|             { return CBaseList::AddAfter(p, (CBaseList *) pList); };
 | |
|     BOOL AddBefore(__in_opt POSITION p, __in CGenericList<OBJECT> *pList)
 | |
|             { return CBaseList::AddBefore(p, (CBaseList *) pList); };
 | |
|     __out_opt POSITION Find( __in OBJECT * pObj) const { return FindI(pObj); }
 | |
| }; // end of class declaration
 | |
| 
 | |
| 
 | |
| 
 | |
| /* These define the standard list types */
 | |
| 
 | |
| typedef CGenericList<CBaseObject> CBaseObjectList;
 | |
| typedef CGenericList<IUnknown> CBaseInterfaceList;
 | |
| 
 | |
| #endif /* __WXLIST__ */
 | |
| 
 |