qse/ase/lib/cmn/sll.c

288 lines
5.2 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 TOB(sll,len) ((len)*(sll)->scale)
#define size_t ase_size_t
#define mmgr_t ase_mmgr_t
sll_t* ase_sll_open (mmgr_t* mmgr, size_t ext)
{
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;
return ase_sll_init (sll, mmgr);
}
void ase_sll_close (sll_t* sll)
{
ase_sll_fini (sll);
ASE_MMGR_FREE (sll->mmgr, sll);
}
sll_t* ase_sll_init (sll_t* sll, mmgr_t* mmgr)
{
/* do not zero out the extension */
ASE_MEMSET (sll, 0, ASE_SIZEOF(sll_t));
sll->mmgr = mmgr;
sll->size = 0;
sll->scale = 1;
return sll;
}
void ase_sll_fini (sll_t* sll)
{
ase_sll_clear (sll);
}
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);
}
int ase_sll_getscale (sll_t* sll)
{
return sll->scale;
}
void ase_sll_setscale (sll_t* sll, int scale)
{
ASE_ASSERTX (scale > 0 && scale <= ASE_TYPE_MAX(ase_byte_t),
"The scale should be larger than 0 and less than or equal to the maximum value that the ase_byte_t type can hold");
if (scale <= 0) scale = 1;
if (scale > ASE_TYPE_MAX(ase_byte_t)) scale = ASE_TYPE_MAX(ase_byte_t);
sll->scale = scale;
}
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) + TOB(sll,dlen));
if (n == ASE_NULL) return ASE_NULL;
ASE_MEMCPY (n + 1, dptr, TOB(sll,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;
}
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_clear (sll_t* sll)
{
while (HEAD(sll) != ASE_NULL) ase_sll_delete (sll, HEAD(sll));
ASE_ASSERT (TAIL(sll) == ASE_NULL);
}
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_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;
}