Files
mars-nwe/include/core/que.h
Mario Fetka 4602d9fa2a
All checks were successful
Source release / source-package (push) Successful in 1m15s
core: import NSS queue helper header into libnwcore
2026-06-12 15:51:18 +02:00

2773 lines
84 KiB
C

/****************************************************************************
|
| (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 <stddef.h>
#endif
#ifndef _OMNI_H_
# include <omni.h>
#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_ */