/**************************************************************************** | | (C) Copyright 1985, 1991, 1993, 1996 Novell, Inc. | All Rights Reserved. | | This program is free software; you can redistribute it and/or | modify it under the terms of version 2 of the GNU General Public | License as published by the Free Software Foundation. | | This program is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General Public License for more details. | | You should have received a copy of the GNU General Public License | along with this program; if not, contact Novell, Inc. | | To contact Novell about this file by physical or electronic mail, | you may find current contact information at www.novell.com | |*************************************************************************** | | NetWare Advance File Services (NSS) module | |--------------------------------------------------------------------------- | | $Author: blarsen $ | $Date: 2007-06-23 03:33:49 +0530 (Sat, 23 Jun 2007) $ | | $RCSfile$ | $Revision: 2068 $ | |--------------------------------------------------------------------------- | This module is used to: | Define all of the QUEING operations | | WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! | | This header file should ONLY be used for NSS internal development. | This includes Semantic Agents (SA) and Loadable Storage Services (LSS). | Any other use may cause conflicts which NSS will NOT fix. +-------------------------------------------------------------------------*/ #ifndef _QUE_H_ #define _QUE_H_ #ifndef _STDDEF_H_ # include #endif #ifndef _OMNI_H_ # include #endif #ifdef __cplusplus extern "C" { #endif /*---------------------------------------------------------------------------- | Que.h defines a set of macros for manipulating various types of | linked lists. When a linked list needs to be used, these macros | and functions will be used. A structure that wants to use one or | more of these linked lists, must include in their structure | definition a link field of a type appropriate to the type of linked | list structure being used. The link field can be any place in the | structure though being placed at the front of the structure generates | slightly better code. | | We support four types of linked list. | | 1. A stack (STK) | 2. A singly linked list (SQ) | 3. A singly linked circular list (CIR) | 4. A doubly linked circular list (DQ) | | The following sections describe each of these link types in | detail and how to use the various operations and under what | circumstances they should be used. | | You have several compile time options to ENABLE or DISABLE to | select how these routines are implemented in your system. | | MCCABE ENABLE Sets rest of options to minimize complexity | measures from the MCCABE tools. | DISABLE Use options set by developer. | | QUE_NULL ENABLE NULL out next pointer after dequeuing | DISABLE Next pointer is not nulled, thus QMEMBER | and QUE_CHECK are not available. | | QUE_CHECK ENABLE Make sure 'next' is NULL when putting an | element into a linked list. This should | be ENABLED during development but should | be DISABLED for maximum performance. | DISABLE No checking done. | | QUE_MACRO ENABLE Use the macro (in-line) versions. Because | of locality in caches, it may be more | efficient to use the function version of | these routines rather than the macro version. | DISABLE Use the function versions. Makes it | easier to step over queuing functions | when debugging. | | The generic macros work across all linked list types. The following | parameters are the same for all the macros. | | type | INPUT: The type of the structure pointed to by 'item'. | linkField | INPUT: The field allocated in the structure to be | used as the link field for the linked list. It should | be declared to be of appropriate for the linked list. | | Definitions used in USAGE sections: | | typedef struct Xyz_s | { | int field_a; | DQlink_t link; | int field_b; | } Xyz_s; | | DQhead_t Head; | Zyz_s Xyzzy; | Zyz_s *xyz; | | FRONTADDR(item, type, linkField) | Because the link field can be any place in the structure, | sometimes you have a pointer to the link field and want | a pointer to the beginning of the structure. FRONTADDR | subtracts the offset of the 'linkField' from the pointer | to adjust 'item' to point to the front of the structure. | item | UPDATE: points to the link field and is modified to point | to the front of the structure. | USAGE: | { | Xyz_s *abc = (Xyz_s *)&Xyzzy.link; | | FRONTADDR(abc, Xyz_s, link); | } | | STRUCT(item, type, linkField) | Same as FRONTADDR but rather than updating 'item', lets | the new pointer be assigned to a variable of your choice. | item | INPUT: points to the link field in the structure. | USAGE: | { | DQlink_t *abc = &Xyzzy.link; | Xyz_s *efg; | | efg = STRUCT(abc, Xyz_s, link); | } | | NEXT(item) | Gets the next item in a linked list. In this case, | item points to the link field of the structure. | item | INPUT: points to the link field of the structure. | USAGE: | { | DQlink_t *abc = &Xyzzy.link; | DQlink_t *next; | Xyz_s *efg; | | next = NEXT(abc); | efg = STRUCT(next, Xyz_s, link); | } | | ONEXT(item, type, linkField) | Gets the next item in a linked list. In this case, | assumes item is pointing to the front of the structure | and returns the pointer to the front of the next | element in the structure. | item | INPUT: points to the front of the structure. | USAGE: | { | Xyz_s *abc = &Xyzzy; | Xyz_s *next; | | next = NEXT(abc, Xyz_s, link); | } | | PREV and OPREV only apply to doubly linked lists which have | a previous element pointer but are included here because they | complement NEXT and ONEXT. | | PREV(item) | Gets the previous item in a doubly linked list. In | this case, item points to the link field of the structure. | Useful for backing up when in a loop before removing | the current element being processed. | item | INPUT: points to the link field of the structure. | USAGE: | { | DQlink_t *abc = &Xyzzy.link; | DQlink_t *prev; | Xyz_s *efg; | | prev = PREV(abc); | efg = STRUCT(prev, Xyz_s, link); | } | | OPREV(item, type, linkField) | Gets the previous item in a doubly linked list. In | this case, it assumes item is pointing to the front | of the structure and returns the pointer to the front | of the previous element in the structure. | item | INPUT: points to the front of the structure. | USAGE: | { | Xyz_s *abc = &Xyzzy; | Xyz_s *prev; | | prev = PREV(abc, Xyz_s, link); | } | | NULLIFY(link) | Used internally by link list routines to set the | 'next' field to NULL if QUE_NULL is ENABLED. Can | be used by code to initialize the link field of | a structure if the structure is not zeroed. | link | INPUT: pointer to the link field of the structure. | USAGE: | { | NULLIFY( &Xyzzy.link); | } | | QMEMBER(link) | Used to test if linkField is in a linked list. It does | this by comparing the linkField to NULL. Only works if | QUE_NULL is ENABLED. | item | INPUT: pointer to the link field of the structure. | USAGE: | { | if (QMEMBER( &Xyzzy.link)) | { | DQ_RMV( &Xyzzy, link); | } | | Stack: STK | A stack is a singly linked list that supports Last-In-First-Out | (LIFO) order access to its members. The last element on the | list points to NULL. | | Empty Head | +-------+ | | NULL | | +-------+ | | +-------+ | | Top +-------+ | +-------+ | | | | v | +-------+ | | A | first item on list | +---+---+ | | | v | +-------+ | | B | | +---+---+ | | | v | +-------+ | | C | last item on list | +---+---+ | | | --+-- | --- | - | | typedef struct Xyz_s | { | int field_a; | STKlink_t stkLink; | int field_b; | } Xyz_s; | | zyzzy() | { | STKtop_t Top; | Xyz_s A, B, C; | Xyz_s *a, *b, *c; | | STK_INIT(Top); | | STK_PUSH(Top, &C, stkLink); | STK_PUSH(Top, &B, stkLink); | STK_PUSH(Top, &A, stkLink); | | STK_POP(Top, a, Xyz_s, stkLink); | STK_POP(Top, b, Xyz_s, stkLink); | STK_POP(Top, c, Xyz_s, stkLink); | } | | Stacks are useful for handling free lists of resources. The link fields | have been designed so that a structure that normally resides on some | other type of linked data structure, can be stored on a free list managed | by the stack macros. | | Typedefs: | | STKlink_t Use the STKlink_t typedef to define the link field | in the structures to be managed as a stack. This | field must be initialized to zero either by zeroing | the whole structure or calling NULLIFY with the field. | | STKtop_t Use the STKtop_t typedef to define the top of the | stack or LIFO. The top must be initialized by either | using STK_INIT or STK_INIT_ELEMENTS. | | Macros: | | STK_INIT(top) | Initialize the top of the stack. | top | OUTPUT: A variable of type STKtop_t used for the | top of the stack. | | STK_STATIC_INIT() | Uses compile time initialization to initialize the head. | USAGE: | STKtop_t Top = STK_STATIC_INIT(); | | STK_INIT_ELEMENTS(top, data, numElements, typeElement, linkField) | Used to take an array of items and initialize all of them | and push them onto the stack. A nice way to build a free | list during initialization. | top | OUTPUT: A variable of type STKtop_t used for the | top of the stack. Assumed to be uninitialized. | data | INPUT: Pointer to the first item in the array. Usually | the array name. | numElements | INPUT: Number of elements in the array. | typeElement | INPUT: The type of structure of the elements in the array. | linkField: | INPUT: The name of the field to be used for stack link (does | not have to be of type STKlink_t). | USAGE: | { | Xyz_s Xyz[10]; | STKtop_t Top; | | STK_INIT_ELEMENTS(Top, Xyz, 10, Xyz_s, link); | } | | STK_EMPTY(top) | Is True, if top of stack is empty, otherwise is False. | Used to test if there are any items left on the stack. | top | INPUT: The top of the stack. | USAGE: | if (STK_EMPTY(Top)) { ... } | | STK_NOT_EMPTY(top) | Is False, if top of stack is empty, otherwise is True. | Easier to understand then "if (!STK_EMPTY(top))...". | top | INPUT: The top of the stack. | USAGE: | if (STK_NOT_EMPTY(Top)) { ... } | | STK_PUSH(top, item, linkField) | Push an item on to the stack. If the stack is immediately | popped, this item will come off first. | top | UPDATE: The top of the stack. Updated to point to 'item'. | item | INPUT: Pointer to a structure to be put in the stack. | The 'linkField' of 'item' is set to the current structure | pointer in 'top' and 'top' points to 'item'. | | STK_POP(top, item, type, linkField) | Pop the top item off the stack. If the stack is empty, | item is set to NULL, otherwise it has the top structure | on the stack and the top now points to the next item on | the stack. | top | UPDATE: The top of the stack. Updated to point to | the next item on the stack. | item | OUTPUT: Pointer to a structure of type 'type'. Set | to NULL if the stack is empty, otherwise set to a | pointer to the structure pointed to by top. | | STK_POP_NO_CHECK(top, item, type, linkField) | STK_POP_NO_CHECK is just like STK_POP except we know | something is on the stack having done a STK_NOT_EMPTY | or a STK_PEEK earlier. | top | UPDATE: The top of the stack. Updated to point to | the next item on the stack. | item | OUTPUT: Pointer to a structure of type 'type'. Set | to NULL if the stack is empty, otherwise set to a | pointer to the structure pointed to by top. | | STK_PEEK(top, item, type, linkField) | Sets 'item' to the first element at the top of the stack | but does not remove it from the stack. Good for checking | resources before committing them. Usually used with | STK_DROP. | top | INPUT: The top of the stack. | item | OUTPUT: Pointer to a structure of type 'type'. Set | to NULL if the stack is empty, otherwise set to a | pointer to the structure pointed to by top. | | STK_DROP(top, item, type, linkField) | Used to drop or remove 'item' from the top of the stack. | Normally, 'item' is obtained by using STK_PEEK. | top | UPDATE: The top of the stack. Updated to point to | the next item on the stack. | item | OUTPUT: Pointer to a structure of type 'type'. Set | to NULL if the stack is empty, otherwise set to a | pointer to the structure pointed to by top. | | STK_RMV(top, item, linkField) | Removes the designated 'item' from the stack by starting | at the head of the stack and scanning the stack linearly | until it finds the item and removes it from the stack. | top | UPDATE: The top of the stack. Updated to point to | the next item on the stack. | item | INPUT: Pointer to a structure of type 'type'. This is the | item to be removed from the stack. | RETURNS: | TRUE: found the item in the stack and removed it. | FALSE: did not find the item in the stack and did nothing. | | STK_FOREACH(head, item, type, linkField) | Used to scan through the stack to process it or search for | a particular element in the stack. It is really a 'for' loop | with all the pieces setup for scanning the stack. | top | INPUT: A pointer to the top of the stack. | item | OUTPUT: A pointer to the current item in the stack. | USAGE: | { | extern STKtop_t Top; | Xyz_s *x; | | STK_FOREACH(Top, x, Xyz_s, stkLink) | { | if (x->field_a == 42) return x; | } | } | Singly Linked Queue: SQ | A singly linked queue is a linked lists that supports First-In-First-Out | (FIFO) order access to its members. The head has a pointer to the | beginning and end of the linked list. This is the most efficient | for enqueuing and dequeuing operations of the FIFO data structures | we support. The head does take more space than the circular linked | lists (CIR). Elements can be inserted at either the head or the tail | of the queue but can only be take from the head. | | Empty Head | +-------+ | | next |<------+ | +-------+ | | | last | | | +---+---+ | | | | | +-----------+ | | Head | +-------+ | | next +-------+ | +-------+ | | | last | | | +-------+ | | | | | | v | | +-------+ | | | A | first item on list | | +---+---+ | | | | | v | | +-------+ | | | B | | | +---+---+ | | | | | v | | +-------+ | +------>| C | last item on list | +-------+ | | typedef struct Xyz_s | { | int field_a; | SQlink_t sqLink; | int field_b; | } Xyz_s; | | zyzzy() | { | SQhead_t Head; | Xyz_s A, B, C; | Xyz_s *a, *b, *c; | | SQ_INIT( &Head); | | SQ_ENQ( &Head, &A, sqLink); | SQ_ENQ( &Head, &B, sqLink); | SQ_ENQ( &Head, &C, sqLink); | | SQ_DEQ( &Head, a, Xyz_s, sqLink); | SQ_DEQ( &Head, b, Xyz_s, sqLink); | SQ_DEQ( &Head, c, Xyz_s, sqLink); | } | | Singly linked queues can quickly process queues that are normally | accessed in FIFO order and elements are rarely or never removed | from the middle of the queue. To remove an element from the middle | of the queue requires starting a scan at the head and following the | links until the desired element is found. | | Typedefs: | | SQlink_t Use the SQlink_t typedef to define the link field | in the structures to be managed as a singly linked | queue. This field must be initialized to zero either | by zeroing the whole structure or calling NULLIFY | with the field. | | SQhead_t Use the SQhead_t typedef to define the head of the | singly linked queue. The head must be initialized by | either using SQ_INIT or SQ_INIT_ELEMENTS. | | Macros: | | SQ_INIT(head) | Initialize the head of the queue. | head | OUTPUT: A pointer to a variable of type SQhead_t. | | SQ_INIT_ELEMENTS(head, data, numElements, typeElement, linkField) | Used to take an array of items and initialize all of them | and enqueue them in the queue. | head | OUTPUT: A variable of type SQhead_t used for the | head of the queue. Assumed to be uninitialized. | data | INPUT: Pointer to the first item in the array. Usually | the array name. | numElements | INPUT: Number of elements in the array. | typeElement | INPUT: The type of structure of the elements in the array. | linkField: | INPUT: The name of the field to be used for queue link. | USAGE: | { | Xyz_s Xyz[10]; | SQhead_t Head; | | SQ_INIT_ELEMENTS(Head, Xyz, 10, Xyz_s, link); | } | | SQ_EMPTY(head) | Is True, if queue is empty, otherwise is False. | Used to test if there are any items left in the queue. | head | INPUT: A pointer to the head of the queue. | USAGE: | if (SQ_EMPTY(Head)) { ... } | | SQ_NOT_EMPTY(head) | Is False, if queue is empty, otherwise is True. | Easier to understand then "if (!SQ_EMPTY(head))...". | head | INPUT: A pointer to the head of the queue. | USAGE: | if (SQ_NOT_EMPTY(Head)) { ... } | | SQ_ENQ(head, item, linkField) | Enqueue an item on to the tail of the queue. | head | UPDATE: Pointer to the head of the queue. The tail | pointer in the head will point to 'item'. | item | INPUT: Pointer to the element to be inserted at the | tail of the queue. | | SQ_PUSH(head, item, linkField) | Push an item on to the front of the queue. If the queue | is immediately dequeued, this item will come off. Useful | preempting others or forcing something to be reused quickly. | head | UPDATE: Pointer to the head of the queue. The head | pointer in the head will point to 'item'. | item | UPDATE: Pointer to the element to be inserted at the head | of the queue. The link field of 'item' points to what | the 'head' did. | | SQ_DEQ(head, item, type, linkField) | Dequeue the first item off the queue. If the queue is | empty, item is set to NULL, otherwise it has the oldest | structure in the queue and the head now points to the | next item in the queue. | head | UPDATE: A pointer to the head of the queue. Updated to | point to the next item on the queue. | item | OUTPUT: Pointer to a structure of type 'type'. Set | to NULL if the queue is empty, otherwise set to a | pointer to the structure pointed to by head. | | SQ_DEQ_NO_CHECK(head, item, type, linkField) | SQ_DEQ_NO_CHECK is just like SQ_DEQ except we know | something is on the queue having done a SQ_NOT_EMPTY | or a SQ_PEEK earlier. | head | UPDATE: A pointer to the head of the queue. Updated to | point to the next item on the queue. | item | OUTPUT: Pointer to a structure of type 'type'. Set | to a pointer to the structure pointed to by head. | | SQ_PEEK(head, item, type, linkField) | Sets 'item' to the first element at the head of the queue | but does not remove it from the queue. Good for checking | resources before committing them. Usually used with | SQ_DROP. | head | INPUT: A pointer to the head of the queue. | item | OUTPUT: Pointer to a structure of type 'type'. Set | to a pointer to the structure pointed to by head. If | queue is empty, it is set to NULL. | | SQ_PEEK_LAST(head, item, type, linkField) | Sets 'item' to the element at the tail of the queue | but does not remove it from the queue. | head | INPUT: A pointer to the head of the queue. | item | OUTPUT: Pointer to a structure of type 'type'. Set | to a pointer to the structure pointed to by head. If | queue is empty, it is set to NULL. | | SQ_DROP(head, item, linkField) | Used to drop or remove 'item' from the head of the queue. | Normally, 'item' is obtained by using SQ_PEEK. | head | UPDATE: A pointer to the head of the queue. Updated to | point to the next item on the queue. | item | UPDATE: Pointer to a structure of type 'type'. 'item' | was obtained by doing a SQ_PEEK. | | SQ_RMV(head, item, linkField) | Removes the designated 'item' from the queue by starting | at the head of the queue and scanning the queue linearly | until it finds the item and removes it from the queue. | head | UPDATE: A pointer to the head of the queue. If the 'item' | is pointed to by the head or tail, the head structure is | updated appropriately. | item | INPUT: Pointer to a structure of type 'type'. LinkField | will be set to NULL, if QUE_NULL is enabled. | | SQ_APPEND(head, appendee) | Used to append one queue to another queue. All the | elements in the appendee queue are placed at the tail | of the head queue. | head | UPDATE: A pointer to the head of the queue that the other | queue will be appended. Its tail pointer is set to the | tail of the 'appendee' queue. | appendee | UPDATE: A pointer to the head of the queue that will be | attached to the end of the head queue. 'appendee' is | made an empty queue. | | SQ_PREPEND(head, prependee) | Used to prepend one queue to another queue. All the | elements in the prepend queue are placed at the front | of the head queue. | head | UPDATE: A pointer to the head of the queue that the other | queue will be prepended. Its head pointer is set to the | head of the 'prependee' queue. | prependee | UPDATE: A pointer to the head of the queue that will be | attached to the beginning of the head queue. The 'prependee' | is made an empty queue. | | SQ_FIND(head, item, linkField) | Returns TRUE if it finds 'item' in the queue, otherwise | returns FALSE. Does a linear search of the queue to find | the 'item'. | head | INPUT: A pointer to the head of the queue. | | SQ_CNT(head) | Returns the number of elements in the queue. | head | INPUT: A pointer to the head of the queue. | Singly Linked Circular Queue: CIR | A singly linked circular queue is a linked list where the head of | the queue actually points to the tail element which points to the | head element. It is a little more costly to manipulate than the | singly linked queue described above but it only uses one pointer | for the head so can be used when many instances of queues are needed. | | Empty Head | +-------+ | | 0 | | +-------+ | | +-------+ | | Head +-------+ | +-------+ | | | | v | +-------+ | +------>| C | last item on list | | +---+---+ | | | | | v | | +-------+ | | | A | first item on list (note different order). | | +---+---+ | | | | | v | | +-------+ | +-------+ B | | +-------+ | | typedef struct Xyz_s | { | int field_a; | CIRlink_t cirLink; | int field_b; | } Xyz_s; | | zyzzy() | { | CIRhead_t Head; | Xyz_s A, B, C; | Xyz_s *a, *b, *c; | | CIR_INIT(Head); | | CIR_ENQ(Head, &A, cirLink); | CIR_ENQ(Head, &B, cirLink); | CIR_ENQ(Head, &C, cirLink); | | CIR_DEQ(Head, a, Xyz_s, cirLink); | CIR_DEQ(Head, b, Xyz_s, cirLink); | CIR_DEQ(Head, c, Xyz_s, cirLink); | } | | Typedefs: | | CIRlink_t Use the CIRlink_t typedef to define the link field | in the structures to be managed as a singly linked | circular queue. This field must be initialized to | zero either by zeroing the whole structure or calling | NULLIFY with the field. | | CIRhead_t Use the CIRhead_t typedef to define the head of the | singly linked circular queue. The head must be | initialized by either using CIR_INIT or CIR_INIT_ELEMENTS. | | Macros: | | CIR_INIT(head) | Initialize the head of the queue. | head | OUTPUT: A variable of type CIRhead_t initialized to NULL. | | CIR_INIT_ELEMENTS(head, data, numElements, typeElement, linkField) | Used to take an array of items and initialize all of them | and enqueue them in the queue. | head | OUTPUT: A variable of type CIRhead_t used for the | head of the queue. Assumed to be uninitialized. | data | INPUT: Pointer to the first item in the array. Usually | the array name. | numElements | INPUT: Number of elements in the array. | typeElement | INPUT: The type of structure of the elements in the array. | linkField: | INPUT: The name of the field to be used for queue link. | USAGE: | { | Xyz_s Xyz[10]; | CIRhead_t Head; | | CIR_INIT_ELEMENTS(Head, Xyz, 10, Xyz_s, link); | } | | CIR_EMPTY(head) | Is True, if queue is empty, otherwise is False. | Used to test if there are any items left in the queue. | head | INPUT: The head of the queue. | USAGE: | if (CIR_EMPTY(Head)) { ... } | | CIR_NOT_EMPTY(head) | Is False, if queue is empty, otherwise is True. | Easier to understand then "if (!CIR_EMPTY(head))...". | head | INPUT: The head of the queue. | USAGE: | if (CIR_NOT_EMPTY(Head)) { ... } | | CIR_ENQ(head, item, linkField) | Enqueue an item on to the tail of the queue. | head | UPDATE: The head of the queue. The head will now point | to 'item' and 'item' will point to what 'head' was pointing | and the old tail's link field will point to 'item'. | item | UPDATE: Pointer to element to be inserted at tail of queue. | Its link field is updated to point to the head element. | | CIR_PUSH(head, item, linkField) | Push an item on to the front of the queue. If the queue | is immediately dequeued, this item will come off. Useful | preempting others or forcing something to be reused quickly. | head | INPUT: The head of the queue. The tail element that head | points to will have its link field updated to point to | 'item' and 'item' will point to what was the head element | of the queue. | item | UPDATE: Pointer to element to be inserted at head of queue. | Its link field is updated to point to the old head element. | | CIR_DEQ(head, item, type, linkField) | Dequeue the first item off the queue. If the queue is | empty, item is set to NULL, otherwise it has the oldest | structure in the queue and the head now points to the | next item in the queue. | head | UPDATED: The head of the queue. The tail element is updated | to point to the next element of the queue. If this is the | last element in the queue, 'head' is set to NULL. | item | OUTPUT: Pointer to a structure of type 'type'. Set | to NULL if the queue is empty, otherwise set to a | pointer to the structure pointed to by the tail element | pointed to by 'head'. | | CIR_DEQ_NO_CHECK(head, item, type, linkField) | CIR_DEQ_NO_CHECK is just like CIR_DEQ except we know | something is on the queue having done a CIR_NOT_EMPTY | or a CIR_PEEK earlier. | head | UPDATED: The head of the queue. The tail element is updated | to point to the next element of the queue. If this is the | last element in the queue, 'head' is set to NULL. | item | OUTPUT: Pointer to a structure of type 'type'. Set | to NULL if the queue is empty, otherwise set to a | pointer to the structure pointed to by the tail element | pointed to by 'head'. | | CIR_PEEK(head, item, type, linkField) | Sets 'item' to the first element at the head of the queue | but does not remove it from the queue. Good for checking | resources before committing them. Usually used with | CIR_DROP. | head | INPUT: The head of the queue. | item | OUTPUT: Pointer to a structure of type 'type'. Set | to the first element of the queue which is pointed | to by tail element which is pointed to by head. If | queue is empty, it is set to NULL. | | CIR_DROP(head, item, linkField) | Used to drop or remove 'item' from the head of the queue. | Normally, 'item' is obtained by using CIR_PEEK. | head | UPDATE: The head of the queue. The tail element is | set pointing to the next element unless the queue | is now empty in which case the 'head' is set to NULL. | item | UPDATE: Pointer to a structure of type 'type'. 'item' | was obtained by doing a CIR_PEEK. | | CIR_RMV(head, item, linkField) | Removes the designated 'item' from the queue by starting | at the head of the queue and scanning the queue linearly | until it finds the item and removes it from the queue. | head | UPDATE: The head of the queue. If the 'item' is pointed | to by the 'head', the head is updated appropriately. | item | INPUT: Pointer to a structure of type 'type'. LinkField | will be set to NULL, if QUE_NULL is enabled. | | CIR_APPEND(head, appendee) | Used to append one queue to another queue. All the | elements in the appendee queue are placed at the tail | of the head queue. | head | UPDATE: The head of the queue that the other queue will | be appended. | appendee | UPDATE: The head of the queue that will be attached to | the end of the head queue. 'appendee' is made an empty | queue. | | CIR_PREPEND(head, prependee) | Used to prepend one queue to another queue. All the | elements in the prepend queue are placed at the front | of the head queue. | head | UPDATE: The head of the queue that the other queue will | be prepended. Its head pointer is set to the head of | the 'prependee' queue. | prependee | UPDATE: The head of the queue that will be attached to | the beginning of the head queue. The 'prependee' is made | an empty queue. | | CIR_FIND(head, item, linkField) | Returns TRUE if it finds 'item' in the queue, otherwise | returns FALSE. Does a linear search of the queue to find | the 'item'. | head | INPUT: A pointer to the head of the queue. | | CIR_CNT(head) | Returns the number of elements in the queue. | head | INPUT: A pointer to the head of the queue. | Doubly Linked Circular Queue: DQ | A doubly linked circular queue is the most general of these link list | routines and of course it takes the most resources to manipulate and | store. The head of a doubly linked queue appears as a member of the | queue. It has a 'next' and 'previous' pointer and can be traversed | in either direction. The queue is empty when the head points to itself. | | Empty Head | +-------+ | +-->| next +---+ | | +-------+ | | +---+ prev |<--+ | +-------+ | | Head | +-->+-------+<---------------+ | | | next +-------+ | | | +-------+ | | | | | prev | | | | | +---+---+ | | | | | | | | | | v | | | | +-->+-------+ | | | | | | A | | first item on list | | | | +-------+ | | | | | | +----+ | | | | +---+---+ | | | | | | | | | v | | | | +-------+<---+ | | | | | B | | | | | | +-------+ | | | | +---+ | | | | | +---+---+ | | | | | | | | | v | | | +------>+-------+ | | +---------------+ C | | last item on list | +-------+ | | | +----+ | +-------+ | | typedef struct Xyz_s | { | int field_a; | DQlink_t dqLink; | int field_b; | } Xyz_s; | | zyzzy() | { | DQhead_t Head; | Xyz_s A, B, C; | Xyz_s *a, *b, *c; | | DQ_INIT( &Head); | | DQ_ENQ( &Head, &A, dqLink); | DQ_ENQ( &Head, &B, dqLink); | DQ_ENQ( &Head, &C, dqLink); | | DQ_DEQ( &Head, a, Xyz_s, dqLink); | DQ_DEQ( &Head, b, Xyz_s, dqLink); | DQ_DEQ( &Head, c, Xyz_s, dqLink); | } | | Their biggest advantages are easy removal of an item from the middle | of a list (you don't even have to know the head) and simple routines | for scanning the list. For data structures that need to use multiple | linked lists, this is the queue of choice because once you have found | the element on one list, you can easily remove it from other lists. | | Typedefs: | | DQlink_t Use the DQlink_t typedef to define the link field | in the structures to be managed as doubly linked | queue. This field must be initialized to zero either | by zeroing the whole structure or calling NULLIFY | with the field. | | DQhead_t Use the DQhead_t typedef to define the head of the | doubly linked queue. The head must be initialized by | either using DQ_INIT or DQ_INIT_ELEMENTS. | | Macros: | | DQ_INIT(head) | Initialize the head of the queue. | head | OUTPUT: A pointer to a variable of type DQhead_t. | USAGE: | DQ_INIT( &Head); | | DQ_STATIC_INIT(head) | Uses compile time initialization to initialize the head. | head | OUTPUT: A variable of type DQhead_t. | USAGE: | DQhead_t Head = DQ_STATIC_INIT(Head); | | DQ_INIT_ELEMENTS(head, data, numElements, typeElement, linkField) | Used to take an array of items and initialize all of them | and enqueue them in the queue. | head | OUTPUT: A variable of type DQhead_t used for the | head of the queue. Assumed to be uninitialized. | data | INPUT: Pointer to the first item in the array. Usually | the array name. | numElements | INPUT: Number of elements in the array. | typeElement | INPUT: The type of structure of the elements in the array. | linkField: | INPUT: The name of the field to be used for queue link. | USAGE: | { | Xyz_s Xyz[10]; | DQhead_t Head; | | DQ_INIT_ELEMENTS(Head, Xyz, 10, Xyz_s, link); | } | | DQ_EMPTY(head) | Is True, if queue is empty, otherwise is False. | Used to test if there are any items left in the queue. | head | INPUT: A pointer to the head of the queue. | USAGE: | if (DQ_EMPTY(Head)) { ... } | | DQ_NOT_EMPTY(head) | Is False, if queue is empty, otherwise is True. | Easier to understand then "if (!DQ_EMPTY(head))...". | head | INPUT: A pointer to the head of the queue. | USAGE: | if (DQ_NOT_EMPTY(Head)) { ... } | | DQ_IS_MORE_THAN_ONE(head) | Is True, if more than one item on queue, otherwise is False. | It is easy to test if there is only 0 or 1 items on a DQ. | head | INPUT: A pointer to the head of the queue. | USAGE: | if (DQ_MORE_THAN_ONE(Head)) { ... } | | DQ_ENQ(head, item, linkField) | Enqueue an item on to the tail of the queue. | head | UPDATE: Pointer to the head of the queue. The 'previous' | pointer of the head will point to 'item'. If the list was | empty, the 'next' field of 'head' will point to 'item'. | item | INPUT: Pointer to the element to be inserted at the | tail of the queue. Its 'next' pointer will point to | the 'head' and its 'previous' pointer will point to | the old tail. | | DQ_PUSH(head, item, linkField) | Push an item on to the front of the queue. If the queue | is immediately dequeued, this item will come off. Useful | preempting others or forcing something to be reused quickly. | head | UPDATE: Pointer to the head of the queue. The 'next' field | of 'head' will point to 'item'. | item | UPDATE: Pointer to the element to be inserted at the head | of the queue. The 'previous' field of 'item' will point | to the 'head' and the 'next' field will point to the old | head element of the queue. | | DQ_DEQ(head, item, type, linkField) | Dequeue the first item off the queue. If the queue is | empty, item is set to NULL, otherwise it has the oldest | structure in the queue and the head now points to the | next item in the queue. | head | UPDATE: A pointer to the head of the queue. Updated to | point to the next item on the queue. | item | OUTPUT: Pointer to a structure of type 'type'. Set | to NULL if the queue is empty, otherwise set to a | pointer to the structure pointed to by head. | | DQ_DEQ_NO_CHECK(head, item, type, linkField) | DQ_DEQ_NO_CHECK is just like DQ_DEQ except we know | something is on the queue having done a DQ_NOT_EMPTY | or a DQ_PEEK earlier. | head | UPDATE: A pointer to the head of the queue. Updated to | point to the next item on the queue. | item | OUTPUT: Pointer to a structure of type 'type'. Set | to a pointer to the structure pointed to by head. | | DQ_TAKE(head, item, type, linkField) | Dequeue the last item off the queue (which is normally the | the last item inserted). If the queue is empty, item is set | to NULL, otherwise it has the newest structure in the queue | and the head's back link now points to the next newest item | in the queue. | head | UPDATE: A pointer to the head of the queue. Its back link | is updated to point to the next previous item on the queue. | item | OUTPUT: Pointer to a structure of type 'type'. Set | to NULL if the queue is empty, otherwise set to a | pointer to the structure pointed to by head. | | DQ_PEEK(head, item, type, linkField) | Sets 'item' to the first element at the head of the queue | but does not remove it from the queue. Good for checking | resources before committing them. Usually used with | DQ_DROP. | head | INPUT: A pointer to the head of the queue. | item | OUTPUT: Pointer to a structure of type 'type'. Set | to a pointer to the structure pointed to by head. If | queue is empty, it is set to NULL. | | DQ_PEEK_END(head, item, type, linkField) | Sets 'item' to the LAST element at the head of the queue | but does not remove it from the queue. Good for checking | resources before committing them. | head | INPUT: A pointer to the head of the queue. | item | OUTPUT: Pointer to a structure of type 'type'. Set | to a pointer to the structure pointed to by head. If | queue is empty, it is set to NULL. | | DQ_DROP(head, item, linkField) | Used to drop or remove 'item' from the head of the queue. | Normally, 'item' is obtained by using DQ_PEEK. | head | UPDATE: A pointer to the head of the queue. Updated to | point to the next item on the queue. | item | UPDATE: Pointer to a structure of type 'type'. 'item' | was obtained by doing a DQ_PEEK. | | DQ_RMV(item, linkField) | Removes the designated 'item' from the queue. Because | we have a 'next' and 'previous' pointers, this operation | is done very quickly. Unlike SQ_RMV and CIR_RMV, we don't | even have to know the head of the queue. | item | INPUT: Pointer to a structure of type 'type'. 'next' field | will be set to NULL, if QUE_NULL is enabled. Its successor | and predecessor elements in the queue will now point | to each others | | DQ_APPEND(head, appendee) | Used to append one queue to another queue. All the | elements in the appendee queue are placed at the tail | of the head queue. | head | UPDATE: A pointer to the head of the queue that the other | queue will be appended. Its 'previous' pointer is set to the | tail of the 'appendee' queue. | appendee | UPDATE: A pointer to the head of the queue that will be | attached to the end of the head queue. 'appendee' is | made an empty queue. | | DQ_PREPEND(head, prependee) | Used to prepend one queue to another queue. All the | elements in the prepend queue are placed at the front | of the head queue. | head | UPDATE: A pointer to the head of the queue that the other | queue will be prepended. Its head pointer is set to the | head of the 'prependee' queue. | prependee | UPDATE: A pointer to the head of the queue that will be | attached to the beginning of the head queue. The 'prependee' | is made an empty queue. | | DQ_FOREACH(head, item, type, linkField) | Used to scan through the queue to process it or search for | a particular element in the queue. It is really a 'for' loop | with all the pieces setup for scanning the queue. | head | INPUT: A pointer to the head of the queue. | item | OUTPUT: A pointer to the current item in the queue. | USAGE: | { | extern DQhead_t Head; | Xyz_s *x; | | DQ_FOREACH( &Head, x, Xyz_s, dqLink) | { | if (x->field_a == 42) return x; | } | } | | DQ_ISHEADNEXT(head, item, type, linkField) | Can be used to check if you are at the last item in the | list. | head | INPUT: A pointer to the head of the queue. | item | OUTPUT: A pointer to the current item in the queue. | USAGE: | { | extern DQhead_t Head; | Xyz_s *x; | | DQ_FOREACH( &Head, x, Xyz_s, dqLink) | { | if (x->field_a == 42) return x; | | if (DQ_ISHEADNEXT( &head, x, Xyz_s, dqLink)) | { | processLastElement(x); | } | } | } | | DQ_NEXT(head, item, type, linkField) | Get the next 'item' in the queue. If you reach the head, | 'item' is set to NULL. Useful for more generic scanning. | head | INPUT: A pointer to the head of the queue. | item | INPUT: A pointer to the current item in the queue. | USAGE: | { | extern DQhead_t Head; | Xyz_s *x; | | x = STRUCT( &Head, Xyz_s, dqLink); | x = DQ_NEXT( &Head, x, Xyz_s, dqLink); | while (x != NULL) | { | if (x->field_a == 42) return x; | x = DQ_NEXT( &Head, x, Xyz_s, dqLink); | } | return NULL; | } | | DQ_PREV(head, item, type, linkField) | Get the previous 'item' in the queue. If you reach the head, | 'item' is set to NULL. | head | INPUT: A pointer to the head of the queue. | item | INPUT: A pointer to the current item in the queue. | USAGE: | { | extern DQhead_t Head; | Xyz_s *x; | | x = STRUCT( &Head, Xyz_s, dqLink); | x = DQ_PREV( &Head, x, Xyz_s, dqLink); | for(;;) | { | if (x->field_a == 42) return x; | x = DQ_PREV( &Head, x, Xyz_s, dqLink); | } | } | | DQ_FIND(head, item, linkField) | Returns TRUE if it finds 'item' in the queue, otherwise | returns FALSE. Does a linear search of the queue to find | the 'item'. | head | INPUT: A pointer to the head of the queue. | | DQ_CNT(head) | Returns the number of elements in the queue. | head | INPUT: A pointer to the head of the queue. +--------------------------------------------------------------------------*/ #if __KERNEL__ void QueueAbend(const char *message); #else # define QueueAbend(_message_) ((void) 0) #endif #define QUE_NULL ENABLE /* NULL out next pointer after dequeuing * This will ALWAYS be enabled for PSS so that * we can easily tell if something is a member * of linked list. */ /* * Generic link definition. Should only be used * by generic functions. Never used by itself. */ struct Link_s { struct Link_s *next; }; typedef struct Link_s *Link_t; /* * Stack link and head */ struct STKlink_s { struct STKlink_s *next; }; typedef struct STKlink_s *STKlink_t; typedef struct STKlink_s *STKtop_t; /* * Singly Linked Queue link and header */ struct SQlink_s { struct SQlink_s *next; }; typedef struct SQlink_s *SQlink_t; typedef struct SQhead_t { SQlink_t next; SQlink_t last; } SQhead_t; /* * Circular Linked Queue link and header */ struct CIRlink_s { struct CIRlink_s *next; }; typedef struct CIRlink_s *CIRlink_t; typedef struct CIRlink_s *CIRhead_t; /* * Doubly Linked Queue link and header */ typedef struct DQlink_t { struct DQlink_t *next; struct DQlink_t *prev; } DQlink_t; typedef struct DQlink_t DQhead_t; /* * Ordered set link and header */ typedef struct SETlink_t { struct SETlink_t *next; struct SETlink_t *prev; SQUAD setNum; } SETlink_t; typedef struct SETlink_t SEThead_t; /* * Generic macros: STRUCT has been moved to omni.h */ #define FRONTADDR(item, type, linkField) \ ((item) = ((type *)(((ADDR)(item)) - offsetof(type, linkField)))) #define NEXT(item) (((Link_t)(item))->next) #define ONEXT(item, type, linkField) \ ((type *)((ADDR)(((Link_t)&((item)->linkField))->next) \ - offsetof(type, linkField))) #define PREV(item) ((item)->prev) #define OPREV(item, type, linkField) \ ((type *)((ADDR)((item)->linkField.prev) \ - offsetof(type, linkField))) /* * To allow some sanity checks on queue and stack operations, we null out * the link field. This lets us check if an item is already on a list * before putting into a list. NULLIFY is used to set the link field to * NULL before is used the first time. */ extern int LBQ_QAssertError(char *, Link_t); #if QUE_NULL IS_ENABLED # define NULLIFY(linkField) (NEXT(linkField) = NULL) # define QMEMBER(linkField) (NEXT(linkField) != NULL) # if QUE_CHECK IS_ENABLED # define IS_NULL(linkField) \ ((NEXT(linkField) == NULL) || \ LBQ_QAssertError(WHERE, (Link_t)linkField)) # else # define IS_NULL(linkField) (TRUE) # endif #else /* * NOTE: QMEMBER is not defined in this case! */ # define NULLIFY(linkField) ((void)0) # define IS_NULL(linkField) (TRUE) #endif /****************************************************************************/ /* function prototypes for all STK functions */ extern void LBQ_STKpush(STKtop_t *, STKlink_t); extern ADDR LBQ_STKpop(STKtop_t *top, NINT offset); extern ADDR LBQ_STKpopNoCheck(STKtop_t *top, NINT offset); extern void LBQ_STKdrop(STKtop_t *); extern int LBQ_STKrmv(STKtop_t *, STKlink_t); extern void LBQ_STKinitElements(STKtop_t *stacktop, ADDR start,NINT num, NINT size); #define STK_INIT(top) ((top) = NULL) #define STK_STATIC_INIT() { NULL } #define STK_EMPTY(top) ((top) == NULL) #define STK_NOT_EMPTY(top) ((top) != NULL) #if QUE_MACRO IS_ENABLED #define STK_PUSH(top, item, linkField) \ { \ STKlink_t _item = (STKlink_t)&((item)->linkField); \ \ if (IS_NULL(_item)) \ { \ _item->next = (top); \ (top) = _item; \ } \ } #else #define STK_PUSH(top, item, linkField) \ { \ LBQ_STKpush( &top, (STKlink_t)&((item)->linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define STK_POP(top, item, type, linkField) \ { \ STKlink_t _next; \ \ _next = top; \ if (_next != NULL) \ { \ top = _next->next; \ NULLIFY(_next); \ item = (type *)(((ADDR)_next) - offsetof(type, linkField)); \ } \ else \ { \ item = NULL; \ } \ } #else #define STK_POP(top, item, type, linkField) \ { \ item = (type *)LBQ_STKpop( &top, offsetof(type, linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define STK_POP_NO_CHECK(top, item, type, linkField) \ { \ STKlink_t _next; \ \ _next = top; \ top = _next->next; \ NULLIFY(_next); \ item = (type *)(((ADDR)_next) - offsetof(type, linkField)); \ } #else #define STK_POP_NO_CHECK(top, item, type, linkField) \ { \ item = (type *)LBQ_STKpopNoCheck( &top, offsetof(type, linkField)); \ } #endif #define STK_PEEK(top, item, type, linkField) \ { \ if (STK_EMPTY(top)) \ { \ item = NULL; \ } \ else \ { \ item = (type *)(((ADDR)top) - offsetof(type, linkField)); \ } \ } #if QUE_MACRO IS_ENABLED #define STK_DROP(top, item, linkField) \ { \ STKlink_t _next = (STKlink_t)&((item)->linkField); \ \ zASSERT((top)->next == _next); \ top = _next->next; \ NULLIFY(_next); \ } #else #define STK_DROP(top, item, linkField) \ { \ LBQ_STKdrop( &top); \ } #endif #define STK_RMV(top, item, linkField) \ (LBQ_STKrmv( &(top), (STKlink_t)&((item)->linkField))) #define STK_FOREACH(top, item, type, linkField) \ for (item = (type *)(((ADDR)(top)) - offsetof(type, linkField)); \ (ADDR)item != (0 - offsetof(type, linkField)); \ item = ONEXT(item, type, linkField) \ ) #define STK_INIT_ELEMENTS(top, data, numElements, typeElement, linkField) \ { \ LBQ_STKinitElements( &top, ((ADDR)data) + offsetof(typeElement, linkField), \ numElements, sizeof(typeElement)); \ } /****************************************************************************/ /* function prototypes for all SQ functions */ extern void LBQ_SQenq(SQhead_t *, SQlink_t); extern void LBQ_SQpush(SQhead_t *, SQlink_t); extern ADDR LBQ_SQdeq(SQhead_t *sqhead, NINT offset); extern ADDR LBQ_SQdeqNoCheck(SQhead_t *sqhead, NINT offset); extern void LBQ_SQdrop(SQhead_t *); extern int LBQ_SQrmv(SQhead_t *, SQlink_t); extern void LBQ_SQappend(SQhead_t *, SQhead_t *); extern void LBQ_SQprepend(SQhead_t *, SQhead_t *); extern void LBQ_SQinitElements(SQhead_t *sqhead, ADDR start, NINT num, NINT size); extern int LBQ_SQfind(SQhead_t *head, SQlink_t item); extern int LBQ_SQcnt(SQhead_t *head); #define SQ_CNT(head) LBQ_SQcnt(head) #define SQ_INIT(head) \ { \ ((head)->last = ((SQlink_t)head)); \ ((head)->next = 0); \ } #define SQ_EMPTY(head) ((head)->last == ((SQlink_t)head)) #define SQ_NOT_EMPTY(head) ((head)->last != ((SQlink_t)head)) #if QUE_MACRO IS_ENABLED #define SQ_ENQ(head, item, linkField) \ { \ SQhead_t *_head = head; \ SQlink_t _item = (SQlink_t)&((item)->linkField); \ \ if (IS_NULL(_item)) \ { \ _head->last->next = _item; \ _head->last = _item; \ } \ } #else #define SQ_ENQ(head, item, linkField) \ { \ LBQ_SQenq(head, (SQlink_t)&((item)->linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define SQ_PUSH(head, item, linkField) \ { \ SQhead_t *_head = head; \ SQlink_t _item = (SQlink_t)&((item)->linkField); \ \ if (IS_NULL(_item)) \ { \ if (SQ_EMPTY(_head)) \ { \ _head->last = _item; \ } \ else \ { \ _item->next = _head->next; \ } \ _head->next = _item; \ } \ } #else #define SQ_PUSH(head, item, linkField) \ { \ LBQ_SQpush(head, (SQlink_t)&((item)->linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define SQ_DEQ(head, item, type, linkField) \ { \ SQhead_t *_head = head; \ SQlink_t _item; \ SQlink_t _last; \ \ _last = _head->last; \ if (_last == (SQlink_t)_head) \ { \ item = NULL; \ } \ else \ { \ _item = _head->next; \ if (_last == _item) \ { \ _head->last = (SQlink_t)_head; \ _head->next = 0; \ } \ else \ { \ _head->next = _item->next; \ } \ NULLIFY(_item); \ item = (type *)(((ADDR)_item) - offsetof(type, linkField)); \ } \ } #else #define SQ_DEQ(head, item, type, linkField) \ { \ item = (type *)LBQ_SQdeq(head, offsetof(type, linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define SQ_DEQ_NO_CHECK(head, item, type, linkField) \ { \ SQhead_t *_head = head; \ SQlink_t _item; \ SQlink_t _last; \ \ _last = _head->last; \ _item = _head->next; \ if (_last == _item) \ { \ _head->last = (SQlink_t)_head; \ _head->next = 0; \ } \ else \ { \ _head->next = _item->next; \ } \ NULLIFY(_item); \ item = (type *)(((ADDR)_item) - offsetof(type, linkField)); \ } #else #define SQ_DEQ_NO_CHECK(head, item, type, linkField) \ { \ item = (type *)LBQ_SQdeqNoCheck(head, offsetof(type, linkField)); \ } #endif #define SQ_PEEK(head, item, type, linkField) \ { \ if (SQ_EMPTY(head)) \ { \ item = NULL; \ } \ else \ { \ item = (type *)(((ADDR)((head)->next)) - offsetof(type, linkField));\ } \ } #define SQ_PEEK_LAST(head, item, type, linkField) \ { \ if (SQ_EMPTY(head)) \ { \ item = NULL; \ } \ else \ { \ item = (type *)(((ADDR)((head)->last)) - offsetof(type, linkField));\ } \ } #if QUE_MACRO IS_ENABLED #define SQ_DROP(head, item, linkField) \ { \ SQhead_t *_head = (SQhead_t *)head; \ SQlink_t _item = (SQlink_t)&((item)->linkField); \ \ zASSERT(_head->next == _item); \ if (_head->last == _item) \ { \ _head->last = (SQlink_t)_head; \ _head->next = 0; \ } \ else \ { \ _head->next = _item->next; \ } \ NULLIFY(_item); \ } #else #define SQ_DROP(head, item, linkField) \ { \ LBQ_SQdrop(head); \ } #endif #define SQ_RMV(head, item, linkField) \ (LBQ_SQrmv(head, (SQlink_t)&((item)->linkField))) #if QUE_MACRO IS_ENABLED #define SQ_APPEND(head, appendee) \ { \ SQhead_t *_head = head; \ SQhead_t *_appendee = appendee; \ \ if (SQ_NOT_EMPTY(_appendee)) \ { \ _head->last->next = _appendee->next; \ _head->last = _appendee->last; \ SQ_INIT(_appendee); \ } \ } #else #define SQ_APPEND(head, appendee) \ { \ LBQ_SQappend(head, appendee); \ } #endif #if QUE_MACRO IS_ENABLED #define SQ_PREPEND(head, prependee) \ { \ SQhead_t *_head = head; \ SQhead_t *_prependee = prependee; \ \ if (SQ_NOT_EMPTY(_prependee)) \ { \ if (SQ_EMPTY(_head)) \ { \ _head->last = _prependee->last; \ } \ else \ { \ _prependee->last->next = _head->next; \ } \ _head->next = _prependee->next; \ SQ_INIT(_prependee); \ } \ } #else #define SQ_PREPEND(head, prependee) \ { \ LBQ_SQprepend(head, prependee); \ } #endif #define SQ_INIT_ELEMENTS(head, data, numElements, typeElement, linkField) \ { \ LBQ_SQinitElements( &head, ((ADDR)data) + offsetof(typeElement, linkField), \ numElements, sizeof(typeElement)); \ } #define SQ_FIND(head, item, linkField) \ LBQ_SQfind(head, (SQlink_t)&((item)->linkField)) #define SQ_FOREACH(head, item, type, linkField) \ for (item = (type *)(((ADDR)((head)->next)) - offsetof(type, linkField));\ (ADDR)item != (0 - offsetof(type, linkField)); \ item = ONEXT(item, type, linkField) \ ) /****************************************************************************/ /* function prototypes for all CIR functions */ extern void LBQ_CIRenq(CIRhead_t *, CIRlink_t); extern void LBQ_CIRpush(CIRhead_t *, CIRlink_t); extern ADDR LBQ_CIRdeq(CIRhead_t *cirhead, NINT offset); extern ADDR LBQ_CIRdeqNoCheck(CIRhead_t *cirhead, NINT offset); extern void LBQ_CIRdrop(CIRhead_t *); extern int LBQ_CIRrmv(CIRhead_t *, CIRlink_t); extern void LBQ_CIRappend(CIRhead_t *, CIRhead_t *); extern void LBQ_CIRprepend(CIRhead_t *, CIRhead_t *); extern void LBQ_CIRinitElements(CIRhead_t *cirhead, ADDR start,NINT num, NINT size); extern int LBQ_CIRfind(CIRhead_t head, CIRlink_t item); extern int LBQ_CIRcnt(CIRhead_t head); #define CIR_CNT(head) LBQ_CIRcnt(head) #define CIR_INIT(head) ((head) = NULL) #define CIR_EMPTY(head) ((head) == NULL) #define CIR_NOT_EMPTY(head) ((head) != NULL) #if QUE_MACRO IS_ENABLED #define CIR_ENQ(head, item, linkField) \ { \ CIRlink_t _item = (CIRlink_t)&((item)->linkField); \ \ if (IS_NULL(_item)) \ { \ if (CIR_EMPTY(head)) \ { \ _item->next = _item; \ } \ else \ { \ _item->next = (head)->next; \ (head)->next = _item; \ } \ (head) = (CIRlink_t)_item; \ } \ } #else #define CIR_ENQ(head, item, linkField) \ { \ LBQ_CIRenq( &head, (CIRlink_t)&((item)->linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define CIR_PUSH(head, item, linkField) \ { \ CIRlink_t _item = (CIRlink_t)&((item)->linkField); \ \ if (IS_NULL(_item)) \ { \ if (CIR_EMPTY(head)) \ { \ _item->next = _item; \ (head) = (CIRlink_t)item; \ } \ else \ { \ _item->next = (head)->next; \ (head)->next = _item; \ } \ } \ } #else #define CIR_PUSH(head, item, linkField) \ { \ LBQ_CIRpush( &head, (CIRlink_t)&((item)->linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define CIR_DEQ(head, item, type, linkField) \ { \ CIRlink_t _item; \ \ if (CIR_EMPTY(head)) \ { \ item = NULL; \ } \ else \ { \ _item = (head)->next; \ if (_item == (head)) \ { \ (head) = NULL; \ } \ else \ { \ (head)->next = _item->next; \ } \ NULLIFY(_item); \ item = (type *)(((ADDR)_item) - offsetof(type, linkField)); \ } \ } #else #define CIR_DEQ(head, item, type, linkField) \ { \ item = (type *)LBQ_CIRdeq( &head, offsetof(type, linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define CIR_DEQ_NO_CHECK(head, item, type, linkField) \ { \ CIRlink_t _item; \ \ _item = (head)->next; \ if (_item == (head)) \ { \ (head) = NULL; \ } \ else \ { \ (head)->next = _item->next; \ } \ NULLIFY(_item); \ item = (type *)(((ADDR)_item) - offsetof(type, linkField)); \ } #else #define CIR_DEQ_NO_CHECK(head, item, type, linkField) \ { \ item = (type *)LBQ_CIRdeqNoCheck( &head, offsetof(type, linkField)); \ } #endif #define CIR_PEEK(head, item, type, linkField) \ { \ if (CIR_EMPTY(head)) \ { \ item = NULL; \ } \ else \ { \ item = (type *)(((ADDR)((head)->next)) - offsetof(type, linkField));\ } \ } #if QUE_MACRO IS_ENABLED #define CIR_DROP(head, item, linkField) \ { \ CIRlink_t _item = (CIRlink_t)&((item)->linkField); \ \ zASSERT((head)->next == _item); \ if (_item == (head)) \ { \ (head) = NULL; \ } \ else \ { \ (head)->next = _item->next; \ } \ NULLIFY(_item); \ } #else #define CIR_DROP(head, item, linkField) \ { \ LBQ_CIRdrop( &head); \ } #endif #define CIR_RMV(head, item, linkField) \ (LBQ_CIRrmv( &(head), (CIRlink_t)&((item)->linkField))) #if QUE_MACRO IS_ENABLED #define CIR_APPEND(head, appendee) \ { \ CIRlink_t temp; \ \ if (CIR_NOT_EMPTY(appendee)) \ { \ if (CIR_NOT_EMPTY(head)) \ { \ temp = (appendee)->next; \ (appendee)->next = (head)->next; \ (head)->next = temp; \ } \ (head) = (appendee); \ CIR_INIT(appendee); \ } \ } #else #define CIR_APPEND(head, appendee) \ { \ LBQ_CIRappend( &head, &appendee); \ } #endif #if QUE_MACRO IS_ENABLED #define CIR_PREPEND(head, prependee) \ { \ CIRlink_t temp; \ \ if (CIR_NOT_EMPTY(prependee)) \ { \ if (CIR_NOT_EMPTY(head)) \ { \ temp = (prependee)->next; \ (prependee)->next = (head)->next; \ (head)->next = temp; \ } \ else \ { \ (head) = (prependee); \ } \ CIR_INIT(prependee); \ } \ } #else #define CIR_PREPEND(head, prependee) \ { \ LBQ_CIRprepend( &head, &prependee); \ } #endif #define CIR_INIT_ELEMENTS(head, data, numElements, typeElement, linkField) \ { \ LBQ_CIRinitElements( &head, ((ADDR)data) + offsetof(typeElement, linkField),\ numElements, sizeof(typeElement)); \ } #define CIR_FIND(head, item, linkField) \ LBQ_CIRfind(head, (CIRlink_t)&((item)->linkField)) /****************************************************************************/ /* function prototypes for all DQ functions */ extern BOOL DoDQAudit; extern boolfunc_t NSS_QAssertErrorCallback; extern boolfunc_t NSS_DQAuditCallback; extern void LBQ_DQenq(DQhead_t *, DQlink_t *); extern void LBQ_DQpush(DQhead_t *, DQlink_t *); extern ADDR LBQ_DQdeq(DQhead_t *dqhead, NINT offset); extern ADDR LBQ_DQdeqNoCheck(DQhead_t *dqhead, NINT offset); extern ADDR LBQ_DQtake(DQhead_t *dqhead, NINT offset); extern void LBQ_DQdrop(DQhead_t *); extern void LBQ_DQrmv(DQlink_t *); extern void LBQ_DQappend(DQhead_t *, DQhead_t *); extern void LBQ_DQprepend(DQhead_t *, DQhead_t *); extern void LBQ_DQinitElements(DQhead_t *dqhead, ADDR start,NINT num, NINT size); extern int LBQ_DQfind(DQhead_t *head, DQlink_t *item); extern int LBQ_DQcnt(DQhead_t *head); extern int LBQ_DQaudit(DQhead_t *head); #define DQ_CNT(head) LBQ_DQcnt(head) #define DQ_INIT(head) ((head)->next = (head)->prev = (head)) #define DQ_STATIC_INIT(head) { &(head), &(head) } #define DQ_EMPTY(head) ((head)->next == head) #define DQ_NOT_EMPTY(head) ((head)->next != head) #define DQ_IS_MORE_THAN_ONE(head) ((head)->next != (head)->prev) #if QUE_MACRO IS_ENABLED #define DQ_ENQ(head, item, linkField) \ { \ DQhead_t *_head = head; \ DQlink_t *_item = &((item)->linkField); \ \ if (IS_NULL(_item)) \ { \ if (_head->prev->next != _head) \ { \ QueueAbend("DQ_ENQ would cause memory corruption"); \ } \ _item->prev = _head->prev; \ _item->next = _head; \ _head->prev->next = _item; \ _head->prev = _item; \ } \ else \ { \ QueueAbend("DQ_ENQ would cause memory corruption(2)"); \ } \ } #else #define DQ_ENQ(head, item, linkField) \ { \ LBQ_DQenq(head, &((item)->linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define DQ_PUSH(head, item, linkField) \ { \ DQhead_t *_head = head; \ DQlink_t *_item = &((item)->linkField); \ \ if (IS_NULL(_item)) \ { \ if (_head->next->prev != _head) \ { \ QueueAbend("DQ_PUSH would cause memory corruption"); \ } \ _item->next = _head->next; \ _item->prev = _head; \ _head->next->prev = _item; \ _head->next = _item; \ } \ else \ { \ QueueAbend("DQ_PUSH would cause memory corruption(2)"); \ } \ } #else #define DQ_PUSH(head, item, linkField) \ { \ LBQ_DQpush(head, &((item)->linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define DQ_DEQ(head, item, type, linkField) \ { \ DQhead_t *_head = head; \ DQlink_t *_item; \ \ if (DQ_EMPTY(_head)) \ { \ item = NULL; \ } \ else \ { \ _item = _head->next; \ \ if ((_item->prev != _head) || (_item->next->prev != _item)) \ { \ QueueAbend("DQ_DEQ would cause memory corruption"); \ } \ _head->next = _item->next; \ _head->next->prev = _head; \ NULLIFY(_item); \ item = (type *)(((ADDR)_item) - offsetof(type, linkField)); \ } \ } #else #define DQ_DEQ(head, item, type, linkField) \ { \ item = (type *)LBQ_DQdeq(head, offsetof(type, linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define DQ_DEQ_NO_CHECK(head, item, type, linkField) \ { \ DQhead_t *_head = head; \ DQlink_t *_item; \ \ _item = _head->next; \ \ if ((_item->prev != _head) || (_item->next->prev != _item)) \ { \ QueueAbend("DQ_DEQ_NO_CHECK would cause memory corruption"); \ } \ _head->next = _item->next; \ _head->next->prev = _head; \ NULLIFY(_item); \ item = (type *)(((ADDR)_item) - offsetof(type, linkField)); \ } #else #define DQ_DEQ_NO_CHECK(head, item, type, linkField) \ { \ item = (type *)LBQ_DQdeqNoCheck(head, offsetof(type, linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define DQ_TAKE(head, item, type, linkField) \ { \ DQhead_t *_head = head; \ DQlink_t *_item; \ \ if (DQ_EMPTY(_head)) \ { \ item = NULL; \ } \ else \ { \ _item = _head->prev; \ \ if ((_item->next != _head) || (_item->prev->next != _item)) \ { \ QueueAbend("DQ_TAKE would cause memory corruption"); \ } \ _head->prev = _item->prev; \ _head->prev->next = _head; \ NULLIFY(_item); \ item = (type *)(((ADDR)_item) - offsetof(type, linkField)); \ } \ } #else #define DQ_TAKE(head, item, type, linkField) \ { \ item = (type *)LBQ_DQtake(head, offsetof(type, linkField)); \ } #endif #define DQ_PEEK(head, item, type, linkField) \ { \ DQhead_t *_head = head; \ DQlink_t *_item; \ \ if (DQ_EMPTY(_head)) \ { \ item = NULL; \ } \ else \ { \ _item = _head->next; \ item = (type *)(((ADDR)_item) - offsetof(type, linkField)); \ } \ } #define DQ_PEEK_END(head, item, type, linkField) \ { \ DQhead_t *_head = head; \ DQlink_t *_item; \ \ if (DQ_EMPTY(_head)) \ { \ item = NULL; \ } \ else \ { \ _item = _head->prev; \ item = (type *)(((ADDR)_item) - offsetof(type, linkField)); \ } \ } #if QUE_MACRO IS_ENABLED #define DQ_DROP(head) \ { \ DQhead_t *_head = head; \ DQlink_t *_item = _head->next; \ \ if ((DQ_EMPTY(_head)) || \ (_item->prev != _head) || (_item->next->prev != _item)) \ { \ QueueAbend("DQ_DROP would cause memory corruption"); \ } \ _head->next = _item->next; \ _head->next->prev = _head; \ NULLIFY(_item); \ } #else #define DQ_DROP(head) \ { \ LBQ_DQdrop(head); \ } #endif #if QUE_MACRO IS_ENABLED #define DQ_RMV(item, linkField) \ { \ DQlink_t *_item = &((item)->linkField); \ \ if ((_item->prev->next != _item) || (_item->next->prev != _item)) \ { \ QueueAbend("DQ_RMV would cause memory corruption"); \ } \ _item->next->prev = _item->prev; \ _item->prev->next = _item->next; \ NULLIFY(_item); \ } #else #define DQ_RMV(item, linkField) \ { \ LBQ_DQrmv(&((item)->linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define DQ_APPEND(head, appendee) \ { \ DQhead_t *_head = (DQhead_t *)head; \ DQhead_t *_appendee = (DQhead_t *)appendee; \ \ if (DQ_NOT_EMPTY(_appendee)) \ { \ if ((_head->prev->next != _head) || \ (_appendee->prev->next != _appendee) || \ (_appendee->next->prev != _appendee)) \ { \ QueueAbend("DQ_APPEND would cause memory corruption"); \ } \ _appendee->prev->next = _head; \ _appendee->next->prev = _head->prev; \ _head->prev->next = _appendee->next; \ _head->prev = _appendee->prev; \ DQ_INIT(_appendee); \ } \ } #else #define DQ_APPEND(head, appendee) \ { \ LBQ_DQappend(head, appendee); \ } #endif #if QUE_MACRO IS_ENABLED #define DQ_PREPEND(head, prependee) \ { \ DQhead_t *_head = (DQhead_t *)head; \ DQhead_t *_prependee = (DQhead_t *)prependee; \ \ if (DQ_NOT_EMPTY(_prependee)) \ { \ if ((_head->next->prev != _head) || \ (_prependee->prev->next != _prependee) || \ (_prependee->next->prev != _prependee)) \ { \ QueueAbend("DQ_PREPEND would cause memory corruption"); \ } \ _prependee->prev->next = _head->next; \ _head->next->prev = _prependee->prev; \ _prependee->next->prev = _head; \ _head->next = _prependee->next; \ DQ_INIT(_prependee); \ } \ } #else #define DQ_PREPEND(head, prependee) \ { \ LBQ_DQprepend(head, prependee); \ } #endif #define DQ_FOREACH(head, item, type, linkField) \ for (item = (type *)(((ADDR)((head)->next)) - offsetof(type, linkField));\ item != (type *)(((ADDR)head) - offsetof(type, linkField)); \ item = ONEXT(item, type, linkField) \ ) /***************************************************************************/ /* * These next two macros should be used as a pair. An example of where to * use this would be if there is a potential that the item being processed * is freed, then do the DQ_FOREACH_NEXT before doing the routine that frees * the item. That way the item is no longer in use. */ #define DQ_FOREACH_NONEXT(head, item, type, linkField) \ for (item = (type *)(((ADDR)((head)->next)) - offsetof(type, linkField));\ item != (type *)(((ADDR)head) - offsetof(type, linkField)); \ ) #define DQ_FOREACH_NEXT(prevItem, item, type, linkField) \ { \ prevItem = item; \ item = ONEXT(item, type, linkField); \ } /***************************************************************************/ //#define DQ_ISHEADNEXT(head, item, type, linkField) \ // ((type *)((((item)->linkField.next) == (DQlink_t *)(head)))) // #define DQ_ISHEADNEXT(head, item, type, linkField) \ (((item)->linkField.next) == (DQlink_t *)(head)) #define DQ_NEXT(head, item, type, linkField) \ ((type *)((((item)->linkField.next) == (DQlink_t *)(head)) \ ? 0 \ : ((ADDR)((item)->linkField.next) - offsetof(type, linkField)))) #define DQ_PREV(head, item, type, linkField) \ ((type *)((((item)->linkField.prev) == (DQlink_t *)(head)) \ ? 0 \ : ((ADDR)((item)->linkField.prev) - offsetof(type, linkField)))) #define DQ_INIT_ELEMENTS(head, data, numElements, typeElement, linkField) \ { \ LBQ_DQinitElements( &head, ((ADDR)data) + offsetof(typeElement, linkField), \ numElements, sizeof(typeElement)); \ } #define DQ_FIND(head, item, linkField) \ LBQ_DQfind(head, &((item)->linkField)) #if QUE_MACRO IS_ENABLED #define DQ_AUDIT(head) ((void)0); #else #define DQ_AUDIT(head) ((void)(DoDQAudit && LBQ_DQaudit(head))) #endif /****************************************************************************/ /* function prototypes for all SET functions */ /* | SET_FOREACHBLOCKING() & SET_FOREACHBLOCKINGEND() | Use in places where the link list may have a item removed because | your code blocks (another thread does removal) or itself removes items | from the list link. | Same as SET_FOREACH but assumes that body of the FOR statement | has blocked (SET_FOREACH assumes that body does not block). In addition, | SET_FOREACHBLOCKING goes through the list using the NEXT link (oldest | to newest). You MUST end the for loop with the macro SET_FOREACHBLOCKINGEND | (this macro resets the current item to the HEAD just in case the list | changed on us). YOU MUST NOT USE CONTINUE statements in the body | of your for loop. Instead do a goto to the line above your | SET_FOREACHBLOCKINGEND macro. | SET_FOREACHBLOCKING is much slower than SET_FOREACH because the | link list must be scanned from the HEAD each time. Generally, items | on the list link need a 'use count' on them so that the routine | that removes/frees the item is aware that an item is in use. | | Use SETs when you have link lists with items that may be removed on | you while a thread is blocked. Another solution is a latch that | protects the link list. The viability of this depends on how long | you block and deadlock concerns. | | See Also | SET_APPLY - Neat way to 'apply' a single function to a SET. | SET_FOREACH - For loop for code that does not block. | */ #define SET_FOREACHBLOCKING(head, item, type, linkField) \ { \ SETlink_t _dummySet; \ _dummySet.setNum = (head)->next->setNum - 1; \ SET_FOREACH(head, item, type, linkField) \ { \ if ( SET_LE( &(item)->linkField, &_dummySet ) ) \ { \ continue; \ } \ else \ { /* Done up front just in case item is freed. */ \ _dummySet.setNum = (item)->linkField.setNum; \ } #define SET_FOREACHBLOCKINGEND(head, item, type, linkField) \ item = (type*)(((ADDR)((head)))-offsetof(type,linkField)); \ } \ } #define SET_GT(_x, _y) (((_x)->setNum - (_y)->setNum) > 0) #define SET_LT(_x, _y) (((_x)->setNum - (_y)->setNum) < 0) #define SET_GE(_x, _y) (((_x)->setNum - (_y)->setNum) >= 0) #define SET_LE(_x, _y) (((_x)->setNum - (_y)->setNum) <= 0) #define SET_EQ(_x, _y) ((_x)->setNum == (_y)->setNum) #define SET_NE(_x, _y) ((_x)->setNum != (_y)->setNum) extern void LBQ_SETenq(SEThead_t *, SETlink_t *); extern void LBQ_SETpush(SEThead_t *, SETlink_t *); extern ADDR LBQ_SETdeq(SEThead_t *sethead, NINT offset); extern ADDR LBQ_SETdeqNoCheck(SEThead_t *sethead, NINT offset); extern ADDR LBQ_SETtake(SEThead_t *sethead, NINT offset); extern void LBQ_SETdrop(SEThead_t *); extern void LBQ_SETrmv(SETlink_t *); extern void LBQ_SETinitElements(SEThead_t *sethead, ADDR start,NINT num, NINT size); extern int LBQ_SETfind(SEThead_t *head, SETlink_t *item); extern int LBQ_SETcnt(SEThead_t *head); extern STATUS LBQ_SETapply(SEThead_t *head, statusfunc_t userFunction, void *userArgs); #define SET_CNT(head) LBQ_SETcnt(head) #define SET_INIT(head) ((head)->setNum = 0, \ (head)->next = (head)->prev = (head)) #define SET_STATIC_INIT(head) { &(head), &(head), 0 } #define SET_EMPTY(head) ((head)->next == head) #define SET_NOT_EMPTY(head) ((head)->next != head) #if QUE_MACRO IS_ENABLED #define SET_ENQ(head, item, linkField) \ { \ SEThead_t *_head = head; \ SETlink_t *_item = &((item)->linkField); \ \ if (IS_NULL(_item)) \ { \ _item->setNum = _head->setNum++; \ _item->prev = _head->prev; \ _item->next = _head; \ _head->prev->next = _item; \ _head->prev = _item; \ } \ } #else #define SET_ENQ(head, item, linkField) \ { \ LBQ_SETenq(head, &((item)->linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define SET_PUSH(head, item, linkField) \ { \ SEThead_t *_head = head; \ SETlink_t *_item = &((item)->linkField); \ \ if (IS_NULL(_item)) \ { \ _item->setNum = _head->next->setNum - 1; \ _item->next = _head->next; \ _item->prev = _head; \ _head->next->prev = _item; \ _head->next = _item; \ } \ } #else #define SET_PUSH(head, item, linkField) \ { \ LBQ_SETpush(head, &((item)->linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define SET_DEQ(head, item, type, linkField) \ { \ SEThead_t *_head = head; \ SETlink_t *_item; \ \ if (SET_EMPTY(_head)) \ { \ item = NULL; \ } \ else \ { \ _item = _head->next; \ _head->next = _item->next; \ _head->next->prev = _head; \ NULLIFY(_item); \ item = (type *)(((ADDR)_item) - offsetof(type, linkField)); \ } \ } #else #define SET_DEQ(head, item, type, linkField) \ { \ item = (type *)LBQ_SETdeq(head, offsetof(type, linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define SET_DEQ_NO_CHECK(head, item, type, linkField) \ { \ SEThead_t *_head = head; \ SETlink_t *_item; \ \ _item = _head->next; \ _head->next = _item->next; \ _head->next->prev = _head; \ NULLIFY(_item); \ item = (type *)(((ADDR)_item) - offsetof(type, linkField)); \ } #else #define SET_DEQ_NO_CHECK(head, item, type, linkField) \ { \ item = (type *)LBQ_SETdeqNoCheck(head, offsetof(type, linkField)); \ } #endif #if QUE_MACRO IS_ENABLED #define SET_TAKE(head, item, type, linkField) \ { \ SEThead_t *_head = head; \ SETlink_t *_item; \ \ if (SET_EMPTY(_head)) \ { \ item = NULL; \ } \ else \ { \ _item = _head->prev; \ _head->prev = _item->prev; \ _head->prev->next = _head; \ NULLIFY(_item); \ item = (type *)(((ADDR)_item) - offsetof(type, linkField)); \ } \ } #else #define SET_TAKE(head, item, type, linkField) \ { \ item = (type *)LBQ_SETtake(head, offsetof(type, linkField)); \ } #endif #define SET_PEEK(head, item, type, linkField) \ { \ SEThead_t *_head = head; \ SETlink_t *_item; \ \ if (SET_EMPTY(_head)) \ { \ item = NULL; \ } \ else \ { \ _item = _head->next; \ item = (type *)(((ADDR)_item) - offsetof(type, linkField)); \ } \ } #define SET_PEEK_END(head, item, type, linkField) \ { \ SEThead_t *_head = head; \ SETlink_t *_item; \ \ if (SET_EMPTY(_head)) \ { \ item = NULL; \ } \ else \ { \ _item = _head->prev; \ item = (type *)(((ADDR)_item) - offsetof(type, linkField)); \ } \ } #if QUE_MACRO IS_ENABLED #define SET_DROP(head, item, linkField) \ { \ SEThead_t *_head = head; \ SETlink_t *_item = &((item)->linkField); \ \ _head->next = _item->next; \ _head->next->prev = _head; \ NULLIFY(_item); \ } #else #define SET_DROP(head, item, linkField) \ { \ LBQ_SETdrop(head); \ } #endif #if QUE_MACRO IS_ENABLED #define SET_RMV(item, linkField) \ { \ SETlink_t *_item = &((item)->linkField); \ \ _item->next->prev = _item->prev; \ _item->prev->next = _item->next; \ NULLIFY(_item); \ } #else #define SET_RMV(item, linkField) \ { \ LBQ_SETrmv(&((item)->linkField)); \ } #endif #define SET_FOREACH(head, item, type, linkField) \ for (item = (type *)(((ADDR)((head)->next)) - offsetof(type, linkField));\ item != (type *)(((ADDR)head) - offsetof(type, linkField)); \ item = ONEXT(item, type, linkField) \ ) #define SET_ISHEADNEXT(head, item, type, linkField) \ ((type *)((((item)->linkField.next) == (SETlink_t *)(head)))) #define SET_NEXT(head, item, type, linkField) \ ((type *)((((item)->linkField.next) == (SETlink_t *)(head)) \ ? 0 \ : ((ADDR)((item)->linkField.next) - offsetof(type, linkField)))) #define SET_PREV(head, item, type, linkField) \ ((type *)((((item)->linkField.prev) == (SETlink_t *)(head)) \ ? 0 \ : ((ADDR)((item)->linkField.prev) - offsetof(type, linkField)))) #define SET_INIT_ELEMENTS(head, data, numElements, typeElement, linkField) \ { \ LBQ_SETinitElements( &head, ((ADDR)data) + offsetof(typeElement, linkField),\ numElements, sizeof(typeElement)); \ } #define SET_APPLY(head, userFunction, userArgs) \ LBQ_SETapply(head, userFunction, userArgs) #define SET_FIND(head, item, linkField) \ LBQ_SETfind(head, &((item)->linkField)) #ifdef __cplusplus } #endif #endif /* _QUE_H_ */