⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 listfunc.c

📁 早期freebsd实现
💻 C
字号:
/* * Copyright (c) 1993 David I. Bell * Permission is granted to use, distribute, or modify this source, * provided that this copyright notice remains intact. * * List handling routines. * Lists can be composed of any types of values, mixed if desired. * Lists are doubly linked so that elements can be inserted or * deleted efficiently at any point in the list.  A pointer is * kept to the most recently indexed element so that sequential * accesses are fast. */#include "value.h"static LISTELEM *elemalloc MATH_PROTO((void));static LISTELEM *listelement MATH_PROTO((LIST *lp, long index));static void elemfree MATH_PROTO((LISTELEM *ep));static void removelistelement MATH_PROTO((LIST *lp, LISTELEM *ep));/* * Free lists for list headers and list elements. */static FREELIST	headerfreelist = {	sizeof(LIST),		/* size of list header */	20			/* number of free headers to keep */};static FREELIST elementfreelist = {	sizeof(LISTELEM),	/* size of list element */	1000			/* number of free list elements to keep */};/* * Insert an element before the first element of a list. */voidinsertlistfirst(lp, vp)	LIST *lp;		/* list to put element onto */	VALUE *vp;		/* value to be inserted */{	LISTELEM *ep;		/* list element */	ep = elemalloc();	copyvalue(vp, &ep->e_value);	if (lp->l_count == 0)		lp->l_last = ep;	else {		lp->l_cacheindex++;		lp->l_first->e_prev = ep;		ep->e_next = lp->l_first;	}	lp->l_first = ep;	lp->l_count++;}/* * Insert an element after the last element of a list. */voidinsertlistlast(lp, vp)	LIST *lp;		/* list to put element onto */	VALUE *vp;		/* value to be inserted */{	LISTELEM *ep;		/* list element */	ep = elemalloc();	copyvalue(vp, &ep->e_value);	if (lp->l_count == 0)		lp->l_first = ep;	else {		lp->l_last->e_next = ep;		ep->e_prev = lp->l_last;	}	lp->l_last = ep;	lp->l_count++;}/* * Insert an element into the middle of list at the given index (zero based). * The specified index will select the new element, so existing elements * at or beyond the index will be shifted down one position.  It is legal * to specify an index which is right at the end of the list, in which * case the element is appended to the list. */voidinsertlistmiddle(lp, index, vp)	LIST *lp;		/* list to put element onto */	long index;		/* element number to insert in front of */	VALUE *vp;		/* value to be inserted */{	LISTELEM *ep;		/* list element */	LISTELEM *oldep;	/* old list element at desired index */	if (index == 0) {		insertlistfirst(lp, vp);		return;	}	if (index == lp->l_count) {		insertlistlast(lp, vp);		return;	}	oldep = NULL;	if ((index >= 0) && (index < lp->l_count))		oldep = listelement(lp, index);	if (oldep == NULL)		math_error("Index out of bounds for list insertion");	ep = elemalloc();	copyvalue(vp, &ep->e_value);	ep->e_next = oldep;	ep->e_prev = oldep->e_prev;	ep->e_prev->e_next = ep;	oldep->e_prev = ep;	lp->l_cache = ep;	lp->l_cacheindex = index;	lp->l_count++;}/* * Remove the first element from a list, returning its value. * Returns the null value if no more elements exist. */voidremovelistfirst(lp, vp)	LIST *lp;		/* list to have element removed */	VALUE *vp;		/* location of the value */{	if (lp->l_count == 0) {		vp->v_type = V_NULL;		return;	}	*vp = lp->l_first->e_value;	lp->l_first->e_value.v_type = V_NULL;	removelistelement(lp, lp->l_first);}/* * Remove the last element from a list, returning its value. * Returns the null value if no more elements exist. */voidremovelistlast(lp, vp)	LIST *lp;		/* list to have element removed */	VALUE *vp;		/* location of the value */{	if (lp->l_count == 0) {		vp->v_type = V_NULL;		return;	}	*vp = lp->l_last->e_value;	lp->l_last->e_value.v_type = V_NULL;	removelistelement(lp, lp->l_last);}/* * Remove the element with the given index from a list, returning its value. */voidremovelistmiddle(lp, index, vp)	LIST *lp;		/* list to have element removed */	long index;		/* list element to be removed */	VALUE *vp;		/* location of the value */{	LISTELEM *ep;		/* element being removed */	ep = NULL;	if ((index >= 0) && (index < lp->l_count))		ep = listelement(lp, index);	if (ep == NULL)		math_error("Index out of bounds for list deletion");	*vp = ep->e_value;	ep->e_value.v_type = V_NULL;	removelistelement(lp, ep);}/* * Remove an arbitrary element from a list. * The value contained in the element is freed. */static voidremovelistelement(lp, ep)	register LIST *lp;		/* list header */	register LISTELEM *ep;		/* list element to remove */{	if ((ep == lp->l_cache) || ((ep != lp->l_first) && (ep != lp->l_last)))		lp->l_cache = NULL;	if (ep->e_next)		ep->e_next->e_prev = ep->e_prev;	if (ep->e_prev)		ep->e_prev->e_next = ep->e_next;	if (ep == lp->l_first) {		lp->l_first = ep->e_next;		lp->l_cacheindex--;	}	if (ep == lp->l_last)		lp->l_last = ep->e_prev;	lp->l_count--;	elemfree(ep);}/* * Search a list for the specified value starting at the specified index. * Returns the element number (zero based) of the found value, or -1 if * the value was not found. */longlistsearch(lp, vp, index)	LIST *lp;	VALUE *vp;	long index;{	register LISTELEM *ep;	if (index < 0)		index = 0;	ep = listelement(lp, index);	while (ep) {		if (!comparevalue(&ep->e_value, vp)) {			lp->l_cache = ep;			lp->l_cacheindex = index;			return index;		}		ep = ep->e_next;		index++;	}	return -1;}/* * Search a list backwards for the specified value starting at the * specified index.  Returns the element number (zero based) of the * found value, or -1 if the value was not found. */longlistrsearch(lp, vp, index)	LIST *lp;	VALUE *vp;	long index;{	register LISTELEM *ep;	if (index >= lp->l_count)		index = lp->l_count - 1;	ep = listelement(lp, index);	while (ep) {		if (!comparevalue(&ep->e_value, vp)) {			lp->l_cache = ep;			lp->l_cacheindex = index;			return index;		}		ep = ep->e_prev;		index--;	}	return -1;}/* * Index into a list and return the address for the value corresponding * to that index.  Returns NULL if the element does not exist. */VALUE *listfindex(lp, index)	LIST *lp;		/* list to index into */	long index;		/* index of desired element */{	LISTELEM *ep;	ep = listelement(lp, index);	if (ep == NULL)		return NULL;	return &ep->e_value;}/* * Return the element at a specified index number of a list. * The list is indexed starting at zero, and negative indices * indicate to index from the end of the list.  This routine finds * the element by chaining through the list from the closest one * of the first, last, and cached elements.  Returns NULL if the * element does not exist. */static LISTELEM *listelement(lp, index)	register LIST *lp;	/* list to index into */	long index;		/* index of desired element */{	register LISTELEM *ep;	/* current list element */	long dist;		/* distance to element */	long temp;		/* temporary distance */	BOOL forward;		/* TRUE if need to walk forwards */	if (index < 0)		index += lp->l_count;	if ((index < 0) || (index >= lp->l_count))		return NULL;	/*	 * Check quick special cases first.	 */	if (index == 0)		return lp->l_first;	if (index == 1)		return lp->l_first->e_next;	if (index == lp->l_count - 1)		return lp->l_last;	if ((index == lp->l_cacheindex) && lp->l_cache)		return lp->l_cache;	/*	 * Calculate whether it is better to go forwards from	 * the first element or backwards from the last element.	 */	forward = ((index * 2) <= lp->l_count);	if (forward) {		dist = index;		ep = lp->l_first;	} else {		dist = (lp->l_count - 1) - index;		ep = lp->l_last;	}	/*	 * Now see if we have a cached element and if so, whether or	 * not the distance from it is better than the above distance.	 */	if (lp->l_cache) {		temp = index - lp->l_cacheindex;		if ((temp >= 0) && (temp < dist)) {			dist = temp;			ep = lp->l_cache;			forward = TRUE;		}		if ((temp < 0) && (-temp < dist)) {			dist = -temp;			ep = lp->l_cache;			forward = FALSE;		}	}	/*	 * Now walk forwards or backwards from the selected element	 * until we reach the correct element.  Cache the location of	 * the found element for future use.	 */	if (forward) {		while (dist-- > 0)			ep = ep->e_next;	} else {		while (dist-- > 0)			ep = ep->e_prev;	}	lp->l_cache = ep;	lp->l_cacheindex = index;	return ep;}/* * Compare two lists to see if they are identical. * Returns TRUE if they are different. */BOOLlistcmp(lp1, lp2)	LIST *lp1, *lp2;{	LISTELEM *e1, *e2;	long count;	if (lp1 == lp2)		return FALSE;	if (lp1->l_count != lp2->l_count)		return TRUE;	e1 = lp1->l_first;	e2 = lp2->l_first;	count = lp1->l_count;	while (count-- > 0) {		if (comparevalue(&e1->e_value, &e2->e_value))			return TRUE;		e1 = e1->e_next;		e2 = e2->e_next;	}	return FALSE;}/* * Copy a list */LIST *listcopy(oldlp)	LIST *oldlp;{	LIST *lp;	LISTELEM *oldep;	lp = listalloc();	oldep = oldlp->l_first;	while (oldep) {		insertlistlast(lp, &oldep->e_value);		oldep = oldep->e_next;	}	return lp;}/* * Allocate an element for a list. */static LISTELEM *elemalloc(){	LISTELEM *ep;	ep = (LISTELEM *) allocitem(&elementfreelist);	if (ep == NULL)		math_error("Cannot allocate list element");	ep->e_next = NULL;	ep->e_prev = NULL;	ep->e_value.v_type = V_NULL;	return ep;}/* * Free a list element, along with any contained value. */static voidelemfree(ep)	LISTELEM *ep;{	if (ep->e_value.v_type != V_NULL)		freevalue(&ep->e_value);	freeitem(&elementfreelist, (FREEITEM *) ep);}/* * Allocate a new list header. */LIST *listalloc(){	register LIST *lp;	lp = (LIST *) allocitem(&headerfreelist);	if (lp == NULL)		math_error("Cannot allocate list header");	lp->l_first = NULL;	lp->l_last = NULL;	lp->l_cache = NULL;	lp->l_cacheindex = 0;	lp->l_count = 0;	return lp;}/* * Free a list header, along with all of its list elements. */voidlistfree(lp)	register LIST *lp;{	register LISTELEM *ep;	while (lp->l_count-- > 0) {		ep = lp->l_first;		lp->l_first = ep->e_next;		elemfree(ep);	}	freeitem(&headerfreelist, (FREEITEM *) lp);}/* * Print out a list along with the specified number of its elements. * The elements are printed out in shortened form. */voidlistprint(lp, max_print)	LIST *lp;	long max_print;{	long count;	long index;	LISTELEM *ep;	if (max_print > lp->l_count)		max_print = lp->l_count;	count = 0;	ep = lp->l_first;	index = lp->l_count;	while (index-- > 0) {		if ((ep->e_value.v_type != V_NUM) ||			(!qiszero(ep->e_value.v_num)))				count++;		ep = ep->e_next;	}	if (max_print > 0)		math_str("\n");	math_fmt("list (%ld element%s, %ld nonzero)", lp->l_count,		((lp->l_count == 1) ? "" : "s"), count);	if (max_print <= 0)		return;	/*	 * Walk through the first few list elements, printing their	 * value in short and unambiguous format.	 */	math_str(":\n");	ep = lp->l_first;	for (index = 0; index < max_print; index++) {		math_fmt("  [[%ld]] = ", index);		printvalue(&ep->e_value, PRINT_SHORT | PRINT_UNAMBIG);		math_str("\n");		ep = ep->e_next;	}	if (max_print < lp->l_count)		math_str("  ...\n");}/* * Return a trivial hash value for a list. */HASHlisthash(lp)	LIST *lp;{	HASH hash;	hash = lp->l_count * 600011;	if (lp->l_count > 0)		hash = hash * 600043 + hashvalue(&lp->l_first->e_value);	if (lp->l_count > 1)		hash = hash * 600053 + hashvalue(&lp->l_last->e_value);	return hash;}/* END CODE */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -