static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/ring.doc,v 1.12 1997/02/21 19:49:24 drh Exp $";
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "assert.h"
#include "ring.h"
#include "mem.h"
#define T Ring_T
struct T {
	struct node {
		struct node *llink, *rlink;
		void *value;
	} *head;
	int length;
};
T Ring_new(void) {
	T ring;
	NEW0(ring);
	ring->head = NULL;
	return ring;
}
T Ring_ring(void *x, ...) {
	va_list ap;
	T ring = Ring_new();
	va_start(ap, x);
	for ( ; x; x = va_arg(ap, void *))
		Ring_addhi(ring, x);
	va_end(ap);
	return ring;
}
void Ring_free(T *ring) {
	struct node *p, *q;
	assert(ring && *ring);
	if ((p = (*ring)->head) != NULL) {
		int n = (*ring)->length;
		for ( ; n-- > 0; p = q) {
			q = p->rlink;
			FREE(p);
		}
	}
	FREE(*ring);
}
int Ring_length(T ring) {
	assert(ring);
	return ring->length;
}
void *Ring_get(T ring, int i) {
	struct node *q;
	assert(ring);
	assert(i >= 0 && i < ring->length);
	{
		int n;
		q = ring->head;
		if (i <= ring->length/2)
			for (n = i; n-- > 0; )
				q = q->rlink;
		else
			for (n = ring->length - i; n-- > 0; )
				q = q->llink;
	}
	return q->value;
}
void *Ring_put(T ring, int i, void *x) {
	struct node *q;
	void *prev;
	assert(ring);
	assert(i >= 0 && i < ring->length);
	{
		int n;
		q = ring->head;
		if (i <= ring->length/2)
			for (n = i; n-- > 0; )
				q = q->rlink;
		else
			for (n = ring->length - i; n-- > 0; )
				q = q->llink;
	}
	prev = q->value;
	q->value = x;
	return prev;
}
void *Ring_addhi(T ring, void *x) {
	struct node *p, *q;
	assert(ring);
	NEW(p);
	if ((q = ring->head) != NULL)
		{
			p->llink = q->llink;
			q->llink->rlink = p;
			p->rlink = q;
			q->llink = p;
		}
	else
		ring->head = p->llink = p->rlink = p;
	ring->length++;
	return p->value = x;
}
void *Ring_addlo(T ring, void *x) {
	assert(ring);
	Ring_addhi(ring, x);
	ring->head = ring->head->llink;
	return x;
}
void *Ring_add(T ring, int pos, void *x) {
	assert(ring);
	assert(pos >= -ring->length && pos<=ring->length+1);
	if (pos == 1 || pos == -ring->length)
		return Ring_addlo(ring, x);
	else if (pos == 0 || pos == ring->length + 1)
		return Ring_addhi(ring, x);
	else {
		struct node *p, *q;
		int i = pos < 0 ? pos + ring->length : pos - 1;
		{
			int n;
			q = ring->head;
			if (i <= ring->length/2)
				for (n = i; n-- > 0; )
					q = q->rlink;
			else
				for (n = ring->length - i; n-- > 0; )
					q = q->llink;
		}
		NEW(p);
		{
			p->llink = q->llink;
			q->llink->rlink = p;
			p->rlink = q;
			q->llink = p;
		}
		ring->length++;
		return p->value = x;
	}
}
void *Ring_remove(T ring, int i) {
	void *x;
	struct node *q;
	assert(ring);
	assert(ring->length > 0);
	assert(i >= 0 && i < ring->length);
	{
		int n;
		q = ring->head;
		if (i <= ring->length/2)
			for (n = i; n-- > 0; )
				q = q->rlink;
		else
			for (n = ring->length - i; n-- > 0; )
				q = q->llink;
	}
	if (i == 0)
		ring->head = ring->head->rlink;
	x = q->value;
	q->llink->rlink = q->rlink;
	q->rlink->llink = q->llink;
	FREE(q);
	if (--ring->length == 0)
		ring->head = NULL;
	return x;
}
void *Ring_remhi(T ring) {
	void *x;
	struct node *q;
	assert(ring);
	assert(ring->length > 0);
	q = ring->head->llink;
	x = q->value;
	q->llink->rlink = q->rlink;
	q->rlink->llink = q->llink;
	FREE(q);
	if (--ring->length == 0)
		ring->head = NULL;
	return x;
}
void *Ring_remlo(T ring) {
	assert(ring);
	assert(ring->length > 0);
	ring->head = ring->head->rlink;
	return Ring_remhi(ring);
}
void Ring_rotate(T ring, int n) {
	struct node *q;
	int i;
	assert(ring);
	assert(n >= -ring->length && n <= ring->length);
	if (n >= 0)
		i = n%ring->length;
	else
		i = n + ring->length;
	{
		int n;
		q = ring->head;
		if (i <= ring->length/2)
			for (n = i; n-- > 0; )
				q = q->rlink;
		else
			for (n = ring->length - i; n-- > 0; )
				q = q->llink;
	}
	ring->head = q;
}


syntax highlighted by Code2HTML, v. 0.9.1