Blame src/list.h

Packit 549fdc
/*
Packit 549fdc
 * Copyright (C) 2001,2002 Paul Sheer
Packit 549fdc
 *
Packit 549fdc
 * This file is part of GnuTLS.
Packit 549fdc
 *
Packit 549fdc
 * GnuTLS is free software; you can redistribute it and/or modify
Packit 549fdc
 * it under the terms of the GNU General Public License as published by
Packit 549fdc
 * the Free Software Foundation; either version 3 of the License, or
Packit 549fdc
 * (at your option) any later version.
Packit 549fdc
 *
Packit 549fdc
 * GnuTLS is distributed in the hope that it will be useful,
Packit 549fdc
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 549fdc
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 549fdc
 * GNU General Public License for more details.
Packit 549fdc
 *
Packit 549fdc
 * You should have received a copy of the GNU General Public License
Packit 549fdc
 * along with this program; if not, write to the Free Software
Packit 549fdc
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Packit 549fdc
 */
Packit 549fdc
Packit 549fdc
/*
Packit 549fdc
    SOAP:
Packit 549fdc
    
Packit 549fdc
    Academics always want to implement hash tables (i.e. dictionaries),
Packit 549fdc
    singly or doubly linked lists, and queues, because ...  well ... they
Packit 549fdc
    know how.
Packit 549fdc
    
Packit 549fdc
    These datatypes are nonsense for the following reasons:
Packit 549fdc
	hash tables: Hash tables are a mapping of some
Packit 549fdc
	    string to some data, where that data is going to
Packit 549fdc
	    be accessed COMPLETELY RANDOMLY. This is what it
Packit 549fdc
	    is for. However it is extremely rare to have a
Packit 549fdc
	    large number of data elements which really are
Packit 549fdc
	    being accessed in a completely random way.
Packit 549fdc
Packit 549fdc
	lists: appending and searching through lists is always
Packit 549fdc
	    slow because these operations search all the way
Packit 549fdc
	    through the list.
Packit 549fdc
Packit 549fdc
	queues: whats the difference between a queue and a list?
Packit 549fdc
	    very little really.
Packit 549fdc
Packit 549fdc
    The system implemented here is a doubly linked list with previous
Packit 549fdc
    search index that can be appended or prepended with no overhead,
Packit 549fdc
    implemented entirely in macros. It is hence as versatile as a
Packit 549fdc
    doubly/singly linked list or queue and blazingly fast. Hence doing
Packit 549fdc
    sequential searches where the next search result is likely to be
Packit 549fdc
    closely indexed to the previous (usual case), is efficient.
Packit 549fdc
Packit 549fdc
    Of course this doesn't mean you should use this as a hash table
Packit 549fdc
    where you REALLY need a hash table.
Packit 549fdc
Packit 549fdc
*/
Packit 549fdc
Packit 549fdc
/********** example usage **********/
Packit 549fdc
/*
Packit 549fdc
Packit 549fdc
#include "list.h"
Packit 549fdc
Packit 549fdc
extern void free (void *x);
Packit 549fdc
extern char *strdup (char *s);
Packit 549fdc
Packit 549fdc
// consider a list of elements containing an `int' and a `char *'
Packit 549fdc
LIST_TYPE_DECLARE (names, char *s; int i;);
Packit 549fdc
Packit 549fdc
// for sorting, to compare elements
Packit 549fdc
static int cm (names **a, names **b)
Packit 549fdc
{
Packit 549fdc
    return strcmp ((*a)->s, (*b)->s);
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
// to free the contents of an element
Packit 549fdc
static void free_item (names *a)
Packit 549fdc
{
Packit 549fdc
    free (a->s);
Packit 549fdc
    a->s = 0;	// say
Packit 549fdc
    a->i = 0;	// say
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
int main (int argc, char **argv)
Packit 549fdc
{
Packit 549fdc
// you can separate these into LIST_TYPE_DECLARE(), LIST_DECLARE() and linit() if needed.
Packit 549fdc
    LIST_DECLARE_INIT (l, names, free_item);
Packit 549fdc
    names *j;
Packit 549fdc
Packit 549fdc
    lappend (l);
Packit 549fdc
    l.tail->s = strdup ("hello");
Packit 549fdc
    l.tail->i = 1;
Packit 549fdc
    lappend (l);
Packit 549fdc
    l.tail->s = strdup ("there");
Packit 549fdc
    l.tail->i = 2;
Packit 549fdc
    lappend (l);
Packit 549fdc
    l.tail->s = strdup ("my");
Packit 549fdc
    l.tail->i = 3;
Packit 549fdc
    lappend (l);
Packit 549fdc
    l.tail->s = strdup ("name");
Packit 549fdc
    l.tail->i = 4;
Packit 549fdc
    lappend (l);
Packit 549fdc
    l.tail->s = strdup ("is");
Packit 549fdc
    l.tail->i = 5;
Packit 549fdc
    lappend (l);
Packit 549fdc
    l.tail->s = strdup ("fred");
Packit 549fdc
    l.tail->i = 6;
Packit 549fdc
Packit 549fdc
    printf ("%ld\n\n", lcount (l));
Packit 549fdc
    lloopforward (l, j, printf ("%d %s\n", j->i, j->s));
Packit 549fdc
    printf ("\n");
Packit 549fdc
Packit 549fdc
    lsort (l, cm);
Packit 549fdc
    lloopforward (l, j, printf ("%d %s\n", j->i, j->s));
Packit 549fdc
Packit 549fdc
    lloopreverse (l, j, if (j->i <= 3) ldeleteinc (l, j););
Packit 549fdc
Packit 549fdc
    printf ("\n");
Packit 549fdc
    lloopforward (l, j, printf ("%d %s\n", j->i, j->s));
Packit 549fdc
Packit 549fdc
    ldeleteall (l);
Packit 549fdc
Packit 549fdc
    printf ("\n");
Packit 549fdc
    lloopforward (l, j, printf ("%d %s\n", j->i, j->s));
Packit 549fdc
    return 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
*/
Packit 549fdc
Packit 549fdc
Packit 549fdc
#ifndef _LIST_H
Packit 549fdc
#define _LIST_H
Packit 549fdc
Packit 549fdc
/* the `search' member points to the last found.
Packit 549fdc
   this speeds up repeated searches on the same list-item,
Packit 549fdc
   the consecutive list-item, or the pre-consecutive list-item.
Packit 549fdc
   this obviates the need for a hash table for 99% of
Packit 549fdc
   cercumstances the time */
