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