mirror of
https://github.com/php/php-src.git
synced 2024-11-29 04:46:07 +08:00
983 lines
18 KiB
C
983 lines
18 KiB
C
static const char rcsid[] = "#(@) $Id$";
|
|
|
|
/*
|
|
* Date last modified: Jan 2001
|
|
* Modifications by Dan Libby (dan@libby.com), including:
|
|
* - various fixes, null checks, etc
|
|
* - addition of Q_Iter funcs, macros
|
|
*/
|
|
|
|
|
|
/*-**************************************************************
|
|
*
|
|
* File : q.c
|
|
*
|
|
* Author: Peter Yard [1993.01.02] -- 02 Jan 1993
|
|
*
|
|
* Disclaimer: This code is released to the public domain.
|
|
*
|
|
* Description:
|
|
* Generic double ended queue (Deque pronounced DEK) for handling
|
|
* any data types, with sorting.
|
|
*
|
|
* By use of various functions in this module the caller
|
|
* can create stacks, queues, lists, doubly linked lists,
|
|
* sorted lists, indexed lists. All lists are dynamic.
|
|
*
|
|
* It is the responsibility of the caller to malloc and free
|
|
* memory for insertion into the queue. A pointer to the object
|
|
* is used so that not only can any data be used but various kinds
|
|
* of data can be pushed on the same queue if one so wished e.g.
|
|
* various length string literals mixed with pointers to structures
|
|
* or integers etc.
|
|
*
|
|
* Enhancements:
|
|
* A future improvement would be the option of multiple "cursors"
|
|
* so that multiple locations could occur in the one queue to allow
|
|
* placemarkers and additional flexibility. Perhaps even use queue
|
|
* itself to have a list of cursors.
|
|
*
|
|
* Usage:
|
|
*
|
|
* /x init queue x/
|
|
* queue q;
|
|
* Q_Init(&q);
|
|
*
|
|
* To create a stack :
|
|
*
|
|
* Q_PushHead(&q, &mydata1); /x push x/
|
|
* Q_PushHead(&q, &mydata2);
|
|
* .....
|
|
* data_ptr = Q_PopHead(&q); /x pop x/
|
|
* .....
|
|
* data_ptr = Q_Head(&q); /x top of stack x/
|
|
*
|
|
* To create a FIFO:
|
|
*
|
|
* Q_PushHead(&q, &mydata1);
|
|
* .....
|
|
* data_ptr = Q_PopTail(&q);
|
|
*
|
|
* To create a double list:
|
|
*
|
|
* data_ptr = Q_Head(&q);
|
|
* ....
|
|
* data_ptr = Q_Next(&q);
|
|
* data_ptr = Q_Tail(&q);
|
|
* if (Q_IsEmpty(&q)) ....
|
|
* .....
|
|
* data_ptr = Q_Previous(&q);
|
|
*
|
|
* To create a sorted list:
|
|
*
|
|
* Q_PushHead(&q, &mydata1); /x push x/
|
|
* Q_PushHead(&q, &mydata2);
|
|
* .....
|
|
* if (!Q_Sort(&q, MyFunction))
|
|
* .. error ..
|
|
*
|
|
* /x fill in key field of mydata1.
|
|
* * NB: Q_Find does linear search
|
|
* x/
|
|
*
|
|
* if (Q_Find(&q, &mydata1, MyFunction))
|
|
* {
|
|
* /x found it, queue cursor now at correct record x/
|
|
* /x can retrieve with x/
|
|
* data_ptr = Q_Get(&q);
|
|
*
|
|
* /x alter data , write back with x/
|
|
* Q_Put(&q, data_ptr);
|
|
* }
|
|
*
|
|
* /x Search with binary search x/
|
|
* if (Q_Seek(&q, &mydata, MyFunction))
|
|
* /x etc x/
|
|
*
|
|
*
|
|
****************************************************************/
|
|
|
|
#ifdef _WIN32
|
|
#include "xmlrpc_win32.h"
|
|
#endif
|
|
#include <stdlib.h>
|
|
#include "queue.h"
|
|
|
|
|
|
static void QuickSort(void *list[], int low, int high,
|
|
int (*Comp)(const void *, const void *));
|
|
static int Q_BSearch(queue *q, void *key,
|
|
int (*Comp)(const void *, const void *));
|
|
|
|
/* The index: a pointer to pointers */
|
|
|
|
static void **index;
|
|
static datanode **posn_index;
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_Init
|
|
*
|
|
** purpose : Initialise queue object and pointers.
|
|
*
|
|
** parameters : 'queue' pointer.
|
|
*
|
|
** returns : True_ if init successful else False_
|
|
*
|
|
** comments :
|
|
***/
|
|
|
|
int Q_Init(queue *q)
|
|
{
|
|
if(q) {
|
|
q->head = q->tail = NULL;
|
|
q->cursor = q->head;
|
|
q->size = 0;
|
|
q->sorted = False_;
|
|
}
|
|
|
|
return True_;
|
|
}
|
|
|
|
/***
|
|
*
|
|
** function : Q_AtHead
|
|
*
|
|
** purpose : tests if cursor is at head of queue
|
|
*
|
|
** parameters : 'queue' pointer.
|
|
*
|
|
** returns : boolean - True_ is at head else False_
|
|
*
|
|
** comments :
|
|
*
|
|
***/
|
|
|
|
int Q_AtHead(queue *q)
|
|
{
|
|
return(q && q->cursor == q->head);
|
|
}
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_AtTail
|
|
*
|
|
** purpose : boolean test if cursor at tail of queue
|
|
*
|
|
** parameters : 'queue' pointer to test.
|
|
*
|
|
** returns : True_ or False_
|
|
*
|
|
** comments :
|
|
*
|
|
***/
|
|
|
|
int Q_AtTail(queue *q)
|
|
{
|
|
return(q && q->cursor == q->tail);
|
|
}
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_IsEmpty
|
|
*
|
|
** purpose : test if queue has nothing in it.
|
|
*
|
|
** parameters : 'queue' pointer
|
|
*
|
|
** returns : True_ if IsEmpty queue, else False_
|
|
*
|
|
** comments :
|
|
*
|
|
***/
|
|
|
|
inline int Q_IsEmpty(queue *q)
|
|
{
|
|
return(!q || q->size == 0);
|
|
}
|
|
|
|
/***
|
|
*
|
|
** function : Q_Size
|
|
*
|
|
** purpose : return the number of elements in the queue
|
|
*
|
|
** parameters : queue pointer
|
|
*
|
|
** returns : number of elements
|
|
*
|
|
** comments :
|
|
*
|
|
***/
|
|
|
|
int Q_Size(queue *q)
|
|
{
|
|
return q ? q->size : 0;
|
|
}
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_Head
|
|
*
|
|
** purpose : position queue cursor to first element (head) of queue.
|
|
*
|
|
** parameters : 'queue' pointer
|
|
*
|
|
** returns : pointer to data at head. If queue is IsEmpty returns NULL
|
|
*
|
|
** comments :
|
|
*
|
|
***/
|
|
|
|
void *Q_Head(queue *q)
|
|
{
|
|
if(Q_IsEmpty(q))
|
|
return NULL;
|
|
|
|
q->cursor = q->head;
|
|
|
|
return q->cursor->data;
|
|
}
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_Tail
|
|
*
|
|
** purpose : locate cursor at tail of queue.
|
|
*
|
|
** parameters : 'queue' pointer
|
|
*
|
|
** returns : pointer to data at tail , if queue IsEmpty returns NULL
|
|
*
|
|
** comments :
|
|
*
|
|
***/
|
|
|
|
void *Q_Tail(queue *q)
|
|
{
|
|
if(Q_IsEmpty(q))
|
|
return NULL;
|
|
|
|
q->cursor = q->tail;
|
|
|
|
return q->cursor->data;
|
|
}
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_PushHead
|
|
*
|
|
** purpose : put a data pointer at the head of the queue
|
|
*
|
|
** parameters : 'queue' pointer, void pointer to the data.
|
|
*
|
|
** returns : True_ if success else False_ if unable to push data.
|
|
*
|
|
** comments :
|
|
*
|
|
***/
|
|
|
|
int Q_PushHead(queue *q, void *d)
|
|
{
|
|
if(q && d) {
|
|
node *n;
|
|
datanode *p;
|
|
|
|
p = malloc(sizeof(datanode));
|
|
if(p == NULL)
|
|
return False_;
|
|
|
|
n = q->head;
|
|
|
|
q->head = (node*)p;
|
|
q->head->prev = NULL;
|
|
|
|
if(q->size == 0) {
|
|
q->head->next = NULL;
|
|
q->tail = q->head;
|
|
}
|
|
else {
|
|
q->head->next = (datanode*)n;
|
|
n->prev = q->head;
|
|
}
|
|
|
|
q->head->data = d;
|
|
q->size++;
|
|
|
|
q->cursor = q->head;
|
|
|
|
q->sorted = False_;
|
|
|
|
return True_;
|
|
}
|
|
return False_;
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_PushTail
|
|
*
|
|
** purpose : put a data element pointer at the tail of the queue
|
|
*
|
|
** parameters : queue pointer, pointer to the data
|
|
*
|
|
** returns : True_ if data pushed, False_ if data not inserted.
|
|
*
|
|
** comments :
|
|
*
|
|
***/
|
|
|
|
int Q_PushTail(queue *q, void *d)
|
|
{
|
|
if(q && d) {
|
|
node *p;
|
|
datanode *n;
|
|
|
|
n = malloc(sizeof(datanode));
|
|
if(n == NULL)
|
|
return False_;
|
|
|
|
p = q->tail;
|
|
q->tail = (node *)n;
|
|
|
|
if(q->size == 0) {
|
|
q->tail->prev = NULL;
|
|
q->head = q->tail;
|
|
}
|
|
else {
|
|
q->tail->prev = (datanode *)p;
|
|
p->next = q->tail;
|
|
}
|
|
|
|
q->tail->next = NULL;
|
|
|
|
q->tail->data = d;
|
|
q->cursor = q->tail;
|
|
q->size++;
|
|
|
|
q->sorted = False_;
|
|
|
|
return True_;
|
|
}
|
|
return False_;
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_PopHead
|
|
*
|
|
** purpose : remove and return the top element at the head of the
|
|
* queue.
|
|
*
|
|
** parameters : queue pointer
|
|
*
|
|
** returns : pointer to data element or NULL if queue is IsEmpty.
|
|
*
|
|
** comments :
|
|
*
|
|
***/
|
|
|
|
void *Q_PopHead(queue *q)
|
|
{
|
|
datanode *n;
|
|
void *d;
|
|
|
|
if(Q_IsEmpty(q))
|
|
return NULL;
|
|
|
|
d = q->head->data;
|
|
n = q->head->next;
|
|
free(q->head);
|
|
|
|
q->size--;
|
|
|
|
if(q->size == 0)
|
|
q->head = q->tail = q->cursor = NULL;
|
|
else {
|
|
q->head = (node *)n;
|
|
q->head->prev = NULL;
|
|
q->cursor = q->head;
|
|
}
|
|
|
|
q->sorted = False_;
|
|
|
|
return d;
|
|
}
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_PopTail
|
|
*
|
|
** purpose : remove element from tail of queue and return data.
|
|
*
|
|
** parameters : queue pointer
|
|
*
|
|
** returns : pointer to data element that was at tail. NULL if queue
|
|
* IsEmpty.
|
|
*
|
|
** comments :
|
|
*
|
|
***/
|
|
|
|
void *Q_PopTail(queue *q)
|
|
{
|
|
datanode *p;
|
|
void *d;
|
|
|
|
if(Q_IsEmpty(q))
|
|
return NULL;
|
|
|
|
d = q->tail->data;
|
|
p = q->tail->prev;
|
|
free(q->tail);
|
|
q->size--;
|
|
|
|
if(q->size == 0)
|
|
q->head = q->tail = q->cursor = NULL;
|
|
else {
|
|
q->tail = (node *)p;
|
|
q->tail->next = NULL;
|
|
q->cursor = q->tail;
|
|
}
|
|
|
|
q->sorted = False_;
|
|
|
|
return d;
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_Next
|
|
*
|
|
** purpose : Move to the next element in the queue without popping
|
|
*
|
|
** parameters : queue pointer.
|
|
*
|
|
** returns : pointer to data element of new element or NULL if end
|
|
* of the queue.
|
|
*
|
|
** comments : This uses the cursor for the current position. Q_Next
|
|
* only moves in the direction from the head of the queue
|
|
* to the tail.
|
|
***/
|
|
|
|
void *Q_Next(queue *q)
|
|
{
|
|
if(!q)
|
|
return NULL;
|
|
|
|
if(!q->cursor || q->cursor->next == NULL)
|
|
return NULL;
|
|
|
|
q->cursor = (node *)q->cursor->next;
|
|
|
|
return q->cursor->data ;
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_Previous
|
|
*
|
|
** purpose : Opposite of Q_Next. Move to next element closer to the
|
|
* head of the queue.
|
|
*
|
|
** parameters : pointer to queue
|
|
*
|
|
** returns : pointer to data of new element else NULL if queue IsEmpty
|
|
*
|
|
** comments : Makes cursor move towards the head of the queue.
|
|
*
|
|
***/
|
|
|
|
void *Q_Previous(queue *q)
|
|
{
|
|
if(!q)
|
|
return NULL;
|
|
|
|
if(q->cursor->prev == NULL)
|
|
return NULL;
|
|
|
|
q->cursor = (node *)q->cursor->prev;
|
|
|
|
return q->cursor->data;
|
|
}
|
|
|
|
|
|
void *Q_Iter_Del(queue *q, q_iter iter)
|
|
{
|
|
void *d;
|
|
datanode *n, *p;
|
|
|
|
if(!q)
|
|
return NULL;
|
|
|
|
if(iter == NULL)
|
|
return NULL;
|
|
|
|
if(iter == (q_iter)q->head)
|
|
return Q_PopHead(q);
|
|
|
|
if(iter == (q_iter)q->tail)
|
|
return Q_PopTail(q);
|
|
|
|
n = ((node*)iter)->next;
|
|
p = ((node*)iter)->prev;
|
|
d = ((node*)iter)->data;
|
|
|
|
free(iter);
|
|
|
|
if(p) {
|
|
p->next = n;
|
|
}
|
|
if (q->cursor == (node*)iter) {
|
|
if (p) {
|
|
q->cursor = p;
|
|
} else {
|
|
q->cursor = n;
|
|
}
|
|
}
|
|
|
|
|
|
if (n != NULL) {
|
|
n->prev = p;
|
|
}
|
|
|
|
q->size--;
|
|
|
|
q->sorted = False_;
|
|
|
|
return d;
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_DelCur
|
|
*
|
|
** purpose : Delete the current queue element as pointed to by
|
|
* the cursor.
|
|
*
|
|
** parameters : queue pointer
|
|
*
|
|
** returns : pointer to data element.
|
|
*
|
|
** comments : WARNING! It is the responsibility of the caller to
|
|
* free any memory. Queue cannot distinguish between
|
|
* pointers to literals and malloced memory.
|
|
*
|
|
***/
|
|
|
|
void *Q_DelCur(queue* q) {
|
|
if(q) {
|
|
return Q_Iter_Del(q, (q_iter)q->cursor);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_Destroy
|
|
*
|
|
** purpose : Free all queue resources
|
|
*
|
|
** parameters : queue pointer
|
|
*
|
|
** returns : null.
|
|
*
|
|
** comments : WARNING! It is the responsibility of the caller to
|
|
* free any memory. Queue cannot distinguish between
|
|
* pointers to literals and malloced memory.
|
|
*
|
|
***/
|
|
|
|
void Q_Destroy(queue *q)
|
|
{
|
|
while(!Q_IsEmpty(q)) {
|
|
Q_PopHead(q);
|
|
}
|
|
}
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_Get
|
|
*
|
|
** purpose : get the pointer to the data at the cursor location
|
|
*
|
|
** parameters : queue pointer
|
|
*
|
|
** returns : data element pointer
|
|
*
|
|
** comments :
|
|
*
|
|
***/
|
|
|
|
void *Q_Get(queue *q)
|
|
{
|
|
if(!q)
|
|
return NULL;
|
|
|
|
if(q->cursor == NULL)
|
|
return NULL;
|
|
return q->cursor->data;
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_Put
|
|
*
|
|
** purpose : replace pointer to data with new pointer to data.
|
|
*
|
|
** parameters : queue pointer, data pointer
|
|
*
|
|
** returns : boolean- True_ if successful, False_ if cursor at NULL
|
|
*
|
|
** comments :
|
|
*
|
|
***/
|
|
|
|
int Q_Put(queue *q, void *data)
|
|
{
|
|
if(q && data) {
|
|
if(q->cursor == NULL)
|
|
return False_;
|
|
|
|
q->cursor->data = data;
|
|
return True_;
|
|
}
|
|
return False_;
|
|
}
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_Find
|
|
*
|
|
** purpose : Linear search of queue for match with key in *data
|
|
*
|
|
** parameters : queue pointer q, data pointer with data containing key
|
|
* comparison function here called Comp.
|
|
*
|
|
** returns : True_ if found , False_ if not in queue.
|
|
*
|
|
** comments : Useful for small queues that are constantly changing
|
|
* and would otherwise need constant sorting with the
|
|
* Q_Seek function.
|
|
* For description of Comp see Q_Sort.
|
|
* Queue cursor left on position found item else at end.
|
|
*
|
|
***/
|
|
|
|
int Q_Find(queue *q, void *data,
|
|
int (*Comp)(const void *, const void *))
|
|
{
|
|
void *d;
|
|
|
|
if (q == NULL) {
|
|
return False_;
|
|
}
|
|
|
|
d = Q_Head(q);
|
|
do {
|
|
if(Comp(d, data) == 0)
|
|
return True_;
|
|
d = Q_Next(q);
|
|
} while(!Q_AtTail(q));
|
|
|
|
if(Comp(d, data) == 0)
|
|
return True_;
|
|
|
|
return False_;
|
|
}
|
|
|
|
/*======== Sorted Queue and Index functions ========= */
|
|
|
|
|
|
static void QuickSort(void *list[], int low, int high,
|
|
int (*Comp)(const void *, const void *))
|
|
{
|
|
int flag = 1, i, j;
|
|
void *key, *temp;
|
|
|
|
if(low < high) {
|
|
i = low;
|
|
j = high + 1;
|
|
|
|
key = list[ low ];
|
|
|
|
while(flag) {
|
|
i++;
|
|
while(Comp(list[i], key) < 0)
|
|
i++;
|
|
|
|
j--;
|
|
while(Comp(list[j], key) > 0)
|
|
j--;
|
|
|
|
if(i < j) {
|
|
temp = list[i];
|
|
list[i] = list[j];
|
|
list[j] = temp;
|
|
}
|
|
else flag = 0;
|
|
}
|
|
|
|
temp = list[low];
|
|
list[low] = list[j];
|
|
list[j] = temp;
|
|
|
|
QuickSort(list, low, j-1, Comp);
|
|
QuickSort(list, j+1, high, Comp);
|
|
}
|
|
}
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_Sort
|
|
*
|
|
** purpose : sort the queue and allow index style access.
|
|
*
|
|
** parameters : queue pointer, comparison function compatible with
|
|
* with 'qsort'.
|
|
*
|
|
** returns : True_ if sort succeeded. False_ if error occurred.
|
|
*
|
|
** comments : Comp function supplied by caller must return
|
|
* -1 if data1 < data2
|
|
* 0 if data1 == data2
|
|
* +1 if data1 > data2
|
|
*
|
|
* for Comp(data1, data2)
|
|
*
|
|
* If queue is already sorted it frees the memory of the
|
|
* old index and starts again.
|
|
*
|
|
***/
|
|
|
|
int Q_Sort(queue *q, int (*Comp)(const void *, const void *))
|
|
{
|
|
int i;
|
|
void *d;
|
|
datanode *dn;
|
|
|
|
/* if already sorted free memory for tag array */
|
|
|
|
if(q->sorted) {
|
|
free(index);
|
|
free(posn_index);
|
|
q->sorted = False_;
|
|
}
|
|
|
|
/* Now allocate memory of array, array of pointers */
|
|
|
|
index = malloc(q->size * sizeof(q->cursor->data));
|
|
if(index == NULL)
|
|
return False_;
|
|
|
|
posn_index = malloc(q->size * sizeof(q->cursor));
|
|
if(posn_index == NULL) {
|
|
free(index);
|
|
return False_;
|
|
}
|
|
|
|
/* Walk queue putting pointers into array */
|
|
|
|
d = Q_Head(q);
|
|
for(i=0; i < q->size; i++) {
|
|
index[i] = d;
|
|
posn_index[i] = q->cursor;
|
|
d = Q_Next(q);
|
|
}
|
|
|
|
/* Now sort the index */
|
|
|
|
QuickSort(index, 0, q->size - 1, Comp);
|
|
|
|
/* Rearrange the actual queue into correct order */
|
|
|
|
dn = q->head;
|
|
i = 0;
|
|
while(dn != NULL) {
|
|
dn->data = index[i++];
|
|
dn = dn->next;
|
|
}
|
|
|
|
/* Re-position to original element */
|
|
|
|
if(d != NULL)
|
|
Q_Find(q, d, Comp);
|
|
else Q_Head(q);
|
|
|
|
q->sorted = True_;
|
|
|
|
return True_;
|
|
}
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_BSearch
|
|
*
|
|
** purpose : binary search of queue index for node containing key
|
|
*
|
|
** parameters : queue pointer 'q', data pointer of key 'key',
|
|
* Comp comparison function.
|
|
*
|
|
** returns : integer index into array of node pointers,
|
|
* or -1 if not found.
|
|
*
|
|
** comments : see Q_Sort for description of 'Comp' function.
|
|
*
|
|
***/
|
|
|
|
static int Q_BSearch( queue *q, void *key,
|
|
int (*Comp)(const void *, const void*))
|
|
{
|
|
int low, mid, hi, val;
|
|
|
|
low = 0;
|
|
hi = q->size - 1;
|
|
|
|
while(low <= hi) {
|
|
mid = (low + hi) / 2;
|
|
val = Comp(key, index[ mid ]);
|
|
|
|
if(val < 0)
|
|
hi = mid - 1;
|
|
|
|
else if(val > 0)
|
|
low = mid + 1;
|
|
|
|
else /* Success */
|
|
return mid;
|
|
}
|
|
|
|
/* Not Found */
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_Seek
|
|
*
|
|
** purpose : use index to locate data according to key in 'data'
|
|
*
|
|
** parameters : queue pointer 'q', data pointer 'data', Comp comparison
|
|
* function.
|
|
*
|
|
** returns : pointer to data or NULL if could not find it or could
|
|
* not sort queue.
|
|
*
|
|
** comments : see Q_Sort for description of 'Comp' function.
|
|
*
|
|
***/
|
|
|
|
void *Q_Seek(queue *q, void *data, int (*Comp)(const void *, const void *))
|
|
{
|
|
int idx;
|
|
|
|
if (q == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if(!q->sorted) {
|
|
if(!Q_Sort(q, Comp))
|
|
return NULL;
|
|
}
|
|
|
|
idx = Q_BSearch(q, data, Comp);
|
|
|
|
if(idx < 0)
|
|
return NULL;
|
|
|
|
q->cursor = posn_index[idx];
|
|
|
|
return index[idx];
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
*
|
|
** function : Q_Insert
|
|
*
|
|
** purpose : Insert an element into an indexed queue
|
|
*
|
|
** parameters : queue pointer 'q', data pointer 'data', Comp comparison
|
|
* function.
|
|
*
|
|
** returns : pointer to data or NULL if could not find it or could
|
|
* not sort queue.
|
|
*
|
|
** comments : see Q_Sort for description of 'Comp' function.
|
|
* WARNING! This code can be very slow since each new
|
|
* element means a new Q_Sort. Should only be used for
|
|
* the insertion of the odd element ,not the piecemeal
|
|
* building of an entire queue.
|
|
***/
|
|
|
|
int Q_Insert(queue *q, void *data, int (*Comp)(const void *, const void *))
|
|
{
|
|
if (q == NULL) {
|
|
return False_;
|
|
}
|
|
|
|
Q_PushHead(q, data);
|
|
|
|
if(!Q_Sort(q, Comp))
|
|
return False_;
|
|
|
|
return True_;
|
|
}
|
|
|
|
/* read only funcs for iterating through queue. above funcs modify queue */
|
|
q_iter Q_Iter_Head(queue *q) {
|
|
return q ? (q_iter)q->head : NULL;
|
|
}
|
|
|
|
q_iter Q_Iter_Tail(queue *q) {
|
|
return q ? (q_iter)q->tail : NULL;
|
|
}
|
|
|
|
q_iter Q_Iter_Next(q_iter qi) {
|
|
return qi ? (q_iter)((node*)qi)->next : NULL;
|
|
}
|
|
|
|
q_iter Q_Iter_Prev(q_iter qi) {
|
|
return qi ? (q_iter)((node*)qi)->prev : NULL;
|
|
}
|
|
|
|
void * Q_Iter_Get(q_iter qi) {
|
|
return qi ? ((node*)qi)->data : NULL;
|
|
}
|
|
|
|
int Q_Iter_Put(q_iter qi, void* data) {
|
|
if(qi) {
|
|
((node*)qi)->data = data;
|
|
return True_;
|
|
}
|
|
return False_;
|
|
}
|