uLib  User mode C/C++ extended API library for Win32 programmers.
ListCls.cpp
Go to the documentation of this file.
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 // Project: uLib - Utility library.
3 // Module: Enhanced double-linked list class.
4 // Author: Copyright (c) Love Nystrom
5 // License: NNOSL (BSD descendant, see NNOSL.txt in the base directory).
6 // Credits:
7 // Someone on Microsoft's kernel team for the original ntddk macros.
8 // Unknown@GeeksForGeeks.org Original ideas for QuickSort.
9 // KeremSahin@ideone.com Original ideas for QuickSort.
10 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11 
12 // NOTA BENE: Contributors - ListCls.cpp and it's siblings can NOT use general
13 // Win32 stuff from uLib like Debug.h or StrFunc.h, because DLinkList must
14 // maintain _cross-platform build ability_.
15 
16 #define ListFunc_Internal // Includes internal defines (currently unused)
17 #include <uLib/ListFunc.h>
18 #include <assert.h>
19 
20 //-----------------------------------------------------------------------------
21 
22 #if (defined(_DEBUG) && defined(_WIN32) && defined(_MSC_VER))
23  #define DBG_LIST 1 /* enable this to add som sanity checking for bug hunts */
24 
25  // Caveat Emptor: This ought not even be here, since it's Win32 specific.
26  // If you absolutely need to debug DLinkList on another platform,
27  // be sure you have facsimile implementations of the used Win32 functions.
28  // E.g #define IsBadReadPtr( addr,len ) false, or your real McCoy, et c.
29  // You'll need these:
30  // BOOL IsBadReadPtr( __in const PVOID lpData, __in UINT_PTR cbData );
31  // BOOL IsBadWritePtr( __in PVOID lpData, __in UINT_PTR cbData );
32  // void OutputDebugString( __in_opt LPCTSTR lpOutputString );
33  // LN
34 
35  static bool IsBadRWPtr( PVOID Addr, UINT Len )
36  {
37  BOOL isBad = IsBadReadPtr( Addr, Len ); // Win32
38  if (!isBad) isBad = IsBadWritePtr( Addr, Len ); // Win32
39  return !!isBad;
40  }
41  #include <tchar.h>
42  #include <stdio.h>
43  #define DP_ERROR 3
44  #define DP_WARNING 4
45  #define DP_DEBUG 6
46  #define _F(s) _T("[%s] ") _T(s), __FUNCTION__
47  #ifndef dimof
48  #define dimof(x) (sizeof(x)/sizeof(x[0]))
49  #endif
50  static void __cdecl DPrint( UINT Lv, PCTSTR Txt, ... )
51  {
52  va_list va;
53  TCHAR szBuf[256];
54  (void)&Lv; // unused
55  va_start( va, Txt );
56  #pragma warning( disable: 4996 )
57  _vsntprintf( szBuf, dimof(szBuf), Txt, va );
58  #pragma warning( default: 4996 )
59  va_end( va );
60  OutputDebugString( szBuf ); // Win32
61  }
62 #else
63  #define DBG_LIST 0
64 #endif
65 
66 //-----------------------------------------------------------------------------
67 // C++ double-linked list class - optimal
68 //-----------------------------------------------------------------------------
69 
71 {
72  _InitializeListHead( this ); // Flink = Blink = this;
73  SafeRemove = Safe;
74  Count = 0;
75 }
76 
77 DLinkList::DLinkList( PLIST_ENTRY ListHead, bool Safe ) // Pick up a plain DDK list.
78 {
79  SafeRemove = Safe;
80  _grabList( ListHead );
81 }
82 
84 {
85  #if DBG_LIST
86  if (Count) DPrint( DP_WARNING, _F("Deleting list with %lu items remaining!\n"), Count );
87  #endif
88 }
89 
90 PLIST_ENTRY DLinkList::Append( PLIST_ENTRY Entry ) // InsertTailList
91 {
92  if (Entry)
93  {
94  Entry->Flink = this;
95  Entry->Blink = Blink;
96  Blink->Flink = Entry;
97  this-> Blink = Entry;
98  Count++;
99  }
100  return Entry;
101 }
102 
103 PLIST_ENTRY DLinkList::Prepend( PLIST_ENTRY Entry ) // InsertHeadList
104 {
105  if (Entry)
106  {
107  Entry->Flink = Flink;
108  Entry->Blink = this;
109  Flink->Blink = Entry;
110  this-> Flink = Entry;
111  Count++;
112  }
113  return Entry;
114 }
115 
116 UINT DLinkList::AppendList( IN PLIST_ENTRY ListToAppend, OPTOUT PLIST_ENTRY* ppFirst ) // preliminary
117 {
118  // ListToAppend is the *head* of the list to append.
119 
120  if (_IsListEmpty( ListToAppend )) return 0;
121 
122  PLIST_ENTRY FirstEntry = ListToAppend->Flink;
123  PLIST_ENTRY LastEntry = ListToAppend->Blink;
124 
125  LastEntry->Flink = this;
126  FirstEntry->Blink = Blink;
127  Blink->Flink = FirstEntry;
128  Blink = LastEntry;
129 
130  UINT nrAdded = 0; // Count the added list items.
131  for( PLIST_ENTRY Entry = FirstEntry; Entry != this; nrAdded++, Entry = Entry->Flink );
132  Count += nrAdded;
133 
134  _InitializeListHead( ListToAppend ); // The list doesn't belong there anymore.
135  if (ppFirst) *ppFirst = FirstEntry;
136  return nrAdded;
137 }
138 
139 UINT DLinkList::AppendList( IN PDLinkList ListToAppend, OPTOUT PLIST_ENTRY* ppFirst ) // preliminary
140 {
141  ListToAppend->Count = 0; // In this case it's safe to zero the source in advance.
142  return AppendList( (PLIST_ENTRY)ListToAppend, ppFirst );
143 }
144 
145 bool DLinkList::Exist( PLIST_ENTRY Entry ) // true if Entry found in list
146 {
147  if (Entry)
148  {
149  #if DBG_LIST // Do some sanity check on behalf of the caller..
150  // If these occur in uLib itself, there is a broken implementation.
151  // If they occur in the caller's code, it's their own responsibility.
152  if (IsBadRWPtr( Entry, sizeof(LIST_ENTRY) ))
153  {
154  DPrint( DP_ERROR, _F("R/W Error: %p\n"), Entry );
155  goto __notFound;
156  }
157  #ifdef _MSC_VER
158  // Detect double deletion, which would demand SEH handling
159  // that is NOT available in GCC and other open source compilers.
160  #ifdef _WIN64
161  static const void* _TAG = (void*) 0xfeeefeeefeeefeee; // vs2oo8
162  #else
163  static const void* _TAG = (void*) 0xfeeefeee; // vs2oo8
164  #endif
165  bool deleted = (Entry == _TAG);
166  if (!deleted) deleted = (Entry->Flink == _TAG) || (Entry->Blink == _TAG);
167  if (deleted)
168  {
169  DPrint( DP_ERROR, _F("Deleted entry: %p\n"), Entry );
170  goto __notFound;
171  }
172  #endif //_MSC_VER
173  #endif //DBG_LIST
174 
175  PLIST_ENTRY Item = Flink;
176  while( Item != this )
177  {
178  if (Item == Entry) return true; // Found
179  Item = Item->Flink;
180  }
181 
182  #if DBG_LIST
183  __notFound: ((void)0); // MSVC don't accept a label directly before an end brace.
184  #endif
185  }
186  return false; // NULL Entry, empty list, or Not found
187 }
188 
189 // GetNext() and GetPrev() provides *fully circular* access to the list.
190 
192 {
193  PLIST_ENTRY next = NULL;
194  if (!IsEmpty())
195  {
196  next = Current->Flink;
197  if (next == this) next = Flink; // Wrap around to beginning of list.
198  }
199  return next;
200 }
201 
203 {
204  PLIST_ENTRY next = NULL;
205  if (!IsEmpty())
206  {
207  next = Current->Blink;
208  if (next == this) next = Blink; // Wrap around to end of list.
209  }
210  return next;
211 }
212 
214 {
215  if (Entry)
216  {
217  if (SafeRemove && !Exist( Entry )) Entry = NULL;
218  else
219  {
220  PLIST_ENTRY _Flink = Entry->Flink;
221  PLIST_ENTRY _Blink = Entry->Blink;
222  _Blink->Flink = _Flink;
223  _Flink->Blink = _Blink;
224  Count--;
225  UnlinkListEntry( Entry );
226  }
227  }
228  return Entry;
229 }
230 
232 {
233  return RemoveEntry( Flink );
234 }
235 
237 {
238  return RemoveEntry( Blink );
239 }
240 
241 void DLinkList::RemoveAll( PDListFunc ItemAction, void* UserData )
242 {
243  if (ItemAction) while( Flink != this )
244  {
245  #if 0
246  if (!ItemAction( RemoveFirst(), UserData )) break; // Abort if user rtn false.
247  #else // Retain the entry for which the callback returned false.
248  PLIST_ENTRY item = RemoveFirst();
249  #if 0
250  if ( !item )
251  {
252  // This should not be possible, since RemoveFirst always calls
253  // RemoveEntry with an item that *is* in the list, i.e. Exist()==true.
254  // If it was NULL for some obscure reason, it would have been
255  // rejected already when attempting to add it to the list.
256  DPrint( DP_ERROR, _F("NULL Flink found. Check your code!\n"));
257  break;
258  }
259  #endif
260  if ( !ItemAction( item, UserData ))
261  {
262  Prepend( item ); // Put it back where it came from.
263  break; // User returned false, so abort enumeration.
264  }
265  #endif
266  }
267  else
268  {
269  // Caller didn't provide an action callback, so there's nothing to do
270  // except clearing the list. Traversing through RemoveEntry is superfluous.
271 
272  _InitializeListHead( this ); // i.e. while( Flink != this ) RemoveFirst();
273  Count = 0;
274  }
275 }
276 
278 {
279  if (IsEmpty()) return NULL;
280  for( PLIST_ENTRY Entry = Flink; Entry != this; Entry = Entry->Flink, Index-- )
281  if (Index == 0) return Entry;
282  return NULL;
283 }
284 
285 // The arrangement of the loop makes these iterators tolerant to Entry removal.
286 
288 {
289  if (!IsEmpty())
290  {
291  PLIST_ENTRY Entry = Flink;
292  while( Entry != this )
293  {
294  PLIST_ENTRY Next = Entry->Flink; // Preload, in case Match removes Entry.
295  if (Match( Entry, UserData )) return Entry;
296  Entry = Next;
297  }
298  }
299  return NULL;
300 }
301 
303 {
304  if (!IsEmpty())
305  {
306  PLIST_ENTRY Entry = Blink;
307  while( Entry != this )
308  {
309  PLIST_ENTRY Next = Entry->Blink;
310  if (Match( Entry, UserData )) return Entry;
311  Entry = Next;
312  }
313  }
314  return NULL;
315 }
316 
317 bool DLinkList::ForEach( PDListFunc Action, void* UserData )
318 {
319  if (IsEmpty()) return false;
320  PLIST_ENTRY Entry = Flink;
321  while( Entry != this )
322  {
323  PLIST_ENTRY Next = Entry->Flink;
324  if (!Action( Entry, UserData )) return false;
325  Entry = Next;
326  }
327  return true;
328 }
329 
330 // Quicksort by swapping links, not swapping node data.
331 // White magic based on code adapted from:
332 // Unknown@GeeksForGeeks.org
333 // KeremSahin@ideone.com
334 
335 void DLinkList::QuickSort( PDListComp Compare, void* Context )
336 {
337  // if ((Flink != this) && (Flink->Flink != this)) // If more than one entry..
338  if (Count > 1) _qsortRecursion( &Flink, &Blink, Compare, Context );
339 }
340 
341 void DLinkList::_qsortRecursion(
342  PLIST_ENTRY *ppHead, PLIST_ENTRY *ppTail, PDListComp Compare, void* Context )
343 {
344  // Quicksort recursion, protected
345 
346  PLIST_ENTRY pPivot = *ppTail;
347 
348  if ((*ppHead != this) && (*ppTail != this) && (*ppHead != *ppTail))
349  {
350  _qsortPartition( ppHead, ppTail, Compare, Context ); // Partition
351  _qsortRecursion( ppHead, &(pPivot->Blink), Compare, Context ); // Sort left part
352  _qsortRecursion( &(pPivot->Flink), ppTail, Compare, Context ); // Sort right part
353 
354  // Connect pivot to left & right parts
355 
356  if (pPivot->Blink != this)
357  pPivot->Blink->Flink = pPivot;
358 
359  if (pPivot->Flink != this)
360  pPivot->Flink->Blink = pPivot;
361  }
362 }
363 
364 void DLinkList::_qsortPartition(
365  PLIST_ENTRY *ppHead, PLIST_ENTRY *ppTail, PDListComp Compare, void* Context )
366 {
367  // Quicksort partitioning, protected
368 
369  PLIST_ENTRY pNewTail = NULL;
370  PLIST_ENTRY pCurr = *ppHead;
371  PLIST_ENTRY pPivot = *ppTail;
372 
373  while( pCurr != pPivot )
374  {
375  int cmp = Compare( pCurr, pPivot, Context );
376  if (cmp > 0) // using normal C tristate comparison value -x/0/+x
377  {
378  if (pCurr->Blink != this)
379  pCurr->Blink->Flink = pCurr->Flink;
380 
381  if (pCurr->Flink != this)
382  pCurr->Flink->Blink = pCurr->Blink;
383 
384  pNewTail = pCurr;
385  pCurr = pCurr->Flink;
386  if (pCurr->Blink == this)
387  *ppHead = pCurr;
388 
389  pNewTail->Blink = *ppTail;
390  pNewTail->Flink = this;
391  (*ppTail)->Flink = pNewTail;
392  *ppTail = pNewTail;
393  }
394  else
395  pCurr = pCurr->Flink;
396  }
397 
398  if (pPivot->Blink != this)
399  pPivot->Blink->Flink = this;
400 
401  if (pPivot->Flink != this)
402  pPivot->Flink->Blink = this;
403 }
404 
405 // Specials - Export/Import to/from listheads and headless lists
406 
408 {
409  // Fail if this is not empty, or the other list is empty.
410  if (!IsEmpty() || _IsListEmpty( SrcListHead )) return NULL;
411  _grabList( SrcListHead );
412  return this;
413 }
414 
415 void DLinkList::_grabList( PLIST_ENTRY ListHead )
416 {
417  if (_IsListEmpty( ListHead ))
418  _InitializeListHead( this );
419  else
420  {
421  Flink = ListHead->Flink; // Pick up the list.
422  Blink = ListHead->Blink; // -"-
423  Blink->Flink = Flink->Blink = this; // Change list head.
424  // This side effect is deliberate, to prevent cross-link errors...
425  _InitializeListHead( ListHead ); // The list doesn't belong to ListHead anymore.
426  }
427  PLIST_ENTRY Entry = Flink; // Count the list items.
428  for( Count = 0; Entry != this; Count++, Entry = Entry->Flink );
429 }
430 
431 UINT DLinkList::ExportToListHead( PLIST_ENTRY ListHead OUT ) // Complement to c'tor 2.
432 {
433  UINT nrEntries = 0;
434  if (ListHead)
435  {
436  ListHead->Flink = Flink;
437  ListHead->Blink = Blink;
438  ListHead->Blink->Flink = ListHead->Flink->Blink = ListHead;
439  _InitializeListHead( this ); // The list doesn't belong to this anymore.
440  nrEntries = Count;
441  Count = 0;
442  }
443  return nrEntries;
444 }
445 
447 {
448  UINT nrEntries = 0;
449  if (ListHead)
450  {
451  if (Count) nrEntries = AppendList( ListHead, ppFirst );
452  else
453  {
454  _grabList( ListHead );
455  if (ppFirst) *ppFirst = Flink;
456  nrEntries = Count;
457  }
458  }
459  return nrEntries;
460 }
461 
462 UINT DLinkList::ExportToHeadlessList( PLIST_ENTRY* Target OUT ) // Special
463 {
464  LIST_ENTRY Head;
465  PLIST_ENTRY FirstEntry = Flink;
466  UINT nrEntries = ExportToListHead( &Head );
467  _RemoveEntryList( &Head ); // Thus it becomes headless (aka. circular).
468  *Target = FirstEntry;
469  return nrEntries;
470 }
471 
472 UINT DLinkList::ImportHeadlessList( PLIST_ENTRY Circular, PLIST_ENTRY* ppFirst ) // Special
473 {
474  UINT nrAdded = 0;
475  if (Circular)
476  {
477  PLIST_ENTRY FirstEntry = Circular;
478  PLIST_ENTRY LastEntry = Circular->Blink;
479  PLIST_ENTRY Entry;
480 
481  if (!Count) // If empty, just usurp the circular list
482  {
483  Flink = FirstEntry;
484  Blink = LastEntry;
485  Blink->Flink = Flink->Blink = this;
486  }
487  else // Append the circular list to this
488  {
489  LastEntry->Flink = this;
490  FirstEntry->Blink = Blink;
491  Blink->Flink = FirstEntry;
492  Blink = LastEntry;
493  }
494  // Count the added list items.
495  for( Entry = FirstEntry; Entry != this; nrAdded++, Entry = Entry->Flink );
496  Count += nrAdded;
497  if (ppFirst) *ppFirst = FirstEntry;
498  }
499  return nrAdded;
500 }
501 
502 //-----------------------------------------------------------------------------
503 // Single link list
504 //-----------------------------------------------------------------------------
505 
506 #define SLIST_SPEEDY 0
507 
508 bool __forceinline SLinkList::IsEmpty()
509 {
510  #if SEMICIRCULAR_SLIST // Work in progress..
511  return (Next == this);
512  #else
513  return (Next == NULL);
514  #endif
515 }
516 
517 // PONDER: Finish implementing the SEMICIRCULAR_SLIST option..?
518 // Pro's? Con's? "Just because I can" doesn't feel like an adequate reason.
519 
521 {
522  if (Entry)
523  {
524  #if SLIST_SPEEDY
525  Entry->Next = Next;
526  Next = Entry;
527  #else // Call "transmutable" C function
528  _PushEntryList( this, Entry );
529  #endif
530  Count++;
531  }
532  return Entry;
533 }
534 
536 {
537  #if SLIST_SPEEDY
538  PSINGLE_LIST_ENTRY Entry = Next;
539  if (Entry != NULL)
540  {
541  Next = Entry->Next;
542  _InitializeEntryList( Entry ); // "Unlink" the entry.
543  Count--;
544  }
545  #else // Call "transmutable" C function
546  PSINGLE_LIST_ENTRY Entry = _PopEntryList( this );
547  if (Entry)
548  {
549  _InitializeEntryList( Entry ); // "Unlink" the entry.
550  Count--;
551  }
552  #endif
553  return Entry;
554 }
555 
557 {
558  if (Entry)
559  {
560  if (Next == NULL) // If list is empty
561  PushEntry( Entry );
562  else
563  {
564  PSINGLE_LIST_ENTRY item = Next;
565  while (item->Next != NULL) // Find the last entry
566  {
567  item = item->Next;
568  }
569  Entry->Next = item->Next; //= NULL;
570  item->Next = Entry;
571  Count++;
572  }
573  }
574  return Entry;
575 }
576 
578 {
579  if (!Entry || IsEmpty()) return NULL;
580 
581  PSINGLE_LIST_ENTRY Item = Next;
582  PSINGLE_LIST_ENTRY Prev = this;
583  while( Item != Entry )
584  {
585  Prev = Item;
586  Item = Item->Next;
587  if (!Item) return NULL;
588  }
589  Count--;
590  Prev->Next = Item->Next;
591  _InitializeEntryList( Item ); // "Unlink" the entry.
592  return Item;
593 }
594 
595 PSINGLE_LIST_ENTRY SLinkList::operator [] ( size_t Index ) // Indexed access (can be slow)
596 {
597  if (IsEmpty()) return NULL;
598  for( PSINGLE_LIST_ENTRY Entry = Next; Entry != NULL; Entry = Entry->Next, Index-- )
599  if (Index == 0) return Entry;
600  return NULL;
601 }
602 
603 void SLinkList::RemoveAll( PSListFunc ItemAction, void* UserData )
604 {
605  if (!ItemAction)
606  while( Next != NULL ) PopEntry();
607  else while( Next != NULL )
608  if (!ItemAction( PopEntry(), UserData )) break; // Abort if user rtn false.
609 }
610 
612 {
613  if (!IsEmpty())
614  {
615  PSINGLE_LIST_ENTRY Entry = Next;
616  while( Entry != NULL )
617  {
618  PSINGLE_LIST_ENTRY NextEntry = Entry->Next;
619  if (Match( Entry, UserData )) return Entry;
620  Entry = NextEntry;
621  }
622  }
623  return NULL;
624 }
625 
626 bool SLinkList::ForEach( PSListFunc Action, void* UserData )
627 {
628  if (IsEmpty()) return false;
629 
630  PSINGLE_LIST_ENTRY Entry = Next;
631  while( Entry != NULL )
632  {
633  PSINGLE_LIST_ENTRY NextEntry = Entry->Next;
634  if (!Action( Entry, UserData )) return false;
635  Entry = NextEntry;
636  }
637  return true;
638 }
639 
640 //-----------------------------------------------------------------------------
641 // EOF
PLIST_ENTRY FirstThat(PDListFunc Match, void *UserData=NULL)
Definition: ListCls.cpp:287
UINT ExportToListHead(PLIST_ENTRY ListHead)
Definition: ListCls.cpp:431
UINT Count
Definition: ListFunc.h:186
bool(__stdcall * PSListFunc)(PSINGLE_LIST_ENTRY Entry, void *UserData)
Definition: ListFunc.h:369
UINT ImportFromListHead(IN PLIST_ENTRY ListHead, OPTOUT PLIST_ENTRY *ppFirst)
Definition: ListCls.cpp:446
PLIST_ENTRY LastThat(PDListFunc Match, void *UserData=NULL)
Definition: ListCls.cpp:302
PLIST_ENTRY operator [](size_t Index)
Definition: ListCls.cpp:277
void _InitializeEntryList(PSINGLE_LIST_ENTRY EntryOrHead)
Definition: ListFunc.c:143
UINT ImportHeadlessList(IN PLIST_ENTRY Circular, OPTOUT PLIST_ENTRY *ppFirst)
Definition: ListCls.cpp:472
bool Exist(PLIST_ENTRY Entry)
Definition: ListCls.cpp:145
bool ForEach(PDListFunc Action, void *UserData=NULL)
Definition: ListCls.cpp:317
#define dimof(x)
Definition: Common.h:949
#define OPTOUT
Definition: Common.h:264
void __cdecl DPrint(int Level, CSTR Fmt,...)
Definition: Debug.cpp:134
UINT AppendList(IN PLIST_ENTRY ListToAppend, OPTOUT PLIST_ENTRY *ppFirst)
Definition: ListCls.cpp:116
PLIST_ENTRY RemoveLast()
Definition: ListCls.cpp:236
struct _LIST_ENTRY * PLIST_ENTRY
bool(__stdcall * PDListFunc)(PLIST_ENTRY Entry, void *UserData)
Definition: ListFunc.h:152
DLinkList(bool Safe=true)
Definition: ListCls.cpp:70
#define UnlinkListEntry(E)
Definition: ListFunc.h:95
PLIST_ENTRY GetNext(PLIST_ENTRY Current)
Definition: ListCls.cpp:191
void _PushEntryList(PSINGLE_LIST_ENTRY ListHead, PSINGLE_LIST_ENTRY Entry)
Definition: ListFunc.c:151
PDLinkList operator=(PLIST_ENTRY ListHead)
Definition: ListCls.cpp:407
bool ForEach(PSListFunc Action, void *UserData=NULL)
Definition: ListCls.cpp:626
PLIST_ENTRY Prepend(PLIST_ENTRY Entry)
Definition: ListCls.cpp:103
BOOL(WINAPI *SysImgList::Shell_GetImageLists)(HIMAGELIST *pimlLarge
void RemoveAll(PSListFunc ItemAction, void *UserData=NULL)
Definition: ListCls.cpp:603
PLIST_ENTRY Append(PLIST_ENTRY Entry)
Definition: ListCls.cpp:90
int(__stdcall * PDListComp)(PLIST_ENTRY X, PLIST_ENTRY Y, void *UserData)
Definition: ListFunc.h:159
void _InitializeListHead(PLIST_ENTRY ListHead)
Definition: ListFunc.c:17
void _RemoveEntryList(PLIST_ENTRY Entry)
Definition: ListFunc.c:47
void QuickSort(PDListComp Compare, void *UserData=NULL)
Definition: ListCls.cpp:335
struct _LIST_ENTRY * Blink
Definition: ListFunc.h:45
#define DP_ERROR
Definition: Debug.h:82
PSINGLE_LIST_ENTRY FirstThat(PSListFunc Match, void *UserData=NULL)
Definition: ListCls.cpp:611
bool IsEmpty()
Definition: ListFunc.h:225
bool __forceinline IsEmpty()
Definition: ListCls.cpp:508
struct _SINGLE_LIST_ENTRY * PSINGLE_LIST_ENTRY
PSINGLE_LIST_ENTRY Remove(PSINGLE_LIST_ENTRY Entry)
Definition: ListCls.cpp:577
void RemoveAll(PDListFunc ItemAction, void *UserData=NULL)
Definition: ListCls.cpp:241
class DLinkList * PDLinkList
Definition: ListFunc.h:143
bool _IsListEmpty(PLIST_ENTRY ListHead)
Definition: ListFunc.c:22
PSINGLE_LIST_ENTRY PopEntry()
Definition: ListCls.cpp:535
~DLinkList()
Definition: ListCls.cpp:83
PSINGLE_LIST_ENTRY _PopEntryList(PSINGLE_LIST_ENTRY ListHead)
Definition: ListFunc.c:156
PSINGLE_LIST_ENTRY operator [](size_t Index)
Definition: ListCls.cpp:595
UINT ExportToHeadlessList(PLIST_ENTRY *Circular)
Definition: ListCls.cpp:462
bool SafeRemove
Definition: ListFunc.h:187
PLIST_ENTRY RemoveFirst()
Definition: ListCls.cpp:231
PSINGLE_LIST_ENTRY Append(PSINGLE_LIST_ENTRY Entry)
Definition: ListCls.cpp:556
#define _F(s)
Definition: Debug.h:49
struct _SINGLE_LIST_ENTRY * Next
Definition: ListFunc.h:51
UINT Count
Definition: ListFunc.h:381
struct _LIST_ENTRY * Flink
Definition: ListFunc.h:44
PLIST_ENTRY RemoveEntry(PLIST_ENTRY Entry)
Definition: ListCls.cpp:213
#define DP_WARNING
Definition: Debug.h:83
PSINGLE_LIST_ENTRY PushEntry(PSINGLE_LIST_ENTRY Entry)
Definition: ListCls.cpp:520
PLIST_ENTRY GetPrev(PLIST_ENTRY Current)
Definition: ListCls.cpp:202