summaryrefslogtreecommitdiffstats
path: root/thirdparties/win32/include/directshow/wxlist.h
blob: 7487f61debd46254c0253fdc97fce7e538d38274 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
//------------------------------------------------------------------------------
// File: WXList.h
//
// Desc: DirectShow base classes - defines a non-MFC generic template list
//       class.
//
// Copyright (c) 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 */
        CNode *Prev() const { return m_pPrev; };


        /* Return the next node after this one */
        CNode *Next() const { return m_pNext; };


        /* Set the previous node before this one */
        void SetPrev(CNode *p) { m_pPrev = p; };


        /* Set the next node after this one */
        void SetNext(CNode *p) { m_pNext = p; };


        /* Get the pointer to the object for this node */
        void *GetData() const { return m_pObject; };


        /* Set the pointer to the object for this node */
        void SetData(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(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(TCHAR *pName,
              INT iItems);

    CBaseList(TCHAR *pName);
#ifdef UNICODE
    CBaseList(CHAR *pName,
              INT iItems);

    CBaseList(CHAR *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 */
    POSITION GetHeadPositionI() const;


    /* Return a cursor which identifies the last element of *this */
    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.
    */
    void *GetNextI(POSITION& rp) const;


    /* Return a pointer to the object at p
       Asking for the object at NULL will return NULL harmlessly.
    */
    void *GetI(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.
    */
    POSITION Next(POSITION pos) const
    {
        if (pos == NULL) {
            return (POSITION) m_pFirst;
        }
        CNode *pn = (CNode *) pos;
        return (POSITION) pn->Next();
    } //Next

    // See Next
    POSITION Prev(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:
    POSITION FindI( void * pObj) const;

    /* 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.
    */
    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.
    */
    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.
    */
    void *RemoveI(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
    */
    POSITION AddTailI(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(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:
    POSITION AddHeadI(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(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:
    POSITION AddAfterI(POSITION p, 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(POSITION p, 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:
    POSITION AddBeforeI(POSITION p, 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(POSITION p, 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(POSITION pos, 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(POSITION pos, 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(TCHAR *pName,
                 INT iItems,
                 BOOL bLock = TRUE,
                 BOOL bAlert = FALSE) :
                     CBaseList(pName, iItems) {
        UNREFERENCED_PARAMETER(bAlert);
        UNREFERENCED_PARAMETER(bLock);
    };
    CGenericList(TCHAR *pName) :
                     CBaseList(pName) {
    };

    POSITION GetHeadPosition() const { return (POSITION)m_pFirst; }
    POSITION GetTailPosition() const { return (POSITION)m_pLast; }
    int GetCount() const { return m_Count; }

    OBJECT *GetNext(POSITION& rp) const { return (OBJECT *) GetNextI(rp); }

    OBJECT *Get(POSITION p) const { return (OBJECT *) GetI(p); }
    OBJECT *GetHead() const  { return Get(GetHeadPosition()); }

    OBJECT *RemoveHead() { return (OBJECT *) RemoveHeadI(); }

    OBJECT *RemoveTail() { return (OBJECT *) RemoveTailI(); }

    OBJECT *Remove(POSITION p) { return (OBJECT *) RemoveI(p); }
    POSITION AddBefore(POSITION p, OBJECT * pObj) { return AddBeforeI(p, pObj); }
    POSITION AddAfter(POSITION p, OBJECT * pObj)  { return AddAfterI(p, pObj); }
    POSITION AddHead(OBJECT * pObj) { return AddHeadI(pObj); }
    POSITION AddTail(OBJECT * pObj)  { return AddTailI(pObj); }
    BOOL AddTail(CGenericList<OBJECT> *pList)
            { return CBaseList::AddTail((CBaseList *) pList); }
    BOOL AddHead(CGenericList<OBJECT> *pList)
            { return CBaseList::AddHead((CBaseList *) pList); }
    BOOL AddAfter(POSITION p, CGenericList<OBJECT> *pList)
            { return CBaseList::AddAfter(p, (CBaseList *) pList); };
    BOOL AddBefore(POSITION p, CGenericList<OBJECT> *pList)
            { return CBaseList::AddBefore(p, (CBaseList *) pList); };
    POSITION Find( 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__ */

OpenPOWER on IntegriCloud