Mercurial > hg > th-libs
diff th_datastruct.c @ 269:fcbdc12f5866
Split data structures (linked lists, growbufs, ringbufs, etc.) code into th_datastruct.[ch] module.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Wed, 17 Feb 2016 14:20:36 +0200 |
parents | |
children | 2f067fbf6f13 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/th_datastruct.c Wed Feb 17 14:20:36 2016 +0200 @@ -0,0 +1,540 @@ +/* + * Various data structure functions + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2002-2016 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#include "th_datastruct.h" + +/* + * Doubly linked list handling + * + * In this implementation first node's prev points to last node of the list, + * and last node's next is NULL. This way we can semi-efficiently traverse to + * beginning and end of the list, assuming user does not do weird things. + */ +th_llist_t * th_llist_new(void *data) +{ + th_llist_t *res = th_malloc0(sizeof(th_llist_t)); + res->data = data; + return res; +} + + +void th_llist_free_func_node(th_llist_t *list, void (*freefunc)(th_llist_t *)) +{ + th_llist_t *curr = list; + + while (curr != NULL) + { + th_llist_t *next = curr->next; + freefunc(curr); + curr = next; + } +} + + +void th_llist_free_func(th_llist_t *list, void (*freefunc)(void *data)) +{ + th_llist_t *curr = list; + + while (curr != NULL) + { + th_llist_t *next = curr->next; + if (curr->data != NULL) + freefunc(curr->data); + th_free(curr); + curr = next; + } +} + + +void th_llist_free(th_llist_t *list) +{ + th_llist_t *curr = list; + + while (curr != NULL) + { + th_llist_t *next = curr->next; + th_free(curr); + curr = next; + } +} + + +void th_llist_append_node(th_llist_t **list, th_llist_t *node) +{ + if (*list != NULL) + { + node->prev = (*list)->prev; + (*list)->prev->next = node; + (*list)->prev = node; + (*list)->num++; + } + else + { + *list = node; + node->prev = node; + (*list)->num = 1; + } + + node->next = NULL; +} + + +th_llist_t *th_llist_append(th_llist_t **list, void *data) +{ + th_llist_t *node = th_llist_new(data); + + th_llist_append_node(list, node); + + return node; +} + + +void th_llist_prepend_node(th_llist_t **list, th_llist_t *node) +{ + if (*list != NULL) + { + node->prev = (*list)->prev; + node->next = *list; + (*list)->prev = node; + node->num = (*list)->num + 1; + *list = node; + } + else + { + *list = node->prev = node; + node->next = NULL; + (*list)->num = 1; + } + +} + + +th_llist_t *th_llist_prepend(th_llist_t **list, void *data) +{ + th_llist_t *node = th_llist_new(data); + + th_llist_prepend_node(list, node); + + return node; +} + +/* +1) Remove a middle node + + node0->prev->next = node->next (node1) + node0->next->prev = node->prev (list) + + node2 <- list <=> node0 <=> node1 <=> node2 -> NULL + node2 <- list <=> node1 <=> node2 -> NULL + +2) Remove first node when many items + + + node2 <- list <=> node0 <=> node1 <=> node2 -> NULL + node2 <- node0 <=> node1 <=> node2 -> NULL + + *list = node0 + +3) Remove last node in list + + if (node->next == NULL) { + list->prev = node->prev; + node->prev->next = NULL; + } + + node2 <- list <=> node0 <=> node1 <=> node2 -> NULL + node1 <- list <=> node0 <=> node1 -> NULL + +4) Remove last + + list <- list -> NULL + + +*/ +void th_llist_delete_node_fast(th_llist_t **list, th_llist_t *node) +{ + if (node == *list) + { + // First node in list + th_llist_t *tmp = (*list)->next; + if (tmp != NULL) + { + tmp->num = (*list)->num - 1; + tmp->prev = (*list)->prev; + } + *list = tmp; + } + else + { + // Somewhere in middle or end + if (node->prev != NULL) + node->prev->next = node->next; + + if (node->next != NULL) + node->next->prev = node->prev; + else + (*list)->prev = node; // Last node + + (*list)->num--; + } + + node->next = node->prev = NULL; +} + + +void th_llist_delete_node(th_llist_t **list, th_llist_t *node) +{ + th_llist_t *curr = *list; + + while (curr != NULL) + { + th_llist_t *next = curr->next; + if (curr == node) + { + th_llist_delete_node_fast(list, curr); + th_free(node); + break; + } + curr = next; + } +} + + +void th_llist_delete(th_llist_t **list, const void *data) +{ + th_llist_t *curr = *list; + + while (curr != NULL) + { + th_llist_t *next = curr->next; + if (curr->data == data) + { + th_llist_delete_node_fast(list, curr); + th_free(curr); + break; + } + curr = next; + } +} + + +th_llist_t * th_llist_get_nth(th_llist_t *list, const size_t n) +{ + th_llist_t *curr = list; + size_t i; + + for (i = 0; curr != NULL && i < n; curr = curr->next, i++); + + return curr; +} + + +size_t th_llist_length(const th_llist_t *list) +{ + if (list == NULL) + return 0; + else + return list->num; +} + + +ssize_t th_llist_position(const th_llist_t *list, const th_llist_t *node) +{ + const th_llist_t *curr = list; + ssize_t i = 0; + + while (curr != NULL) + { + if (curr == node) + return i; + else + i++; + + curr = curr->next; + } + + return -1; +} + + +void th_llist_foreach(th_llist_t *list, void (*func)(th_llist_t *node, void *userdata), void *data) +{ + th_llist_t *curr = list; + + while (curr != NULL) + { + func(curr, data); + curr = curr->next; + } +} + + +int th_llist_foreach_cond(th_llist_t *list, int (*func)(th_llist_t *node, void *userdata), void *data, th_llist_t **ret) +{ + th_llist_t *curr = list; + + while (curr != NULL) + { + int res = func(curr, data); + if (res != 0) + { + *ret = curr; + return res; + } + curr = curr->next; + } + + return 0; +} + + +th_llist_t * th_llist_find(th_llist_t *list, const void *data) +{ + th_llist_t *curr = list; + + while (curr != NULL) + { + if (curr->data == data) + return curr; + curr = curr->next; + } + + return NULL; +} + + +th_llist_t * th_llist_find_func(th_llist_t *list, const void *userdata, int (compare)(const void *, const void *)) +{ + th_llist_t *curr = list; + + while (curr != NULL) + { + if (compare(curr->data, userdata) == 0) + return curr; + curr = curr->next; + } + + return NULL; +} + + +/* + * Ringbuffers + */ +th_ringbuf_t * th_ringbuf_new(const size_t size, void (*mdeallocator)(void *data)) +{ + th_ringbuf_t *res = th_malloc0(sizeof(th_ringbuf_t)); + + res->data = (char **) th_calloc(size, sizeof(char *)); + res->size = size; + res->n = 0; + res->deallocator = mdeallocator; + + return res; +} + + +BOOL th_ringbuf_grow(th_ringbuf_t *buf, const size_t n) +{ + buf->data = (char **) th_realloc(buf->data, (buf->size + n) * sizeof(char *)); + if (buf->data != NULL) + { + memset(buf->data + buf->size, 0, sizeof(char *) * n); + buf->size += n; + return TRUE; + } else + return FALSE; +} + + +void th_ringbuf_free(th_ringbuf_t *buf) +{ + int i; + + for (i = 0; i < buf->size; i++) + { + if (buf->data[i] != NULL) + buf->deallocator(buf->data[i]); + } + + th_free(buf->data); + th_free(buf); +} + + +void th_ringbuf_add(th_ringbuf_t *buf, void *ptr) +{ + if (buf->n < buf->size) + buf->n++; + + th_free(buf->data[0]); + memmove(&(buf->data[0]), &(buf->data[1]), (buf->size - 1) * sizeof(void *)); + buf->data[buf->size - 1] = ptr; +} + + +/* + * Growing buffer + */ +void th_growbuf_clear(th_growbuf_t *buf) +{ + // Simply reset the current "length" + buf->len = 0; +} + + +void th_growbuf_init(th_growbuf_t *buf, const size_t mingrow) +{ + // Initialize the buffer structure + memset(buf, 0, sizeof(th_growbuf_t)); + buf->mingrow = mingrow; +} + + +th_growbuf_t *th_growbuf_new(const size_t mingrow) +{ + th_growbuf_t *buf; + + if ((buf = th_malloc(sizeof(th_growbuf_t))) == NULL) + return NULL; + + th_growbuf_init(buf, mingrow); + buf->allocated = TRUE; + + return buf; +} + + +void th_growbuf_free(th_growbuf_t *buf) +{ + th_free(buf->data); + + if (buf->allocated) + th_free(buf); +} + + +BOOL th_growbuf_grow(th_growbuf_t *buf, const size_t grow) +{ + if (buf == NULL) + return FALSE; + + if (buf->data == NULL || buf->len + grow >= buf->size) + { + buf->size += grow + (buf->mingrow > 0 ? buf->mingrow : TH_BUFGROW); + buf->data = (uint8_t *) th_realloc(buf->data, buf->size); + if (buf->data == NULL) + return FALSE; + } + return TRUE; +} + + +BOOL th_growbuf_puts(th_growbuf_t *buf, const char *str, BOOL eos) +{ + size_t slen; + if (str == NULL) + return FALSE; + + slen = strlen(str); + if (!th_growbuf_grow(buf, slen + 1)) + return FALSE; + + memcpy(buf->data + buf->len, str, slen + 1); + buf->len += eos ? (slen + 1) : slen; + + return TRUE; +} + + +BOOL th_growbuf_putch(th_growbuf_t *buf, const char ch) +{ + if (!th_growbuf_grow(buf, sizeof(char))) + return FALSE; + + buf->data[buf->len++] = (uint8_t) ch; + + return TRUE; +} + + +BOOL th_growbuf_put_str(th_growbuf_t *buf, const void *s, const size_t len) +{ + if (s == NULL) + return FALSE; + + if (!th_growbuf_grow(buf, len + 1)) + return FALSE; + + memcpy(buf->data + buf->len, s, len + 1); + buf->len += len; + + return TRUE; +} + + +BOOL th_growbuf_put_u8(th_growbuf_t *buf, const uint8_t val) +{ + if (!th_growbuf_grow(buf, sizeof(uint8_t))) + return FALSE; + + buf->data[buf->len++] = val; + + return TRUE; +} + + +BOOL th_growbuf_put_u16_be(th_growbuf_t *buf, const uint16_t val) +{ + if (!th_growbuf_grow(buf, sizeof(uint16_t))) + return FALSE; + + buf->data[buf->len++] = (val >> 8) & 0xff; + buf->data[buf->len++] = val & 0xff; + + return TRUE; +} + + +BOOL th_growbuf_put_u16_le(th_growbuf_t *buf, const uint16_t val) +{ + if (!th_growbuf_grow(buf, sizeof(uint16_t))) + return FALSE; + + buf->data[buf->len++] = val & 0xff; + buf->data[buf->len++] = (val >> 8) & 0xff; + + return TRUE; +} + + +BOOL th_growbuf_put_u32_be(th_growbuf_t *buf, const uint32_t val) +{ + if (!th_growbuf_grow(buf, sizeof(uint32_t))) + return FALSE; + + buf->data[buf->len++] = (val >> 24) & 0xff; + buf->data[buf->len++] = (val >> 16) & 0xff; + buf->data[buf->len++] = (val >> 8) & 0xff; + buf->data[buf->len++] = val & 0xff; + + return TRUE; +} + + +BOOL th_growbuf_put_u32_le(th_growbuf_t *buf, const uint32_t val) +{ + if (!th_growbuf_grow(buf, sizeof(uint32_t))) + return FALSE; + + buf->data[buf->len++] = val & 0xff; + buf->data[buf->len++] = (val >> 8) & 0xff; + buf->data[buf->len++] = (val >> 16) & 0xff; + buf->data[buf->len++] = (val >> 24) & 0xff; + + return TRUE; +}