Blame src/dalist.c

e09104
/*****************************************************************************/
e09104
/*  dalist: a zero-dependency book-keeping library                           */
0553af
/*  Copyright (C) 2013--2021  SysDeer Technologies, LLC                      */
e09104
/*  Released under GPLv2 and GPLv3; see COPYING.DALIST.                      */
e09104
/*****************************************************************************/
e09104
e09104
#include <dalist/dalist.h>
e09104
#include "dalist_impl.h"
e09104
e09104
e09104
dalist_api
e09104
int dalist_init(struct dalist *	dlist)
e09104
{
e09104
	dlist->head = dlist->tail = 0;
e09104
	return DALIST_OK;
e09104
}
e09104
e09104
e09104
dalist_api
e09104
int dalist_init_ex(
e09104
	struct dalist_ex *	dlist,
e09104
	size_t			dblock_size,
e09104
	size_t			lblock_size,
e09104
	void *			memfn_ptr,
e09104
	enum dalist_memfn	memfn_method)
e09104
e09104
{
e09104
	if (!dlist)
e09104
		return DALIST_ELIST;
e09104
e09104
	dlist->head = dlist->tail = 0;
e09104
e09104
	dlist->dblock_size = dblock_size;
e09104
	dlist->lblock_size = lblock_size;
e09104
e09104
	dlist->memfn_ptr    = memfn_ptr;
e09104
	dlist->memfn_method = memfn_method;
e09104
e09104
	dlist->free = 0;
e09104
	dlist->bookmarks = 0;
e09104
	dlist->memfn_status = 0;
e09104
e09104
	dlist->info.list_nodes = 0;
e09104
	dlist->info.free_nodes = 0;
e09104
e09104
	dlist->info.bookmark_from = 0;
e09104
	dlist->info.bookmark_to = 0;
e09104
e09104
	dlist->info.bookmark_key_min = 0;
e09104
	dlist->info.bookmark_key_max = 0;
e09104
e09104
	dlist->info.nodes_below_first_bookmark = 0;
e09104
	dlist->info.nodes_above_last_bookmark  = 0;
e09104
e09104
	return DALIST_OK;
e09104
}
e09104
e09104
e09104
dalist_api
e09104
int dalist_insert_before(
e09104
	struct dalist *		dlist,
e09104
	struct dalist_node *	lnode,
e09104
	struct dalist_node *	nnode)
e09104
{
e09104
	if (!dlist)
e09104
		return DALIST_ELIST;
e09104
e09104
	if (lnode) {
e09104
		/* insert before an existing node */
e09104
		nnode->prev = lnode->prev;
e09104
		nnode->next = lnode;
e09104
		lnode->prev = nnode;
e09104
e09104
		if (nnode->prev)
e09104
			nnode->prev->next = nnode;
e09104
		else
e09104
			dlist->head = nnode;
e09104
	} else {
e09104
		if (dlist->head)
e09104
			return DALIST_ENODE;
e09104
		else {
e09104
			/* nnode is the new head/tail */
e09104
			nnode->next = 0;
e09104
			nnode->prev = 0;
e09104
			dlist->head = nnode;
e09104
			dlist->tail = nnode;
e09104
		}
e09104
	}
e09104
e09104
	return DALIST_OK;
e09104
}
e09104
e09104
e09104
dalist_api
e09104
int dalist_insert_after(
e09104
	struct dalist *		dlist,
e09104
	struct dalist_node *	lnode,
e09104
	struct dalist_node *	nnode)
e09104
{
e09104
	if (!dlist)
e09104
		return DALIST_ELIST;
e09104
e09104
	if (lnode) {
e09104
		/* insert after an existing node */
e09104
		nnode->prev = lnode;
e09104
		nnode->next = lnode->next;
e09104
		lnode->next = nnode;
e09104
e09104
		if (nnode->next)
e09104
			nnode->next->prev = nnode;
e09104
		else
e09104
			dlist->tail = nnode;
e09104
	} else {
e09104
		if (dlist->head)
e09104
			return DALIST_ENODE;
e09104
		else {
e09104
			/* nnode is the new head/tail */
e09104
			nnode->next = 0;
e09104
			nnode->prev = 0;
e09104
			dlist->head = nnode;
e09104
			dlist->tail = nnode;
e09104
		}
e09104
	}
e09104
e09104
	return DALIST_OK;
e09104
}
e09104
e09104
e09104
dalist_api
e09104
int dalist_unlink_node(
e09104
	struct dalist *		dlist,
e09104
	struct dalist_node *	node)
e09104
{
e09104
	struct dalist_node * prev;
e09104
	struct dalist_node * next;
e09104
e09104
	if (!dlist)
e09104
		return DALIST_ELIST;
e09104
	else if (!node)
e09104
		return DALIST_ENODE;
e09104
e09104
	prev = node->prev;
e09104
	next = node->next;
e09104
e09104
	if (prev)
e09104
		prev->next = next;
e09104
	else
e09104
		dlist->head = next;
e09104
e09104
	if (next)
e09104
		next->prev = prev;
e09104
	else
e09104
		dlist->tail = prev;
e09104
e09104
	return DALIST_OK;
e09104
}
e09104
e09104
e09104
dalist_api
e09104
int dalist_unlink_node_ex(
e09104
	struct dalist_ex *	dlist,
e09104
	struct dalist_node_ex *	node)
