windows-nt/Source/XPSP1/NT/multimedia/reality/misc/lists.h
2020-09-26 16:20:57 +08:00

519 lines
16 KiB
C

/* 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 <stdio.h>
#include <stdlib.h>
#include <assert.h>
#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