Packit 549fdc
struct list {
Packit 549fdc
	long length;
Packit 549fdc
	long item_size;
Packit 549fdc
	struct list_item {
Packit 549fdc
		struct list_item *next;
Packit 549fdc
		struct list_item *prev;
Packit 549fdc
		char data[1];
Packit 549fdc
	} *head, *tail, *search;
Packit 549fdc
	void (*free_func) (struct list_item *);
Packit 549fdc
};
Packit 549fdc
Packit 549fdc
/* declare a list of type `x', also called `x' having members `typelist' */
Packit 549fdc
Packit 549fdc
#define LIST_TYPE_DECLARE(type,typelist)						\
Packit 549fdc
    typedef struct type {								\
Packit 549fdc
	struct type *next;								\
Packit 549fdc
	struct type *prev;								\
Packit 549fdc
	typelist									\
Packit 549fdc
    } type
Packit 549fdc
Packit 549fdc
#define LIST_DECLARE(l,type)								\
Packit 549fdc
    struct {										\
Packit 549fdc
	long length;									\
Packit 549fdc
	long item_size;									\
Packit 549fdc
	type *head, *tail, *search;							\
Packit 549fdc
	void (*free_func) (type *);							\
Packit 549fdc
    } l
Packit 549fdc
Packit 549fdc
#define LIST_DECLARE_INIT(l,type,free)							\
Packit 549fdc
    struct {										\
Packit 549fdc
	long length;									\
Packit 549fdc
	long item_size;									\
Packit 549fdc
	type *head, *tail, *search;							\
Packit 549fdc
	void (*free_func) (type *);							\
Packit 549fdc
    } l = {0, sizeof (type), 0, 0, 0, (void (*) (type *)) free}