e09104
{
e09104
	int ret;
e09104
e09104
	ret = dalist_unlink_node(
e09104
		(struct dalist *)dlist,
e09104
		(struct dalist_node *)node);
e09104
e09104
	if (ret == DALIST_OK)
e09104
		dlist->info.list_nodes--;
e09104
e09104
	return ret;
e09104
}
e09104
e09104
e09104
dalist_api
e09104
int dalist_discard_node(
e09104
	struct dalist_ex *	dlist,
e09104
	struct dalist_node_ex *	node)
e09104
{
e09104
	int ret;
e09104
e09104
	ret = dalist_unlink_node_ex(dlist,node);
e09104
e09104
	if (ret == DALIST_OK)
e09104
		ret = dalist_deposit_free_node(dlist,node);
e09104
e09104
	return ret;
e09104
}
e09104
e09104
e09104
dalist_api
e09104
int dalist_get_node_by_key(
e09104
	struct dalist_ex *	dlist,
e09104
	struct dalist_node_ex **node,
e09104
	uintptr_t		key,
e09104
	uintptr_t		get_flags,
e09104
	uintptr_t *		node_flags)
e09104
{
e09104
	struct dalist_node_ex *	cnode;
e09104
	struct dalist_node_ex *	nnode;
e09104
	uintptr_t		flags;
e09104
	int			ret;
e09104
e09104
	if (!dlist) return DALIST_ELIST;
e09104
e09104
	/* init */
e09104
	if (!node_flags)
e09104
		node_flags = &flag;;
e09104
e09104
	*node = 0;
e09104
	*node_flags = DALIST_NODE_TYPE_NONE;
e09104
e09104
	/* traverse */
e09104
	cnode = (struct dalist_node_ex *)dlist->head;
e09104
e09104
	while (cnode && (cnode->key < key))
e09104
		cnode = cnode->next;
e09104
e09104
	/* return matching node */
e09104
	if (cnode && (cnode->key == key)) {
e09104
		*node_flags = DALIST_NODE_TYPE_EXISTING;
e09104
		*node = cnode;
e09104
		return DALIST_OK;
e09104
	}
e09104
e09104
	/* key not found, possibly a new node */
e09104
	if (get_flags & DALIST_NODE_TYPE_NEW) {
e09104
		ret = dalist_get_free_node(dlist, (void **)&nnode);
e09104
		if (ret) return ret;
e09104
e09104
		nnode->key = key;
e09104
e09104
		if (cnode)
e09104
			ret = dalist_insert_before(
e09104
				(struct dalist *)dlist,
e09104
				(struct dalist_node *)cnode,
e09104
				(struct dalist_node *)nnode);
e09104
		else
e09104
			ret = dalist_insert_after(
e09104
				(struct dalist *)dlist,
e09104
				(struct dalist_node *)dlist->tail,
e09104
				(struct dalist_node *)nnode);
e09104
e09104
		if (ret == DALIST_OK) {
e09104
			*node = nnode;
e09104
			dlist->info.list_nodes++;
e09104
			*node_flags = DALIST_NODE_TYPE_NEW;
e09104
		} else
e09104
			dalist_deposit_free_node(dlist,nnode);
e09104
	} else
e09104
		ret = DALIST_OK;
e09104
e09104
	return ret;
e09104
}
e09104
e09104
e09104
dalist_api
e09104
int dalist_insert_node_by_key(
e09104
	struct dalist_ex *	dlist,
e09104
	struct dalist_node_ex *	node)
e09104
{
e09104
	struct dalist_node_ex *	cnode;
e09104
	int			ret;
e09104
e09104
	/* verify dlist */
e09104
	if (!dlist)
e09104
		return DALIST_ELIST;
e09104
e09104
	/* traverse */
e09104
	cnode = (struct dalist_node_ex *)dlist->head;
e09104
e09104
	while (cnode && (cnode->key < node->key))
e09104
		cnode = cnode->next;
e09104
e09104
	/* verify that node-> is unique */
e09104
	if (cnode && (cnode->key == node->key))
e09104
		return DALIST_EKEYEXISTS;
e09104
e09104
	/* key is unique, add a new node */
e09104
	if (cnode)
e09104
		ret = dalist_insert_before(
e09104
			(struct dalist *)dlist,
e09104
			(struct dalist_node *)cnode,
e09104
			(struct dalist_node *)node);
e09104
	else
e09104
		ret = dalist_insert_after(
e09104
			(struct dalist *)dlist,
e09104
			(struct dalist_node *)dlist->tail,
e09104
			(struct dalist_node *)node);
e09104
e09104
	if (ret == DALIST_OK)
e09104
		dlist->info.list_nodes++;
e09104
e09104
	return ret;
e09104
}