diff --git a/ase/include/ase/cmn/sll.h b/ase/include/ase/cmn/sll.h index ce524b69..8d979f38 100644 --- a/ase/include/ase/cmn/sll.h +++ b/ase/include/ase/cmn/sll.h @@ -15,6 +15,7 @@ */ typedef struct ase_sll_t ase_sll_t; typedef struct ase_sll_node_t ase_sll_node_t; +typedef enum ase_sll_walk_t ase_sll_walk_t; struct ase_sll_node_t { @@ -29,7 +30,13 @@ struct ase_sll_node_t typedef void* (*ase_sll_copier_t) (ase_sll_t* sll, void* data, ase_size_t len); typedef void (*ase_sll_freeer_t) (ase_sll_t* sll, void* data, ase_size_t len); -typedef int (*ase_sll_walker_t) (ase_sll_t* sll, ase_sll_node_t* node, void* arg); +typedef ase_sll_walk_t (*ase_sll_walker_t) (ase_sll_t* sll, ase_sll_node_t* node, void* arg); + +enum ase_sll_walk_t +{ + ASE_SLL_WALK_STOP = 0, + ASE_SLL_WALK_FORWARD = 1 +}; #define ASE_SLL_COPIER_INLINE ase_sll_copyinline @@ -85,6 +92,10 @@ void ase_sll_setcopier ( ase_sll_copier_t copier /* a element copier */ ); +ase_sll_copier_t ase_sll_getcopier ( + ase_sll_t* sll /* a singly linked list */ +); + /* * NAME specifies how to destroy an element * @@ -96,30 +107,51 @@ void ase_sll_setfreeer ( ase_sll_freeer_t freeer /* a element freeer */ ); +ase_sll_freeer_t ase_sll_getfreeer ( + ase_sll_t* sll /* a singly linked list */ +); + /* - * Returns the pointer to the extension area + * NAME Gets the pointer to the extension area + * RETURN the pointer to the extension area */ void* ase_sll_getextension ( ase_sll_t* sll /* a singly linked list */ ); /* - * Gets the number of elements held in a singly linked list - * RETURNS the number of elements the list holds + * NAME Gets the number of elements held in a singly linked list + * RETURN the number of elements the list holds */ ase_size_t ase_sll_getsize ( ase_sll_t* sll /* a singly linked list */ ); +/* + * NAME Gets the head(first) node + * RETURN the tail node of a singly linked list + */ ase_sll_node_t* ase_sll_gethead ( ase_sll_t* sll /* a singly linked list */ ); +/* + * NAME Gets the tail(last) node + * RETURN the tail node of a singly linked list + */ ase_sll_node_t* ase_sll_gettail ( ase_sll_t* sll /* a singly linked list */ ); -/* Inserts data before a positional node given */ +/* + * NAME Inserts data before a positional node given + * + * DESCRIPTION + * There is performance penalty unless the positional node is neither + * the head node nor ASE_NULL. You should consider a different data + * structure such as a doubly linked list if you need to insert data + * into a random position. + */ ase_sll_node_t* ase_sll_insert ( ase_sll_t* sll /* a singly linked list */, ase_sll_node_t* pos /* a node before which a new node is inserted */, @@ -127,14 +159,60 @@ ase_sll_node_t* ase_sll_insert ( ase_size_t dlen /* the length of the data in bytes */ ); -/* Traverses s singly linked list */ -void ase_sll_walk (ase_sll_t* sll, ase_sll_walker_t walker, void* arg); +ase_sll_node_t* ase_sll_pushhead ( + ase_sll_t* sll /* a singly linked list */, + void* dptr, + ase_size_t dlen +); + +ase_sll_node_t* ase_sll_pushtail ( + ase_sll_t* sll /* a singly linked list */, + void* dptr, + ase_size_t dlen +); + +void ase_sll_delete ( + ase_sll_t* sll, + ase_sll_node_t* pos +); + +void ase_sll_pophead ( + ase_sll_t* sll +); + +void ase_sll_poptail ( + ase_sll_t* sll +); + +/* + * NAME Traverses s singly linked list + * + * DESCRIPTION + * A singly linked list allows uni-directional in-order traversal. + * The ase_sll_walk() function traverses a singly linkked list from its + * head node down to its tail node as long as the walker function returns + * ASE_SLL_WALK_FORWARD. A walker can return ASE_SLL_WALK_STOP to cause + * immediate stop of traversal. + * For each node, the walker function is called and it is passed three + * parameters: the singly linked list, the visiting node, and the + * user-defined data passed as the third parameter in a call to the + * ase_sll_walk() function. + */ +void ase_sll_walk ( + ase_sll_t* sll /* a singly linked list */, + ase_sll_walker_t walker /* a user-defined walker function */, + void* arg /* pointer to user-defined data */ +); /* * Causes a singly linked list to copy in data to a node. * Use ASE_SLL_COPIER_INLINE instead. */ -void* ase_sll_copyinline (ase_sll_t* sll, void* data, ase_size_t len); +void* ase_sll_copyinline ( + ase_sll_t* sll /* a singly linked list */, + void* data /* pointer to data to copy */ , + ase_size_t len /* length of data in bytes */ +); #ifdef __cplusplus } diff --git a/ase/lib/cmn/sll.c b/ase/lib/cmn/sll.c index 543c5484..fd032a70 100644 --- a/ase/lib/cmn/sll.c +++ b/ase/lib/cmn/sll.c @@ -88,11 +88,21 @@ ase_sll_node_t* ase_sll_gettail (ase_sll_t* sll) return sll->tail; } +ase_sll_copier_t ase_sll_getcopier (ase_sll_t* sll) +{ + return sll->copier; +} + void ass_sll_setcopier (ase_sll_t* sll, ase_sll_copier_t copier) { sll->copier = copier; } +ase_sll_freeer_t ase_sll_getfreeer (ase_sll_t* sll) +{ + return sll->freeer; +} + void ase_sll_setfreeer (ase_sll_t* sll, ase_sll_freeer_t freeer) { sll->freeer = freeer; @@ -154,6 +164,7 @@ ase_sll_node_t* ase_sll_insert ( if (pos == sll->head) sll->head = n; else { + /* take note of performance penalty */ ase_sll_node_t* n2 = sll->head; while (n2->next != pos) n2 = n2->next; n2->next = n; @@ -164,23 +175,54 @@ ase_sll_node_t* ase_sll_insert ( return n; } -ase_sll_node_t* ase_sll_prepend (ase_sll_t* sll, void* data, ase_size_t size) +ase_sll_node_t* ase_sll_pushhead (ase_sll_t* sll, void* data, ase_size_t size) { return ase_sll_insert (sll, sll->head, data, size); } -ase_sll_node_t* ase_sll_append (ase_sll_t* sll, void* data, ase_size_t size) +ase_sll_node_t* ase_sll_pushtail (ase_sll_t* sll, void* data, ase_size_t size) { return ase_sll_insert (sll, ASE_NULL, data, size); } +void ase_sll_delete (ase_sll_t* sll, ase_sll_node_t* pos) +{ + ASE_ASSERT (pos != ASE_NULL); + + if (pos == sll->head) + { + sll->head = pos->next; + if (sll->head == ASE_NULL) sll->tail = ASE_NULL; + } + else + { + /* take note of performance penalty */ + ase_sll_node_t* n2 = sll->head; + while (n2->next != pos) n2 = n2->next; + n2->next = pos->next; + if (pos == sll->tail) sll->tail = n2; + } + + sll->size--; +} + +void ase_sll_pophead (ase_sll_t* sll) +{ + ase_sll_delete (sll, sll->head); +} + +void ase_sll_poptail (ase_sll_t* sll) +{ + ase_sll_delete (sll, sll->tail); +} + void ase_sll_walk (ase_sll_t* sll, ase_sll_walker_t walker, void* arg) { ase_sll_node_t* n = sll->head; while (n != ASE_NULL) { - walker (sll, n, arg); + if (walker(sll,n,arg) == ASE_SLL_WALK_STOP) return; n = n->next; } }