qse/ase/lib/cmn/sll.c
2008-08-27 02:50:12 +00:00

259 lines
4.6 KiB
C

/*
* $Id$
*
* {License}
*/
#include <ase/cmn/sll.h>
#include "mem.h"
#define sll_t ase_sll_t
#define node_t ase_sll_node_t
#define copier_t ase_sll_copier_t
#define freeer_t ase_sll_freeer_t
#define walker_t ase_sll_walker_t
#define HEAD(s) ASE_SLL_HEAD(s)
#define TAIL(s) ASE_SLL_TAIL(s)
#define SIZE(s) ASE_SLL_SIZE(s)
#define DPTR(n) ASE_SLL_DPTR(n)
#define DLEN(n) ASE_SLL_DLEN(n)
#define NEXT(n) ASE_SLL_NEXT(n)
#define size_t ase_size_t
#define mmgr_t ase_mmgr_t
sll_t* ase_sll_open (mmgr_t* mmgr, size_t ext, void (*init) (sll_t*))
{
sll_t* sll;
if (mmgr == ASE_NULL)
{
mmgr = ASE_MMGR_GETDFL();
ASE_ASSERTX (mmgr != ASE_NULL,
"Set the memory manager with ASE_MMGR_SETDFL()");
if (mmgr == ASE_NULL) return ASE_NULL;
}
sll = ASE_MMGR_ALLOC (mmgr, ASE_SIZEOF(sll_t) + ext);
if (sll == ASE_NULL) return ASE_NULL;
ASE_MEMSET (sll, 0, ASE_SIZEOF(sll_t) + ext);
sll->mmgr = mmgr;
if (init) init (sll);
return sll;
}
void ase_sll_close (sll_t* sll)
{
ase_sll_clear (sll);
ASE_MMGR_FREE (sll->mmgr, sll);
}
void ase_sll_clear (sll_t* sll)
{
while (HEAD(sll) != ASE_NULL) ase_sll_delete (sll, HEAD(sll));
ASE_ASSERT (TAIL(sll) == ASE_NULL);
}
void* ase_sll_getextension (sll_t* sll)
{
return sll + 1;
}
mmgr_t* ase_sll_getmmgr (sll_t* sll)
{
return sll->mmgr;
}
void ase_sll_setmmgr (sll_t* sll, mmgr_t* mmgr)
{
sll->mmgr = mmgr;
}
size_t ase_sll_getsize (sll_t* sll)
{
return SIZE(sll);
}
node_t* ase_sll_gethead (sll_t* sll)
{
return HEAD(sll);
}
node_t* ase_sll_gettail (sll_t* sll)
{
return TAIL(sll);
}
copier_t ase_sll_getcopier (sll_t* sll)
{
return sll->copier;
}
void ase_sll_setcopier (sll_t* sll, copier_t copier)
{
sll->copier = copier;
}
freeer_t ase_sll_getfreeer (sll_t* sll)
{
return sll->freeer;
}
void ase_sll_setfreeer (sll_t* sll, freeer_t freeer)
{
sll->freeer = freeer;
}
static node_t* alloc_node (sll_t* sll, void* dptr, size_t dlen)
{
node_t* n;
if (sll->copier == ASE_NULL)
{
n = ASE_MMGR_ALLOC (sll->mmgr, ASE_SIZEOF(node_t));
if (n == ASE_NULL) return ASE_NULL;
DPTR(n) = dptr;
}
else if (sll->copier == ASE_SLL_COPIER_INLINE)
{
n = ASE_MMGR_ALLOC (sll->mmgr, ASE_SIZEOF(node_t) + dlen);
if (n == ASE_NULL) return ASE_NULL;
ASE_MEMCPY (n + 1, dptr, dlen);
DPTR(n) = n + 1;
}
else
{
n = ASE_MMGR_ALLOC (sll->mmgr, ASE_SIZEOF(node_t));
if (n == ASE_NULL) return ASE_NULL;
DPTR(n) = sll->copier (sll, dptr, dlen);
if (DPTR(n) == ASE_NULL)
{
ASE_MMGR_FREE (sll->mmgr, n);
return ASE_NULL;
}
}
DLEN(n) = dlen;
NEXT(n) = ASE_NULL;
return n;
}
node_t* ase_sll_insert (
sll_t* sll, node_t* pos, void* dptr, size_t dlen)
{
node_t* n = alloc_node (sll, dptr, dlen);
if (n == ASE_NULL) return ASE_NULL;
if (pos == ASE_NULL)
{
/* insert at the end */
if (HEAD(sll) == ASE_NULL)
{
ASE_ASSERT (TAIL(sll) == ASE_NULL);
HEAD(sll) = n;
}
else NEXT(TAIL(sll)) = n;
TAIL(sll) = n;
}
else
{
/* insert in front of the positional node */
NEXT(n) = pos;
if (pos == HEAD(sll)) HEAD(sll) = n;
else
{
/* take note of performance penalty */
node_t* n2 = HEAD(sll);
while (NEXT(n2) != pos) n2 = NEXT(n2);
NEXT(n2) = n;
}
}
SIZE(sll)++;
return n;
}
node_t* ase_sll_pushhead (sll_t* sll, void* data, size_t size)
{
return ase_sll_insert (sll, HEAD(sll), data, size);
}
node_t* ase_sll_pushtail (sll_t* sll, void* data, size_t size)
{
return ase_sll_insert (sll, ASE_NULL, data, size);
}
void ase_sll_delete (sll_t* sll, node_t* pos)
{
if (pos == ASE_NULL) return; /* not a valid node */
if (pos == HEAD(sll))
{
/* it is simple to delete the head node */
HEAD(sll) = NEXT(pos);
if (HEAD(sll) == ASE_NULL) TAIL(sll) = ASE_NULL;
}
else
{
/* but deletion of other nodes has significant performance
* penalty as it has look for the predecessor of the
* target node */
node_t* n2 = HEAD(sll);
while (NEXT(n2) != pos) n2 = NEXT(n2);
NEXT(n2) = NEXT(pos);
/* update the tail node if necessary */
if (pos == TAIL(sll)) TAIL(sll) = n2;
}
if (sll->freeer != ASE_NULL)
{
/* free the actual data */
sll->freeer (sll, DPTR(pos), DLEN(pos));
}
/* free the node */
ASE_MMGR_FREE (sll->mmgr, pos);
/* decrement the number of elements */
SIZE(sll)--;
}
void ase_sll_pophead (sll_t* sll)
{
ase_sll_delete (sll, HEAD(sll));
}
void ase_sll_poptail (sll_t* sll)
{
ase_sll_delete (sll, TAIL(sll));
}
void ase_sll_walk (sll_t* sll, walker_t walker, void* arg)
{
node_t* n = HEAD(sll);
while (n != ASE_NULL)
{
if (walker(sll,n,arg) == ASE_SLL_WALK_STOP) return;
n = NEXT(n);
}
}
void* ase_sll_copyinline (sll_t* sll, void* dptr, size_t dlen)
{
/* this is a dummy copier */
return ASE_NULL;
}