diff --git a/datalink814_ge/src/util/list.c b/datalink814_ge/src/util/list.c new file mode 100644 index 0000000..30ab871 --- /dev/null +++ b/datalink814_ge/src/util/list.c @@ -0,0 +1,301 @@ +#ifndef LIST_MALLOC +#define LIST_MALLOC malloc +#endif + +#ifndef LIST_FREE +#define LIST_FREE free +#endif + +// +// list.c +// +// Copyright (c) 2010 TJ Holowaychuk +// + +#include "list.h" + +/* + * Allocates a new list_node_t. NULL on failure. + */ + +list_node_t * +list_node_new(void *val) { + list_node_t *self; + if (!(self = LIST_MALLOC(sizeof(list_node_t)))) + return NULL; + self->prev = NULL; + self->next = NULL; + self->val = val; + return self; +} + +/* + * Allocate a new list_t. NULL on failure. + */ + +list_t * +list_new(void) { + list_t *self; + if (!(self = LIST_MALLOC(sizeof(list_t)))) + return NULL; + self->head = NULL; + self->tail = NULL; + self->free = NULL; + self->match = NULL; + self->len = 0; + return self; +} + +/* + * Remove all the node in list. + * @self: Pointer to the list + */ + +void +list_clear(list_t *self) { + uint32_t len = self->len; + list_node_t *next; + list_node_t *curr = self->head; + + while (len) { + next = curr->next; + if (self->free) self->free(curr->val); + LIST_FREE(curr); + curr = next; + len--; + } +} + +/* + * Free the list. + * @self: Pointer to the list + */ + +void +list_destroy(list_t *self) { + list_clear(self); + LIST_FREE(self); +} + +/* + * Append the given node to the list + * and return the node, NULL on failure. + * @self: Pointer to the list for popping node + * @node: the node to push + */ + +list_node_t * +list_rpush(list_t *self, list_node_t *node) { + if (!node) return NULL; + + if (self->len) { + node->prev = self->tail; + node->next = NULL; + self->tail->next = node; + self->tail = node; + } else { + self->head = self->tail = node; + node->prev = node->next = NULL; + } + + ++self->len; + return node; +} + +/* + * Return / detach the last node in the list, or NULL. + * @self: Pointer to the list for popping node + */ + +list_node_t * +list_rpop(list_t *self) { + if (!self->len) return NULL; + + list_node_t *node = self->tail; + + if (--self->len) { + (self->tail = node->prev)->next = NULL; + } else { + self->tail = self->head = NULL; + } + + node->next = node->prev = NULL; + return node; +} + +/* + * Return / detach the first node in the list, or NULL. + * @self: Pointer to the list for popping node + */ + +list_node_t * +list_lpop(list_t *self) { + if (!self->len) return NULL; + + list_node_t *node = self->head; + + if (--self->len) { + (self->head = node->next)->prev = NULL; + } else { + self->head = self->tail = NULL; + } + + node->next = node->prev = NULL; + return node; +} + +/* + * Prepend the given node to the list + * and return the node, NULL on failure. + * @self: Pointer to the list for pushing node + * @node: the node to push + */ + +list_node_t * +list_lpush(list_t *self, list_node_t *node) { + if (!node) return NULL; + + if (self->len) { + node->next = self->head; + node->prev = NULL; + self->head->prev = node; + self->head = node; + } else { + self->head = self->tail = node; + node->prev = node->next = NULL; + } + + ++self->len; + return node; +} + +/* + * Return the node associated to val or NULL. + * @self: Pointer to the list for finding given value + * @val: Value to find + */ + +list_node_t * +list_find(list_t *self, void *val) { + list_iterator_t *it = list_iterator_new(self, LIST_HEAD); + list_node_t *node; + + while ((node = list_iterator_next(it))) { + if (self->match) { + if (self->match(val, node->val)) { + list_iterator_destroy(it); + return node; + } + } else { + if (val == node->val) { + list_iterator_destroy(it); + return node; + } + } + } + + list_iterator_destroy(it); + return NULL; +} + +/* + * Return the node at the given index or NULL. + * @self: Pointer to the list for finding given index + * @index: the index of node in the list + */ + +list_node_t * +list_at(list_t *self, int index) { + list_direction_t direction = LIST_HEAD; + + if (index < 0) { + direction = LIST_TAIL; + index = ~index; + } + + if ((unsigned)index < self->len) { + list_iterator_t *it = list_iterator_new(self, direction); + list_node_t *node = list_iterator_next(it); + while (index--) node = list_iterator_next(it); + list_iterator_destroy(it); + return node; + } + + return NULL; +} + +/* + * Remove the given node from the list, freeing it and it's value. + * @self: Pointer to the list to delete a node + * @node: Pointer the node to be deleted + */ + +void +list_remove(list_t *self, list_node_t *node) { + node->prev + ? (node->prev->next = node->next) + : (self->head = node->next); + + node->next + ? (node->next->prev = node->prev) + : (self->tail = node->prev); + + if (self->free) self->free(node->val); + + LIST_FREE(node); + --self->len; +} + +/* + * Allocate a new list_iterator_t. NULL on failure. + * Accepts a direction, which may be LIST_HEAD or LIST_TAIL. + */ + +list_iterator_t * +list_iterator_new(list_t *list, list_direction_t direction) { + list_node_t *node = direction == LIST_HEAD + ? list->head + : list->tail; + return list_iterator_new_from_node(node, direction); +} + +/* + * Allocate a new list_iterator_t with the given start + * node. NULL on failure. + */ + +list_iterator_t * +list_iterator_new_from_node(list_node_t *node, list_direction_t direction) { + list_iterator_t *self; + if (!(self = LIST_MALLOC(sizeof(list_iterator_t)))) + return NULL; + self->next = node; + self->direction = direction; + return self; +} + +/* + * Return the next list_node_t or NULL when no more + * nodes remain in the list. + */ + +list_node_t * +list_iterator_next(list_iterator_t *self) { + list_node_t *curr = self->next; + if (curr) { + self->next = self->direction == LIST_HEAD + ? curr->next + : curr->prev; + } + return curr; +} + +/* + * Free the list iterator. + */ + +void +list_iterator_destroy(list_iterator_t *self) { + LIST_FREE(self); + self = NULL; +} diff --git a/datalink814_ge/src/util/list.h b/datalink814_ge/src/util/list.h new file mode 100644 index 0000000..685f0b4 --- /dev/null +++ b/datalink814_ge/src/util/list.h @@ -0,0 +1,114 @@ + +// +// list.h +// +// Copyright (c) 2010 TJ Holowaychuk +// + +#ifndef __LIST_H__ +#define __LIST_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* + * list_t iterator direction. + */ + +typedef enum { + LIST_HEAD, + LIST_TAIL +} list_direction_t; + +/* + * list_t node struct. + */ + +typedef struct list_node { + struct list_node *prev; + struct list_node *next; + void *val; +} list_node_t; + +/* + * list_t struct. + */ + +typedef struct { + list_node_t *head; + list_node_t *tail; + uint32_t len; + void (*free)(void *val); + bool (*match)(void *a, void *b); +} list_t; + +/* + * list_t iterator struct. + */ + +typedef struct { + list_node_t *next; + list_direction_t direction; +} list_iterator_t; + +// Node prototypes. + +list_node_t * +list_node_new(void *val); + +// list_t prototypes. + +list_t * +list_new(void); + +list_node_t * +list_rpush(list_t *self, list_node_t *node); + +list_node_t * +list_lpush(list_t *self, list_node_t *node); + +list_node_t * +list_find(list_t *self, void *val); + +list_node_t * +list_at(list_t *self, int index); + +list_node_t * +list_rpop(list_t *self); + +list_node_t * +list_lpop(list_t *self); + +void +list_remove(list_t *self, list_node_t *node); + +void +list_clear(list_t *self); + +void +list_destroy(list_t *self); + +// list_t iterator prototypes. + +list_iterator_t * +list_iterator_new(list_t *list, list_direction_t direction); + +list_iterator_t * +list_iterator_new_from_node(list_node_t *node, list_direction_t direction); + +list_node_t * +list_iterator_next(list_iterator_t *self); + +void +list_iterator_destroy(list_iterator_t *self); + +#ifdef __cplusplus +} +#endif + +#endif /* __CLIBS_LIST_H__ */