Packit 549fdc
Packit 549fdc
#define linit(l,type,free)								\
Packit 549fdc
    {											\
Packit 549fdc
	memset (&(l), 0, sizeof (l));							\
Packit 549fdc
	(l).item_size = sizeof (type);							\
Packit 549fdc
	(l).free_func = free;								\
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
/* returns a pointer to the data of an item */
Packit 549fdc
#define ldata(i)	((void *) &((i)->data[0]))
Packit 549fdc
Packit 549fdc
/* returns a pointer to the list head */
Packit 549fdc
#define lhead(l)	((l).head)
Packit 549fdc
Packit 549fdc
/* returns a pointer to the list tail */
Packit 549fdc
#define ltail(l)	((l).tail)
Packit 549fdc
Packit 549fdc
#define lnewsearch(l)									\
Packit 549fdc
	(l).search = 0;
Packit 549fdc
Packit 549fdc
/* adds to the beginning of the list */
Packit 549fdc
#define lprepend(l)									\
Packit 549fdc
    {											\
Packit 549fdc
	struct list_item *__t;								\
Packit 549fdc
	__t = (struct list_item *) malloc ((l).item_size);				\
Packit 549fdc
	memset (__t, 0, (l).item_size);							\
Packit 549fdc
	__t->next = (l).head;								\
Packit 549fdc
	if (__t->next)									\
Packit 549fdc
	    __t->next->prev = __t;							\
Packit 549fdc
	__t->prev = 0;									\
Packit 549fdc
	if (!(l).tail)									\
Packit 549fdc
	    (l).tail = __t;								\
Packit 549fdc
	(l).head = __t;									\
Packit 549fdc
	length++;									\
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
/* adds to the end of the list */
Packit 549fdc
#define lappend(l)									\
Packit 549fdc
    {											\
Packit 549fdc
	struct list_item *__t;								\
Packit 549fdc
	__t = (struct list_item *) malloc ((l).item_size);				\
Packit 549fdc
	memset (__t, 0, (l).item_size);							\
Packit 549fdc
	__t->prev = (struct list_item *) (l).tail;					\
Packit 549fdc
	if (__t->prev)									\
Packit 549fdc
	    __t->prev->next = __t;							\
Packit 549fdc
	__t->next = 0;									\
Packit 549fdc
	if (!(l).head)									\
Packit 549fdc
	    (l).head = (void *) __t;							\
Packit 549fdc
	(l).tail = (void *) __t;							\
Packit 549fdc
	(l).length++;									\
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
/* you should free these manually */
Packit 549fdc
#define lunlink(l,e)									\
Packit 549fdc
    {											\
Packit 549fdc
	struct list_item *__t;								\
Packit 549fdc
	(l).search = 0;									\
Packit 549fdc
	__t = (void *) e;								\
Packit 549fdc
	if ((void *) (l).head == (void *) __t)						\
Packit 549fdc
	    (l).head = (l).head->next;							\
Packit 549fdc
	if ((void *) (l).tail == (void *) __t)						\
Packit 549fdc
	    (l).tail = (l).tail->prev;							\
Packit 549fdc
	if (__t->next)									\
Packit 549fdc
	    __t->next->prev = __t->prev;						\
Packit 549fdc
	if (__t->prev)									\
Packit 549fdc
	    __t->prev->next = __t->next;						\
Packit 549fdc
	(l).length--;									\
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
/* deletes list entry at point e, and increments e to the following list entry */
Packit 549fdc
#define ldeleteinc(l,e)									\
Packit 549fdc
    {											\
Packit 549fdc
	struct list_item *__t;								\
Packit 549fdc
	(l).search = 0;									\
Packit 549fdc
	__t = (void *) e;								\
Packit 549fdc
	if ((void *) (l).head == (void *) __t)						\
Packit 549fdc
	    (l).head = (l).head->next;							\
Packit 549fdc
	if ((void *) (l).tail == (void *) __t)						\
Packit 549fdc
	    (l).tail = (l).tail->prev;							\
Packit 549fdc
	if (__t->next)									\
Packit 549fdc
	    __t->next->prev = __t->prev;						\
Packit 549fdc
	if (__t->prev)									\
Packit 549fdc
	    __t->prev->next = __t->next;						\
Packit 549fdc
	__t = __t->next;								\
Packit 549fdc
	if ((l).free_func)								\
Packit 549fdc
	    (*(l).free_func) ((void *) e);						\
Packit 549fdc
	free (e);									\
Packit 549fdc
	e = (void *) __t;								\
Packit 549fdc
	(l).length--;									\
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
/* deletes list entry at point e, and deccrements e to the preceding list emtry */
Packit 549fdc
#define ldeletedec(l,e)									\
Packit 549fdc
    {											\
Packit 549fdc
	struct list_item *__t;								\
Packit 549fdc
	(l).search = 0;									\
Packit 549fdc
	__t = (void *) e;								\
Packit 549fdc
	if ((void *) (l).head == (void *) __t)						\
Packit 549fdc
	    (l).head = (l).head->next;							\
Packit 549fdc
	if ((void *) (l).tail == (void *) __t)						\
Packit 549fdc
	    (l).tail = (l).tail->prev;							\
Packit 549fdc
	if (__t->next)									\
Packit 549fdc
	    __t->next->prev = __t->prev;						\
Packit 549fdc
	if (__t->prev)									\
Packit 549fdc
	    __t->prev->next = __t->next;						\
Packit 549fdc
	__t = __t->prev;								\
Packit 549fdc
	if ((l).free_func)								\
Packit 549fdc
	    (*(l).free_func) ((void *) e);						\
Packit 549fdc
	free (e);									\
Packit 549fdc
	e = (void *) __t;								\
Packit 549fdc
	(l).length--;									\
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
/* p and q must be consecutive and neither must be zero */
Packit 549fdc
#define linsert(l,p,q)									\
Packit 549fdc
    {											\
Packit 549fdc
	struct list_item *__t;								\
Packit 549fdc
	__t = (struct list_item *) malloc ((l).item_size);				\
Packit 549fdc
	memset (__t, 0, (l).item_size);							\
Packit 549fdc
	__t->prev = (void *) p;								\
Packit 549fdc
	__t->next = (void *) q;								\
Packit 549fdc
	q->prev = (void *) __t;								\
Packit 549fdc
	p->next = (void *) __t;								\
Packit 549fdc
	(l).length++;									\
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
/* p and q must be consecutive and neither must be zero */
Packit 549fdc
#define ldeleteall(l)									\
Packit 549fdc
    {											\
Packit 549fdc
	(l).search = 0;									\
Packit 549fdc
	while ((l).head) {								\
Packit 549fdc
	    struct list_item *__p;							\
Packit 549fdc
	    __p = (struct list_item *) (l).head;					\
Packit 549fdc
	    lunlink(l, __p);								\
Packit 549fdc
	    if ((l).free_func)								\
Packit 549fdc
		(*(l).free_func) ((void *) __p);					\
Packit 549fdc
	    free (__p);									\
Packit 549fdc
	}										\
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
#define lloopstart(l,i)									\
Packit 549fdc
	for (i = (void *) (l).head; i;) {						\
Packit 549fdc
	    struct list_item *__tl;							\
Packit 549fdc
	    __tl = (void *) i->next;							\
Packit 549fdc
Packit 549fdc
#define lloopend(l,i)									\
Packit 549fdc
	    i = (void *) __tl;								\
Packit 549fdc
	}										\
Packit 549fdc
Packit 549fdc
#define lloopforward(l,i,op)								\
Packit 549fdc
    {											\
Packit 549fdc
	for (i = (void *) (l).head; i;) {						\
Packit 549fdc
	    struct list_item *__t;							\
Packit 549fdc
	    __t = (void *) i->next;							\
Packit 549fdc
	    op;										\
Packit 549fdc
	    i = (void *) __t;								\
Packit 549fdc
	}										\
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
#define lloopreverse(l,i,op)								\
Packit 549fdc
    {											\
Packit 549fdc
	for (i = (void *) (l).tail; i;) {						\
Packit 549fdc
	    struct list_item *__t;							\
Packit 549fdc
	    __t = (void *) i->prev;							\
Packit 549fdc
	    op;										\
Packit 549fdc
	    i = (void *) __t;								\
Packit 549fdc
	}										\
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
#define lindex(l,i,n)									\
Packit 549fdc
    {											\
Packit 549fdc
	int __k;									\
Packit 549fdc
	for (__k = 0, i = (void *) (l).head; i && __k != n; i = i->next, __k++);	\
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
#define lsearchforward(l,i,op)								\
Packit 549fdc
    {											\
Packit 549fdc
	int __found = 0;								\
Packit 549fdc
	if (!__found)									\
Packit 549fdc
	    if ((i = (void *) (l).search)) {						\
Packit 549fdc
		if (op) {								\
Packit 549fdc
		    __found = 1;							\
Packit 549fdc
		    (l).search = (void *) i;						\
Packit 549fdc
		}									\
Packit 549fdc
		if (!__found)								\
Packit 549fdc
		    if ((i = (void *) (l).search->next))				\
Packit 549fdc
			if (op) {							\
Packit 549fdc
			    __found = 1;						\
Packit 549fdc
			    (l).search = (void *) i;					\
Packit 549fdc
			}								\
Packit 549fdc
		if (!__found)								\
Packit 549fdc
		    if ((i = (void *) (l).search->prev))				\
Packit 549fdc
			if (op) {							\
Packit 549fdc
			    __found = 1;						\
Packit 549fdc
			    (l).search = (void *) i;					\
Packit 549fdc
			}								\
Packit 549fdc
	    }										\
Packit 549fdc
	if (!__found)									\
Packit 549fdc
	    for (i = (void *) (l).head; i; i = i->next)					\
Packit 549fdc
		if (op) {								\
Packit 549fdc
		    __found = 1;							\
Packit 549fdc
		    (l).search = (void *) i;						\
Packit 549fdc
		    break;								\
Packit 549fdc
		}									\
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
#define lsearchreverse(l,i,op)								\
Packit 549fdc
    {											\
Packit 549fdc
	int __found = 0;								\
Packit 549fdc
	if (!__found)									\
Packit 549fdc
	    if ((i = (void *) (l).search)) {						\
Packit 549fdc
		if (op) {								\
Packit 549fdc
		    __found = 1;							\
Packit 549fdc
		    (l).search = (void *) i;						\
Packit 549fdc
		}									\
Packit 549fdc
		if (!__found)								\
Packit 549fdc
		    if ((i = (void *) (l).search->prev))				\
Packit 549fdc
			if (op) {							\
Packit 549fdc
			    __found = 1;						\
Packit 549fdc
			    (l).search = (void *) i;					\
Packit 549fdc
			}								\
Packit 549fdc
		if (!__found)								\
Packit 549fdc
		    if ((i = (void *) (l).search->next))				\
Packit 549fdc
			if (op) {							\
Packit 549fdc
			    __found = 1;						\
Packit 549fdc
			    (l).search = (void *) i;					\
Packit 549fdc
			}								\
Packit 549fdc
	    }										\
Packit 549fdc
	if (!__found)									\
Packit 549fdc
	    for (i = (void *) (l).tail; i; i = i->prev)					\
Packit 549fdc
		if (op) {								\
Packit 549fdc
		    __found = 1;							\
Packit 549fdc
		    (l).search = (void *) i;						\
Packit 549fdc
		    break;								\
Packit 549fdc
		}									\
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
#define lcount(l)	((l).length)
Packit 549fdc
Packit 549fdc
/* sort with comparison function see qsort(3) */
Packit 549fdc
#define larray(l,a)									\
Packit 549fdc
    {											\
Packit 549fdc
	long __i;									\
Packit 549fdc
	struct list_item *__p;								\
Packit 549fdc
	a = (void *) malloc (((l).length + 1) * sizeof (void *));			\
Packit 549fdc
	for (__i = 0, __p = (void *) (l).head; __p; __p = __p->next, __i++)		\
Packit 549fdc
	    a[__i] = (void *) __p;							\
Packit 549fdc
	a[__i] = 0;									\
Packit 549fdc
    }											\
Packit 549fdc
Packit 549fdc
/* sort with comparison function see qsort(3) */
Packit 549fdc
#define llist(l,a)									\
Packit 549fdc
    {											\
Packit 549fdc
	struct list_item *__p;								\
Packit 549fdc
	(l).head = (void *) a[0];							\
Packit 549fdc
	(l).search = 0;									\
Packit 549fdc
	__p = (void *) a[0];								\
Packit 549fdc
	__p->prev = 0;									\
Packit 549fdc
	for (__j = 1; a[__j]; __j++, __p = __p->next) {					\
Packit 549fdc
	    __p->next = (void *) a[__j];						\
Packit 549fdc
	    __p->next->prev = __p;							\
Packit 549fdc
	}										\
Packit 549fdc
	(l).tail = (void *) __p;							\
Packit 549fdc
	__p->next = 0;									\
Packit 549fdc
    }											\
Packit 549fdc
Packit 549fdc
/* sort with comparison function see qsort(3) */
Packit 549fdc
#define lsort(l,compare)								\
Packit 549fdc
    {											\
Packit 549fdc
	void **__t;									\
Packit 549fdc
	long __j;									\
Packit 549fdc
	larray (l,__t);									\
Packit 549fdc
	qsort (__t, (l).length, sizeof (void *), (int (*) (const void *, const void *)) compare);	\
Packit 549fdc
	llist (l,__t);									\
Packit 549fdc
	free (__t);									\
Packit 549fdc
    }											\
Packit 549fdc
Packit 549fdc
#endif				/* _LIST_H */