/* Copyright (c) 1997 Microsoft Corporation */ /* See the .C test code at the end of this file for examples of how to use this stuff. */ #ifndef _LISTS_H #define _LISTS_H #if __cplusplus extern "C" { #endif #define LIST_ROOT(name, type) struct name {struct type *Root;} #define LIST_MEMBER(type) struct { struct type **Prev; struct type *Next;} /* Note! Prev is the ADDRESS of the previous next element ptr */ #define LIST_INSERT_ROOT(root,element,field)\ { if(((element)->field.Next = (root)->Root) != 0)\ (root)->Root->field.Prev = &(element)->field.Next;\ (root)->Root = (element);\ (element)->field.Prev = &(root)->Root;\ } #define LIST_DELETE(element,field)\ {\ if((element)->field.Next)\ (element)->field.Next->field.Prev = (element)->field.Prev;\ *(element)->field.Prev = (element)->field.Next;\ (element)->field.Next = 0;\ (element)->field.Prev = 0;\ } #define LIST_INITIALIZE(root)\ {\ (root)->Root = 0;\ } #define LIST_INITIALIZE_MEMBER(element,field)\ { (element)->field.Next = 0;\ (element)->field.Prev = 0;\ } #define LIST_ORPHAN_MEMBER(element,field) (!((element)->field.Prev)) #define LIST_FIRST(root) (root)->Root #define LIST_NEXT(element,field) (element)->field.Next #define TAIL_QUEUE_INITIALIZE(root)\ {\ (root)->First = NULL;\ (root)->Last = &(root)->First;\ } #define TAIL_QUEUE_ROOT(name,type)\ struct name\ { struct type *First;\ struct type **Last;\ }/* NOTE! This is the address of the last Next pointer. */ #define TAIL_QUEUE_MEMBER(type)\ struct\ { struct type *Next;\ struct type **Prev; /* NOTE! Address of previous Next element ptr */\ } #define TAIL_QUEUE_INSERT_END(root,element,field)\ { (element)->field.Prev = (root)->Last;\ (element)->field.Next = 0;\ *(root)->Last = (element);\ (root)->Last = &(element)->field.Next;\ } #define TAIL_QUEUE_DELETE(root,element,field)\ {\ if (((element)->field.Next) != NULL)\ (element)->field.Next->field.Prev = (element)->field.Prev;\ else\ (root)->Last = (element)->field.Prev;\ *(element)->field.Prev = (element)->field.Next;\ (element)->field.Next = 0;\ (element)->field.Prev = 0;\ } #define TAIL_QUEUE_FIRST(root) (root)->First #define TAIL_QUEUE_NEXT(element,field) (element)->field.Next #define CIRCLE_QUEUE_ROOT(name,type)\ struct name\ { struct type *Last;\ struct type *First;\ } #define CIRCLE_QUEUE_MEMBER(type)\ struct\ { struct type *Prev;\ struct type *Next;\ } #define CIRCLE_QUEUE_INITIALIZE(root,type)\ { (root)->Last = (type *)(root);\ (root)->First = (type *)(root);\ } #define CIRCLE_QUEUE_INITIALIZE_MEMBER(element,field)\ { (element)->field.Next = (element)->field.Prev = 0;\ } #define CIRCLE_QUEUE_INSERT_END(root,type,element,field)\ { (element)->field.Prev = (root)->Last;\ (element)->field.Next = (type *)(root);\ if((root)->First != (type *)(root))\ (root)->Last->field.Next = (element);\ else\ (root)->First = (element);\ (root)->Last = (element);\ } #define CIRCLE_QUEUE_INSERT_ROOT(root,type,element,field)\ { (element)->field.Prev = (type *)(root);\ (element)->field.Next = (root)->First;\ if ((root)->Last != (void *)(root))\ (root)->First->field.Prev = (element);\ else\ (root)->Last = (element);\ (root)->First = (element);\ } #define CIRCLE_QUEUE_INSERT_PREVIOUS(root,current_element,element,field)\ { (element)->field.Prev = (current_element)->field.Prev;\ (element)->field.Next = (current_element);\ if ((current_element)->field.Prev != (void *)(root))\ (current_element)->field.Prev->field.Next = (element);\ else\ (root)->First = (element);\ (current_element)->field.Prev = (element);\ } #define CIRCLE_QUEUE_DELETE(root,element,field)\ { if((element)->field.Next != (void *)(root))\ (element)->field.Next->field.Prev = (element)->field.Prev;\ else\ (root)->Last = (element)->field.Prev;\ if((element)->field.Prev != (void *)(root))\ (element)->field.Prev->field.Next = (element)->field.Next;\ else\ (root)->First = (element)->field.Next;\ (element)->field.Next = 0;\ (element)->field.Prev = 0;\ } #define CIRCLE_QUEUE_FIRST(root)\ ((root)->First == (void *) (root)? 0: (root)->First) #define CIRCLE_QUEUE_LAST(root)\ ((root)->Last == (void *) (root)? 0: (root)->Last) #define CIRCLE_QUEUE_NEXT(root,element,field)\ ((void *) (element)->field.Next == (void *) (root)? 0: (element)->field.Next) #define CIRCLE_QUEUE_PREVIOUS(root,element,field)\ ((element)->field.Prev == (void *) (root)? 0: (element)->field.Prev) #if 0 /* Test code. Strip it out, put it in a .C (or .CPP) file and compile it as a console app to test this stuff. It should run without any assertion failures. Also, use this as example code. */ #include #include #include #include "lists.h" void TestList(void) { struct Foo { int a; LIST_MEMBER(Foo) ListStuff; int b; }; struct Foo MyFoo1, MyFoo2, MyFoo3, *pFoo = 0; LIST_ROOT(sRoot, Foo) MyListRoot; fputs("Testing LIST.\n",stdout); LIST_INITIALIZE(&MyListRoot); LIST_INITIALIZE_MEMBER(&MyFoo1,ListStuff); MyFoo1.a = 0x1A; MyFoo1.b = 0x1B; LIST_INITIALIZE_MEMBER(&MyFoo2,ListStuff); MyFoo2.a = 0x2A; MyFoo2.b = 0x2B; LIST_INITIALIZE_MEMBER(&MyFoo3,ListStuff); MyFoo3.a = 0x3A; MyFoo3.b = 0x3B; assert(LIST_ORPHAN_MEMBER(&MyFoo3,ListStuff)); LIST_INSERT_ROOT(&MyListRoot,&MyFoo3,ListStuff); assert(!LIST_ORPHAN_MEMBER(&MyFoo3,ListStuff)); LIST_INSERT_ROOT(&MyListRoot,&MyFoo2,ListStuff); LIST_INSERT_ROOT(&MyListRoot,&MyFoo1,ListStuff); assert(!LIST_ORPHAN_MEMBER(&MyFoo1,ListStuff)); assert(!LIST_ORPHAN_MEMBER(&MyFoo2,ListStuff)); assert(!LIST_ORPHAN_MEMBER(&MyFoo3,ListStuff)); pFoo = LIST_FIRST(&MyListRoot); assert(pFoo); assert(pFoo->a == 0x1A); assert(pFoo->b == 0x1B); pFoo = LIST_NEXT(pFoo,ListStuff); assert(pFoo); assert(pFoo->a == 0x2A); assert(pFoo->b == 0x2B); pFoo = LIST_NEXT(pFoo,ListStuff); assert(pFoo); assert(pFoo->a == 0x3A); assert(pFoo->b == 0x3B); pFoo = LIST_NEXT(pFoo,ListStuff); assert(pFoo == 0); /* Delete member 2. */ pFoo = LIST_FIRST(&MyListRoot); pFoo = LIST_NEXT(pFoo,ListStuff); LIST_DELETE(pFoo,ListStuff); assert(pFoo->a == 0x2A);/* Make sure we have the right member. */ assert(pFoo->b == 0x2B);/* And the data is intact. */ assert(LIST_NEXT(pFoo,ListStuff) == 0); /* Make sure that there are only members 1 and 3 in the list now. */ pFoo = LIST_FIRST(&MyListRoot); assert(pFoo); assert(pFoo->a == 0x1A); assert(pFoo->b == 0x1B); pFoo = LIST_NEXT(pFoo,ListStuff); assert(pFoo); assert(pFoo->a == 0x3A); assert(pFoo->b == 0x3B); assert(LIST_NEXT(pFoo,ListStuff) == 0); /* Delete member 3. */ pFoo = LIST_FIRST(&MyListRoot); pFoo = LIST_NEXT(pFoo,ListStuff); LIST_DELETE(pFoo,ListStuff); assert(pFoo->a == 0x3A);/* Make sure we have the right member. */ assert(pFoo->b == 0x3B);/* And the data is intact. */ assert(LIST_NEXT(pFoo,ListStuff) == 0); /* Delete member 1. */ pFoo = LIST_FIRST(&MyListRoot); LIST_DELETE(pFoo,ListStuff); assert(pFoo->a == 0x1A);/* Make sure we have the right member. */ assert(pFoo->b == 0x1B);/* And the data is intact. */ assert(LIST_NEXT(pFoo,ListStuff) == 0); assert(LIST_FIRST(&MyListRoot) == 0); LIST_INSERT_ROOT(&MyListRoot,&MyFoo2,ListStuff); LIST_INSERT_ROOT(&MyListRoot,&MyFoo1,ListStuff); /* Delete member 1 while there are other members in the list. */ pFoo = LIST_FIRST(&MyListRoot); LIST_DELETE(pFoo,ListStuff); assert(pFoo->a == 0x1A);/* Make sure we have the right member. */ assert(pFoo->b == 0x1B);/* And the data is intact. */ assert(LIST_NEXT(pFoo,ListStuff) == 0); assert(LIST_FIRST(&MyListRoot) == &MyFoo2); assert(MyFoo1.a == 0x1A); assert(MyFoo1.b == 0x1B); assert(MyFoo2.a == 0x2A); assert(MyFoo2.b == 0x2B); assert(MyFoo3.a == 0x3A); assert(MyFoo3.b == 0x3B); fputs("List passed.\n", stdout); } void TestTailQueue(void) { struct Foo { int a; TAIL_QUEUE_MEMBER(Foo) TQStuff; int b; }; struct Foo MyFoo1, MyFoo2, MyFoo3, *pFoo = 0; TAIL_QUEUE_ROOT(sRoot, Foo) MyTQRoot; fputs("Testing TAIL_QUEUE.\n",stdout); TAIL_QUEUE_INITIALIZE(&MyTQRoot); MyFoo1.a = 0x1A; MyFoo1.b = 0x1B; MyFoo2.a = 0x2A; MyFoo2.b = 0x2B; MyFoo3.a = 0x3A; MyFoo3.b = 0x3B; TAIL_QUEUE_INSERT_END(&MyTQRoot,&MyFoo1,TQStuff); TAIL_QUEUE_INSERT_END(&MyTQRoot,&MyFoo2,TQStuff); TAIL_QUEUE_INSERT_END(&MyTQRoot,&MyFoo3,TQStuff); pFoo = TAIL_QUEUE_FIRST(&MyTQRoot); assert(pFoo); assert(pFoo->a == 0x1A); assert(pFoo->b == 0x1B); pFoo = TAIL_QUEUE_NEXT(pFoo,TQStuff); assert(pFoo); assert(pFoo->a == 0x2A); assert(pFoo->b == 0x2B); pFoo = TAIL_QUEUE_NEXT(pFoo,TQStuff); assert(pFoo); assert(pFoo->a == 0x3A); assert(pFoo->b == 0x3B); pFoo = TAIL_QUEUE_NEXT(pFoo,TQStuff); assert(pFoo == 0); /* Delete member 2. */ pFoo = TAIL_QUEUE_FIRST(&MyTQRoot); pFoo = TAIL_QUEUE_NEXT(pFoo,TQStuff); TAIL_QUEUE_DELETE(&MyTQRoot,pFoo,TQStuff); assert(pFoo->a == 0x2A);/* Make sure we have the right member. */ assert(pFoo->b == 0x2B);/* And the data is intact. */ assert(TAIL_QUEUE_NEXT(pFoo,TQStuff) == 0); /* Make sure that there are only members 1 and 3 in the list now. */ pFoo = TAIL_QUEUE_FIRST(&MyTQRoot); assert(pFoo); assert(pFoo->a == 0x1A); assert(pFoo->b == 0x1B); pFoo = TAIL_QUEUE_NEXT(pFoo,TQStuff); assert(pFoo); assert(pFoo->a == 0x3A); assert(pFoo->b == 0x3B); assert(TAIL_QUEUE_NEXT(pFoo,TQStuff) == 0); /* Delete member 3. */ pFoo = TAIL_QUEUE_FIRST(&MyTQRoot); pFoo = TAIL_QUEUE_NEXT(pFoo,TQStuff); TAIL_QUEUE_DELETE(&MyTQRoot,pFoo,TQStuff); assert(pFoo->a == 0x3A);/* Make sure we have the right member. */ assert(pFoo->b == 0x3B);/* And the data is intact. */ assert(TAIL_QUEUE_NEXT(pFoo,TQStuff) == 0); /* Delete member 1. */ pFoo = TAIL_QUEUE_FIRST(&MyTQRoot); TAIL_QUEUE_DELETE(&MyTQRoot,pFoo,TQStuff); assert(pFoo->a == 0x1A);/* Make sure we have the right member. */ assert(pFoo->b == 0x1B);/* And the data is intact. */ assert(TAIL_QUEUE_NEXT(pFoo,TQStuff) == 0); assert(TAIL_QUEUE_FIRST(&MyTQRoot) == 0); TAIL_QUEUE_INSERT_END(&MyTQRoot,&MyFoo1,TQStuff); TAIL_QUEUE_INSERT_END(&MyTQRoot,&MyFoo2,TQStuff); /* Delete member 1 while there are other members in the list. */ pFoo = TAIL_QUEUE_FIRST(&MyTQRoot); TAIL_QUEUE_DELETE(&MyTQRoot,pFoo,TQStuff); assert(pFoo->a == 0x1A);/* Make sure we have the right member. */ assert(pFoo->b == 0x1B);/* And the data is intact. */ assert(TAIL_QUEUE_NEXT(pFoo,TQStuff) == 0); assert(TAIL_QUEUE_FIRST(&MyTQRoot) == &MyFoo2); assert(MyFoo1.a == 0x1A); assert(MyFoo1.b == 0x1B); assert(MyFoo2.a == 0x2A); assert(MyFoo2.b == 0x2B); assert(MyFoo3.a == 0x3A); assert(MyFoo3.b == 0x3B); fputs("Tail Queue passed.\n", stdout); } void TestCircleQueue(void) { enum {END,ROOT,PREVIOUS,DONE} WhichInsert = END; int i; struct Foo { int a; CIRCLE_QUEUE_MEMBER(Foo) CQStuff; int b; }; struct Foo MyFoo1, MyFoo2, MyFoo3, *pFoo = 0; CIRCLE_QUEUE_ROOT(sRoot, Foo) MyCQRoot; fputs("Testing CIRCLE_QUEUE.\n",stdout); while(WhichInsert != DONE) { CIRCLE_QUEUE_INITIALIZE(&MyCQRoot,Foo); MyFoo1.a = 0x1A; MyFoo1.b = 0x1B; MyFoo2.a = 0x2A; MyFoo2.b = 0x2B; MyFoo3.a = 0x3A; MyFoo3.b = 0x3B; switch(WhichInsert) { case END: CIRCLE_QUEUE_INSERT_END(&MyCQRoot,Foo,&MyFoo1,CQStuff); CIRCLE_QUEUE_INSERT_END(&MyCQRoot,Foo,&MyFoo2,CQStuff); CIRCLE_QUEUE_INSERT_END(&MyCQRoot,Foo,&MyFoo3,CQStuff); WhichInsert = ROOT; break; case ROOT: CIRCLE_QUEUE_INSERT_ROOT(&MyCQRoot,Foo,&MyFoo3,CQStuff); CIRCLE_QUEUE_INSERT_ROOT(&MyCQRoot,Foo,&MyFoo2,CQStuff); CIRCLE_QUEUE_INSERT_ROOT(&MyCQRoot,Foo,&MyFoo1,CQStuff); WhichInsert = PREVIOUS; break; case PREVIOUS: CIRCLE_QUEUE_INSERT_ROOT(&MyCQRoot,Foo,&MyFoo3,CQStuff); CIRCLE_QUEUE_INSERT_PREVIOUS(&MyCQRoot,&MyFoo3,&MyFoo2,CQStuff); CIRCLE_QUEUE_INSERT_PREVIOUS(&MyCQRoot,&MyFoo2,&MyFoo1,CQStuff); WhichInsert = DONE; break; default: assert(0); } pFoo = CIRCLE_QUEUE_FIRST(&MyCQRoot); assert(pFoo); assert(pFoo->a == 0x1A); assert(pFoo->b == 0x1B); pFoo = CIRCLE_QUEUE_NEXT(&MyCQRoot,pFoo,CQStuff); assert(pFoo); assert(pFoo->a == 0x2A); assert(pFoo->b == 0x2B); pFoo = CIRCLE_QUEUE_NEXT(&MyCQRoot,pFoo,CQStuff); assert(pFoo); assert(pFoo->a == 0x3A); assert(pFoo->b == 0x3B); pFoo = CIRCLE_QUEUE_NEXT(&MyCQRoot,pFoo,CQStuff); assert(pFoo == 0); pFoo = CIRCLE_QUEUE_FIRST(&MyCQRoot); assert(CIRCLE_QUEUE_PREVIOUS(&MyCQRoot,pFoo,CQStuff) == 0); pFoo = CIRCLE_QUEUE_LAST(&MyCQRoot); assert(pFoo == &MyFoo3); assert(CIRCLE_QUEUE_PREVIOUS(&MyCQRoot,pFoo,CQStuff) == &MyFoo2); assert(CIRCLE_QUEUE_PREVIOUS(&MyCQRoot,&MyFoo2,CQStuff) == &MyFoo1); /* Delete member 2. */ pFoo = CIRCLE_QUEUE_FIRST(&MyCQRoot); pFoo = CIRCLE_QUEUE_NEXT(&MyCQRoot,pFoo,CQStuff); CIRCLE_QUEUE_DELETE(&MyCQRoot,pFoo,CQStuff); assert(pFoo->a == 0x2A);/* Make sure we have the right member. */ assert(pFoo->b == 0x2B);/* And the data is intact. */ assert(CIRCLE_QUEUE_NEXT(&MyCQRoot,pFoo,CQStuff) == 0); /* Make sure that there are only members 1 and 3 in the list now. */ pFoo = CIRCLE_QUEUE_FIRST(&MyCQRoot); assert(pFoo); assert(pFoo->a == 0x1A); assert(pFoo->b == 0x1B); pFoo = CIRCLE_QUEUE_NEXT(&MyCQRoot,pFoo,CQStuff); assert(pFoo); assert(pFoo->a == 0x3A); assert(pFoo->b == 0x3B); assert(CIRCLE_QUEUE_NEXT(&MyCQRoot,pFoo,CQStuff) == 0); /* Delete member 3. */ pFoo = CIRCLE_QUEUE_FIRST(&MyCQRoot); pFoo = CIRCLE_QUEUE_NEXT(&MyCQRoot,pFoo,CQStuff); CIRCLE_QUEUE_DELETE(&MyCQRoot,pFoo,CQStuff); assert(pFoo->a == 0x3A);/* Make sure we have the right member. */ assert(pFoo->b == 0x3B);/* And the data is intact. */ assert(CIRCLE_QUEUE_NEXT(&MyCQRoot,pFoo,CQStuff) == 0); /* Delete member 1. */ pFoo = CIRCLE_QUEUE_FIRST(&MyCQRoot); CIRCLE_QUEUE_DELETE(&MyCQRoot,pFoo,CQStuff); assert(pFoo->a == 0x1A);/* Make sure we have the right member. */ assert(pFoo->b == 0x1B);/* And the data is intact. */ assert(CIRCLE_QUEUE_NEXT(&MyCQRoot,pFoo,CQStuff) == 0); assert(CIRCLE_QUEUE_FIRST(&MyCQRoot) == 0); CIRCLE_QUEUE_INSERT_END(&MyCQRoot,Foo,&MyFoo1,CQStuff); CIRCLE_QUEUE_INSERT_END(&MyCQRoot,Foo,&MyFoo2,CQStuff); /* Delete member 1 while there are other members in the list. */ pFoo = CIRCLE_QUEUE_FIRST(&MyCQRoot); CIRCLE_QUEUE_DELETE(&MyCQRoot,pFoo,CQStuff); assert(pFoo->a == 0x1A);/* Make sure we have the right member. */ assert(pFoo->b == 0x1B);/* And the data is intact. */ assert(CIRCLE_QUEUE_NEXT(&MyCQRoot,pFoo,CQStuff) == 0); assert(CIRCLE_QUEUE_FIRST(&MyCQRoot) == &MyFoo2); assert(MyFoo1.a == 0x1A); assert(MyFoo1.b == 0x1B); assert(MyFoo2.a == 0x2A); assert(MyFoo2.b == 0x2B); assert(MyFoo3.a == 0x3A); assert(MyFoo3.b == 0x3B); } fputs("Circle Queue passed.\n", stdout); } int main() { TestList(); TestTailQueue(); TestCircleQueue(); fputs("All tests passed.", stdout); return EXIT_SUCCESS; } #endif /* End of test code. */ #if __cplusplus } #endif #endif // !_LISTS_H