Tue, 17 Oct 2017 16:15:41 +0200
changes source directory structure in preperation for autotools rollout
--- a/Makefile Tue Oct 17 15:15:54 2017 +0200 +++ b/Makefile Tue Oct 17 16:15:41 2017 +0200 @@ -45,10 +45,10 @@ all: ucx test ucx: FORCE - cd ucx; $(MAKE) CONF=$(CONF) + cd src; $(MAKE) CONF=$(CONF) ucx-debug: FORCE - cd ucx; $(MAKE) CONF=$(CONF) debug + cd src; $(MAKE) CONF=$(CONF) debug test: ucx FORCE cd test; $(MAKE) CONF=$(CONF) @@ -67,7 +67,7 @@ install: ucx $(DESTDIR)$(PREFIX)/lib $(DESTDIR)$(PREFIX)/include/ucx cp ./build/release/libucx$(LIB_EXT) $(DESTDIR)$(PREFIX)/lib && \ cp ./build/release/libucx$(SO_EXT) $(DESTDIR)$(PREFIX)/lib && \ - cp ./ucx/*.h $(DESTDIR)$(PREFIX)/include/ucx + cp ./src/ucx/*.h $(DESTDIR)$(PREFIX)/include/ucx uninstall: $(RM) $(RMFLAGS) $(DESTDIR)$(PREFIX)/include/ucx &&\
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Makefile Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,79 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2017 Olaf Wintermann. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +include ../$(CONF).mk +include ../cppcheck.mk + +# list of source files +SRC = utils.c +SRC += list.c +SRC += map.c +SRC += avl.c +SRC += properties.c +SRC += mempool.c +SRC += string.c +SRC += test.c +SRC += allocator.c +SRC += logging.c +SRC += buffer.c +SRC += stack.c + +OBJ = $(SRC:%.c=../build/release/ucx/%$(OBJ_EXT)) +OBJ_D = $(SRC:%.c=../build/debug/ucx/%$(OBJ_EXT)) + +all: ../build/release/ucx \ + ../build/release/libucx$(LIB_EXT) ../build/release/libucx$(SO_EXT) +debug: ../build/debug/ucx \ + ../build/debug/libucx$(LIB_EXT) ../build/debug/libucx$(SO_EXT) + +../build/release/libucx$(LIB_EXT): $(OBJ) + $(AR) $(ARFLAGS) ../build/release/libucx$(LIB_EXT) $(OBJ) + +../build/release/libucx$(SO_EXT): $(OBJ) + $(LD) $(SOLDFLAGS) -o ../build/release/libucx$(SO_EXT) $(OBJ) + +../build/release/ucx/%$(OBJ_EXT): %.c + $(CC) $(CFLAGS) -I. -o $@ -c $< + +../build/release/ucx: + $(MKDIR) $(MKDIRFLAGS) ../build/release/ucx + +../build/debug/libucx$(LIB_EXT): $(OBJ_D) + $(AR) $(ARFLAGS) ../build/debug/libucx$(LIB_EXT) $(OBJ_D) + +../build/debug/libucx$(SO_EXT): $(OBJ_D) + $(LD) $(SOLDFLAGS) -o ../build/debug/libucx$(SO_EXT) $(OBJ_D) + +../build/debug/ucx/%$(OBJ_EXT): %.c + $(CC) $(CFLAGS_D) -I. -o $@ -c $< + +../build/debug/ucx: + $(MKDIR) $(MKDIRFLAGS) ../build/debug/ucx + +cppcheck: $(SRC) + $(CPPCHECK) $(CPPCHECK_CONFIG) $(CPPCHECK_FLAGS) $+ 2>> ../$(CPPCHECK_LOG)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/allocator.c Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,60 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ucx/allocator.h" + +#include <stdlib.h> + +UcxAllocator default_allocator = { + NULL, + ucx_default_malloc, + ucx_default_calloc, + ucx_default_realloc, + ucx_default_free +}; + +UcxAllocator *ucx_default_allocator() { + UcxAllocator *allocator = &default_allocator; + return allocator; +} + +void *ucx_default_malloc(void *ignore, size_t n) { + return malloc(n); +} + +void *ucx_default_calloc(void *ignore, size_t n, size_t size) { + return calloc(n, size); +} + +void *ucx_default_realloc(void *ignore, void *data, size_t n) { + return realloc(data, n); +} + +void ucx_default_free(void *ignore, void *data) { + free(data); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/avl.c Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,356 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ucx/avl.h" + +#include <limits.h> + +#define ptrcast(ptr) ((void*)(ptr)) +#define alloc_tree(al) (UcxAVLTree*) almalloc((al), sizeof(UcxAVLTree)) +#define alloc_node(al) (UcxAVLNode*) almalloc((al), sizeof(UcxAVLNode)) + +static void ucx_avl_connect(UcxAVLTree *tree, + UcxAVLNode *node, UcxAVLNode *child, intptr_t nullkey) { + if (child) { + child->parent = node; + } + // if child is NULL, nullkey decides if left or right pointer is cleared + if (tree->cmpfunc( + ptrcast(child ? child->key : nullkey), + ptrcast(node->key), tree->userdata) > 0) { + node->right = child; + } else { + node->left = child; + } + size_t lh = node->left ? node->left->height : 0; + size_t rh = node->right ? node->right->height : 0; + node->height = 1 + (lh > rh ? lh : rh); +} + +#define avlheight(node) ((node) ? (node)->height : 0) + +static UcxAVLNode* avl_rotright(UcxAVLTree *tree, UcxAVLNode *l0) { + UcxAVLNode *p = l0->parent; + UcxAVLNode *l1 = l0->left; + if (p) { + ucx_avl_connect(tree, p, l1, 0); + } else { + l1->parent = NULL; + } + ucx_avl_connect(tree, l0, l1->right, l1->key); + ucx_avl_connect(tree, l1, l0, 0); + return l1; +} + +static UcxAVLNode* avl_rotleft(UcxAVLTree *tree, UcxAVLNode *l0) { + UcxAVLNode *p = l0->parent; + UcxAVLNode *l1 = l0->right; + if (p) { + ucx_avl_connect(tree, p, l1, 0); + } else { + l1->parent = NULL; + } + ucx_avl_connect(tree, l0, l1->left, l1->key); + ucx_avl_connect(tree, l1, l0, 0); + return l1; +} + +static void ucx_avl_balance(UcxAVLTree *tree, UcxAVLNode *n) { + int lh = avlheight(n->left); + int rh = avlheight(n->right); + n->height = 1 + (lh > rh ? lh : rh); + + if (lh - rh == 2) { + UcxAVLNode *c = n->left; + if (avlheight(c->right) - avlheight(c->left) == 1) { + avl_rotleft(tree, c); + } + n = avl_rotright(tree, n); + } else if (rh - lh == 2) { + UcxAVLNode *c = n->right; + if (avlheight(c->left) - avlheight(c->right) == 1) { + avl_rotright(tree, c); + } + n = avl_rotleft(tree, n); + } + + if (n->parent) { + ucx_avl_balance(tree, n->parent); + } else { + tree->root = n; + } +} + +UcxAVLTree *ucx_avl_new(cmp_func cmpfunc) { + return ucx_avl_new_a(cmpfunc, ucx_default_allocator()); +} + +UcxAVLTree *ucx_avl_new_a(cmp_func cmpfunc, UcxAllocator *allocator) { + UcxAVLTree* tree = alloc_tree(allocator); + if (tree) { + tree->allocator = allocator; + tree->cmpfunc = cmpfunc; + tree->root = NULL; + tree->userdata = NULL; + } + + return tree; +} + +static void ucx_avl_free_node(UcxAllocator *al, UcxAVLNode *node) { + if (node) { + ucx_avl_free_node(al, node->left); + ucx_avl_free_node(al, node->right); + alfree(al, node); + } +} + +void ucx_avl_free(UcxAVLTree *tree) { + UcxAllocator *al = tree->allocator; + ucx_avl_free_node(al, tree->root); + alfree(al, tree); +} + +UcxAVLNode *ucx_avl_get_node(UcxAVLTree *tree, intptr_t key) { + UcxAVLNode *n = tree->root; + int cmpresult; + while (n && (cmpresult = tree->cmpfunc( + ptrcast(key), ptrcast(n->key), tree->userdata))) { + n = cmpresult > 0 ? n->right : n->left; + } + return n; +} + +void *ucx_avl_get(UcxAVLTree *tree, intptr_t key) { + UcxAVLNode *n = ucx_avl_get_node(tree, key); + return n ? n->value : NULL; +} + +UcxAVLNode *ucx_avl_find_node(UcxAVLTree *tree, intptr_t key, + distance_func dfnc, int mode) { + UcxAVLNode *n = tree->root; + UcxAVLNode *closest = NULL; + + intmax_t cmpresult; + intmax_t closest_dist; + closest_dist = mode == UCX_AVL_FIND_LOWER_BOUNDED ? INTMAX_MIN : INTMAX_MAX; + + while (n && (cmpresult = dfnc( + ptrcast(key), ptrcast(n->key), tree->userdata))) { + if (mode == UCX_AVL_FIND_CLOSEST) { + intmax_t dist = cmpresult; + if (dist < 0) dist *= -1; + if (dist < closest_dist) { + closest_dist = dist; + closest = n; + } + } else if (mode == UCX_AVL_FIND_LOWER_BOUNDED && cmpresult <= 0) { + if (cmpresult > closest_dist) { + closest_dist = cmpresult; + closest = n; + } + } else if (mode == UCX_AVL_FIND_UPPER_BOUNDED && cmpresult >= 0) { + if (cmpresult < closest_dist) { + closest_dist = cmpresult; + closest = n; + } + } + n = cmpresult > 0 ? n->right : n->left; + } + return n ? n : closest; +} + +void *ucx_avl_find(UcxAVLTree *tree, intptr_t key, + distance_func dfnc, int mode) { + UcxAVLNode *n = ucx_avl_find_node(tree, key, dfnc, mode); + return n ? n->value : NULL; +} + +int ucx_avl_put(UcxAVLTree *tree, intptr_t key, void *value) { + return ucx_avl_put_s(tree, key, value, NULL); +} + +int ucx_avl_put_s(UcxAVLTree *tree, intptr_t key, void *value, + void **oldvalue) { + if (tree->root) { + UcxAVLNode *n = tree->root; + int cmpresult; + while ((cmpresult = tree->cmpfunc( + ptrcast(key), ptrcast(n->key), tree->userdata))) { + UcxAVLNode *m = cmpresult > 0 ? n->right : n->left; + if (m) { + n = m; + } else { + break; + } + } + + if (cmpresult) { + UcxAVLNode* e = alloc_node(tree->allocator); + if (e) { + e->key = key; e->value = value; e->height = 1; + e->parent = e->left = e->right = NULL; + ucx_avl_connect(tree, n, e, 0); + ucx_avl_balance(tree, n); + return 0; + } else { + return 1; + } + } else { + if (oldvalue) { + *oldvalue = n->value; + } + n->value = value; + return 0; + } + } else { + tree->root = alloc_node(tree->allocator); + if (tree->root) { + tree->root->key = key; tree->root->value = value; + tree->root->height = 1; + tree->root->parent = tree->root->left = tree->root->right = NULL; + + if (oldvalue) { + *oldvalue = NULL; + } + + return 0; + } else { + return 1; + } + } +} + +int ucx_avl_remove(UcxAVLTree *tree, intptr_t key) { + return ucx_avl_remove_s(tree, key, NULL, NULL); +} + +int ucx_avl_remove_node(UcxAVLTree *tree, UcxAVLNode *node) { + return ucx_avl_remove_s(tree, node->key, NULL, NULL); +} + +int ucx_avl_remove_s(UcxAVLTree *tree, intptr_t key, + intptr_t *oldkey, void **oldvalue) { + + UcxAVLNode *n = tree->root; + int cmpresult; + while (n && (cmpresult = tree->cmpfunc( + ptrcast(key), ptrcast(n->key), tree->userdata))) { + n = cmpresult > 0 ? n->right : n->left; + } + if (n) { + if (oldkey) { + *oldkey = n->key; + } + if (oldvalue) { + *oldvalue = n->value; + } + + UcxAVLNode *p = n->parent; + if (n->left && n->right) { + UcxAVLNode *s = n->right; + while (s->left) { + s = s->left; + } + ucx_avl_connect(tree, s->parent, s->right, s->key); + n->key = s->key; n->value = s->value; + p = s->parent; + alfree(tree->allocator, s); + } else { + if (p) { + ucx_avl_connect(tree, p, n->right ? n->right:n->left, n->key); + } else { + tree->root = n->right ? n->right : n->left; + if (tree->root) { + tree->root->parent = NULL; + } + } + alfree(tree->allocator, n); + } + + if (p) { + ucx_avl_balance(tree, p); + } + + return 0; + } else { + return 1; + } +} + +static size_t ucx_avl_countn(UcxAVLNode *node) { + if (node) { + return 1 + ucx_avl_countn(node->left) + ucx_avl_countn(node->right); + } else { + return 0; + } +} + +size_t ucx_avl_count(UcxAVLTree *tree) { + return ucx_avl_countn(tree->root); +} + +UcxAVLNode* ucx_avl_pred(UcxAVLNode* node) { + if (node->left) { + UcxAVLNode* n = node->left; + while (n->right) { + n = n->right; + } + return n; + } else { + UcxAVLNode* n = node; + while (n->parent) { + if (n->parent->right == n) { + return n->parent; + } else { + n = n->parent; + } + } + return NULL; + } +} + +UcxAVLNode* ucx_avl_succ(UcxAVLNode* node) { + if (node->right) { + UcxAVLNode* n = node->right; + while (n->left) { + n = n->left; + } + return n; + } else { + UcxAVLNode* n = node; + while (n->parent) { + if (n->parent->left == n) { + return n->parent; + } else { + n = n->parent; + } + } + return NULL; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/buffer.c Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,236 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ucx/buffer.h" + +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +UcxBuffer *ucx_buffer_new(void *space, size_t capacity, int flags) { + UcxBuffer *buffer = (UcxBuffer*) malloc(sizeof(UcxBuffer)); + if (buffer) { + buffer->flags = flags; + if (!space) { + buffer->space = (char*)malloc(capacity); + if (!buffer->space) { + free(buffer); + return NULL; + } + memset(buffer->space, 0, capacity); + buffer->flags |= UCX_BUFFER_AUTOFREE; + } else { + buffer->space = (char*)space; + } + buffer->capacity = capacity; + buffer->size = 0; + + buffer->pos = 0; + } + + return buffer; +} + +void ucx_buffer_free(UcxBuffer *buffer) { + if ((buffer->flags & UCX_BUFFER_AUTOFREE) == UCX_BUFFER_AUTOFREE) { + free(buffer->space); + } + free(buffer); +} + +UcxBuffer* ucx_buffer_extract( + UcxBuffer *src, size_t start, size_t length, int flags) { + if (src->size == 0 || length == 0 || + ((size_t)-1) - start < length || start+length > src->capacity) + { + return NULL; + } + + UcxBuffer *dst = (UcxBuffer*) malloc(sizeof(UcxBuffer)); + if (dst) { + dst->space = (char*)malloc(length); + if (!dst->space) { + free(dst); + return NULL; + } + dst->capacity = length; + dst->size = length; + dst->flags = flags | UCX_BUFFER_AUTOFREE; + dst->pos = 0; + memcpy(dst->space, src->space+start, length); + } + return dst; +} + +int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence) { + size_t npos; + switch (whence) { + case SEEK_CUR: + npos = buffer->pos; + break; + case SEEK_END: + npos = buffer->size; + break; + case SEEK_SET: + npos = 0; + break; + default: + return -1; + } + + size_t opos = npos; + npos += offset; + + if ((offset > 0 && npos < opos) || (offset < 0 && npos > opos)) { + return -1; + } + + if (npos >= buffer->size) { + return -1; + } else { + buffer->pos = npos; + return 0; + } + +} + +int ucx_buffer_eof(UcxBuffer *buffer) { + return buffer->pos >= buffer->size; +} + +int ucx_buffer_extend(UcxBuffer *buffer, size_t len) { + size_t newcap = buffer->capacity; + + if (buffer->capacity + len < buffer->capacity) { + return -1; + } + + while (buffer->capacity + len > newcap) { + newcap <<= 1; + if (newcap < buffer->capacity) { + return -1; + } + } + + char *newspace = (char*)realloc(buffer->space, newcap); + if (newspace) { + memset(newspace+buffer->size, 0, newcap-buffer->size); + buffer->space = newspace; + buffer->capacity = newcap; + } else { + return -1; + } + + return 0; +} + +size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, + UcxBuffer *buffer) { + size_t len = size * nitems; + size_t required = buffer->pos + len; + if (buffer->pos > required) { + return 0; + } + + if (required > buffer->capacity) { + if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) { + if (ucx_buffer_extend(buffer, required - buffer->capacity)) { + return 0; + } + } else { + len = buffer->capacity - buffer->pos; + if (size > 1) { + len -= len%size; + } + } + } + + if (len == 0) { + return len; + } + + memcpy(buffer->space + buffer->pos, ptr, len); + buffer->pos += len; + if(buffer->pos > buffer->size) { + buffer->size = buffer->pos; + } + + return len / size; +} + +size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, + UcxBuffer *buffer) { + size_t len = size * nitems; + if (buffer->pos + len > buffer->size) { + len = buffer->size - buffer->pos; + if (size > 1) len -= len%size; + } + + if (len <= 0) { + return len; + } + + memcpy(ptr, buffer->space + buffer->pos, len); + buffer->pos += len; + + return len / size; +} + +int ucx_buffer_putc(UcxBuffer *buffer, int c) { + if(buffer->pos >= buffer->capacity) { + if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) { + if(ucx_buffer_extend(buffer, 1)) { + return EOF; + } + } else { + return EOF; + } + } + + c &= 0xFF; + buffer->space[buffer->pos] = (char) c; + buffer->pos++; + if(buffer->pos > buffer->size) { + buffer->size = buffer->pos; + } + return c; +} + +int ucx_buffer_getc(UcxBuffer *buffer) { + if (ucx_buffer_eof(buffer)) { + return EOF; + } else { + int c = buffer->space[buffer->pos]; + buffer->pos++; + return c; + } +} + +size_t ucx_buffer_puts(UcxBuffer *buffer, char *str) { + return ucx_buffer_write((const void*)str, 1, strlen(str), buffer); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/list.c Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,370 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ucx/list.h" + +UcxList *ucx_list_clone(UcxList *l, copy_func fnc, void *data) { + return ucx_list_clone_a(ucx_default_allocator(), l, fnc, data); +} + +UcxList *ucx_list_clone_a(UcxAllocator *alloc, UcxList *l, + copy_func fnc, void *data) { + UcxList *ret = NULL; + while (l) { + if (fnc) { + ret = ucx_list_append_a(alloc, ret, fnc(l->data, data)); + } else { + ret = ucx_list_append_a(alloc, ret, l->data); + } + l = l->next; + } + return ret; +} + +int ucx_list_equals(const UcxList *l1, const UcxList *l2, + cmp_func fnc, void* data) { + if (l1 == l2) return 1; + + while (l1 != NULL && l2 != NULL) { + if (fnc == NULL) { + if (l1->data != l2->data) return 0; + } else { + if (fnc(l1->data, l2->data, data) != 0) return 0; + } + l1 = l1->next; + l2 = l2->next; + } + + return (l1 == NULL && l2 == NULL); +} + +void ucx_list_free(UcxList *l) { + ucx_list_free_a(ucx_default_allocator(), l); +} + +void ucx_list_free_a(UcxAllocator *alloc, UcxList *l) { + UcxList *e = l, *f; + while (e != NULL) { + f = e; + e = e->next; + alfree(alloc, f); + } +} + +void ucx_list_free_content(UcxList* list, ucx_destructor destr) { + while (list != NULL) { + destr(list->data); + list = list->next; + } +} + +UcxList *ucx_list_append(UcxList *l, void *data) { + return ucx_list_append_a(ucx_default_allocator(), l, data); +} + +UcxList *ucx_list_append_a(UcxAllocator *alloc, UcxList *l, void *data) { + UcxList *nl = (UcxList*) almalloc(alloc, sizeof(UcxList)); + if (!nl) { + return NULL; + } + + nl->data = data; + nl->next = NULL; + if (l) { + UcxList *t = ucx_list_last(l); + t->next = nl; + nl->prev = t; + return l; + } else { + nl->prev = NULL; + return nl; + } +} + +UcxList *ucx_list_append_once(UcxList *l, void *data, + cmp_func cmpfnc, void *cmpdata) { + return ucx_list_append_once_a(ucx_default_allocator(), l, + data, cmpfnc, cmpdata); +} + +UcxList *ucx_list_append_once_a(UcxAllocator *alloc, UcxList *l, void *data, + cmp_func cmpfnc, void *cmpdata) { + + UcxList *last = NULL; + { + UcxList *e = l; + while (e) { + if (cmpfnc(e->data, data, cmpdata) == 0) { + return l; + } + last = e; + e = e->next; + } + } + + UcxList *nl = ucx_list_append_a(alloc, NULL, data); + if (!nl) { + return NULL; + } + + if (last == NULL) { + return nl; + } else { + nl->prev = last; + last->next = nl; + return l; + } +} + +UcxList *ucx_list_prepend(UcxList *l, void *data) { + return ucx_list_prepend_a(ucx_default_allocator(), l, data); +} + +UcxList *ucx_list_prepend_a(UcxAllocator *alloc, UcxList *l, void *data) { + UcxList *nl = ucx_list_append_a(alloc, NULL, data); + if (!nl) { + return NULL; + } + l = ucx_list_first(l); + + if (l) { + nl->next = l; + l->prev = nl; + } + return nl; +} + +UcxList *ucx_list_concat(UcxList *l1, UcxList *l2) { + if (l1) { + UcxList *last = ucx_list_last(l1); + last->next = l2; + if (l2) { + l2->prev = last; + } + return l1; + } else { + return l2; + } +} + +UcxList *ucx_list_last(const UcxList *l) { + if (l == NULL) return NULL; + + const UcxList *e = l; + while (e->next != NULL) { + e = e->next; + } + return (UcxList*)e; +} + +ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem) { + ssize_t index = 0; + while (list) { + if (list == elem) { + return index; + } + list = list->next; + index++; + } + return -1; +} + +UcxList *ucx_list_get(const UcxList *l, size_t index) { + if (l == NULL) return NULL; + + const UcxList *e = l; + while (e->next && index > 0) { + e = e->next; + index--; + } + + return (UcxList*)(index == 0 ? e : NULL); +} + +ssize_t ucx_list_find(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) { + ssize_t index = 0; + UCX_FOREACH(e, l) { + if (fnc) { + if (fnc(elem, e->data, cmpdata) == 0) { + return index; + } + } else { + if (elem == e->data) { + return index; + } + } + index++; + } + return -1; +} + +int ucx_list_contains(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) { + return ucx_list_find(l, elem, fnc, cmpdata) > -1; +} + +size_t ucx_list_size(const UcxList *l) { + if (l == NULL) return 0; + + const UcxList *e = l; + size_t s = 1; + while (e->next != NULL) { + e = e->next; + s++; + } + + return s; +} + +static UcxList *ucx_list_sort_merge(int length, + UcxList* restrict ls, UcxList* restrict le, UcxList* restrict re, + cmp_func fnc, void* data) { + + UcxList** sorted = (UcxList**) malloc(sizeof(UcxList*)*length); + UcxList *rc, *lc; + + lc = ls; rc = le; + int n = 0; + while (lc && lc != le && rc != re) { + if (fnc(lc->data, rc->data, data) <= 0) { + sorted[n] = lc; + lc = lc->next; + } else { + sorted[n] = rc; + rc = rc->next; + } + n++; + } + while (lc && lc != le) { + sorted[n] = lc; + lc = lc->next; + n++; + } + while (rc && rc != re) { + sorted[n] = rc; + rc = rc->next; + n++; + } + + // Update pointer + sorted[0]->prev = NULL; + for (int i = 0 ; i < length-1 ; i++) { + sorted[i]->next = sorted[i+1]; + sorted[i+1]->prev = sorted[i]; + } + sorted[length-1]->next = NULL; + + UcxList *ret = sorted[0]; + free(sorted); + return ret; +} + +UcxList *ucx_list_sort(UcxList *l, cmp_func fnc, void *data) { + if (l == NULL) { + return NULL; + } + + UcxList *lc; + int ln = 1; + + UcxList *restrict ls = l, *restrict le, *restrict re; + + // check how many elements are already sorted + lc = ls; + while (lc->next != NULL && fnc(lc->next->data, lc->data, data) > 0) { + lc = lc->next; + ln++; + } + le = lc->next; + + if (le == NULL) { + return l; // this list is already sorted :) + } else { + UcxList *rc; + int rn = 1; + rc = le; + // skip already sorted elements + while (rc->next != NULL && fnc(rc->next->data, rc->data, data) > 0) { + rc = rc->next; + rn++; + } + re = rc->next; + + // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them + UcxList *sorted = ucx_list_sort_merge(ln+rn, + ls, le, re, + fnc, data); + + // Something left? Sort it! + size_t remainder_length = ucx_list_size(re); + if (remainder_length > 0) { + UcxList *remainder = ucx_list_sort(re, fnc, data); + + // merge sorted list with (also sorted) remainder + l = ucx_list_sort_merge(ln+rn+remainder_length, + sorted, remainder, NULL, fnc, data); + } else { + // no remainder - we've got our sorted list + l = sorted; + } + + return l; + } +} + +UcxList *ucx_list_first(const UcxList *l) { + if (!l) { + return NULL; + } + + const UcxList *e = l; + while (e->prev) { + e = e->prev; + } + return (UcxList *)e; +} + +UcxList *ucx_list_remove(UcxList *l, UcxList *e) { + return ucx_list_remove_a(ucx_default_allocator(), l, e); +} + +UcxList *ucx_list_remove_a(UcxAllocator *alloc, UcxList *l, UcxList *e) { + if (l == e) { + l = e->next; + } + + if (e->next) { + e->next->prev = e->prev; + } + + if (e->prev) { + e->prev->next = e->next; + } + + alfree(alloc, e); + return l; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/logging.c Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,106 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ucx/logging.h" + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <time.h> + +UcxLogger *ucx_logger_new(void *stream, unsigned int level, unsigned int mask) { + UcxLogger *logger = (UcxLogger*) malloc(sizeof(UcxLogger)); + if (logger != NULL) { + logger->stream = stream; + logger->writer = (write_func)fwrite; + logger->dateformat = (char*) "%F %T %z "; + logger->level = level; + logger->mask = mask; + logger->levels = ucx_map_new(8); + + unsigned int l; + l = UCX_LOGGER_ERROR; + ucx_map_int_put(logger->levels, l, (void*) "[ERROR]"); + l = UCX_LOGGER_WARN; + ucx_map_int_put(logger->levels, l, (void*) "[WARNING]"); + l = UCX_LOGGER_INFO; + ucx_map_int_put(logger->levels, l, (void*) "[INFO]"); + l = UCX_LOGGER_TRACE; + ucx_map_int_put(logger->levels, l, (void*) "[TRACE]"); + } + + return logger; +} + +void ucx_logger_free(UcxLogger *logger) { + ucx_map_free(logger->levels); + free(logger); +} + +// estimated max. message length (documented) +#define UCX_LOGGER_MSGMAX 4096 + +void ucx_logger_logf(UcxLogger *logger, unsigned int level, const char* file, + const unsigned int line, const char *format, ...) { + if (level <= logger->level) { + char msg[UCX_LOGGER_MSGMAX]; + char *text; + size_t k = 0; + size_t n; + + if ((logger->mask & UCX_LOGGER_LEVEL) > 0) { + text = (char*) ucx_map_int_get(logger->levels, level); + n = strlen(text); + n = n > 256 ? 256 : n; + memcpy(msg+k, text, n); + k += n; + msg[k++] = ' '; + } + if ((logger->mask & UCX_LOGGER_TIMESTAMP) > 0) { + time_t now = time(NULL); + k += strftime(msg+k, 128, logger->dateformat, localtime(&now)); + } + if ((logger->mask & UCX_LOGGER_SOURCE) > 0) { + n = strlen(file); + memcpy(msg+k, file, n); + k += n; + k += sprintf(msg+k, ":%u ", line); + } + + msg[k++] = '-'; msg[k++] = ' '; + + va_list args; + va_start (args, format); + k += vsnprintf(msg+k, UCX_LOGGER_MSGMAX-k-1, format, args); + va_end (args); + + msg[k++] = '\n'; + + logger->writer(msg, 1, k, logger->stream); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/map.c Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,328 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ucx/map.h" + +#include <stdlib.h> +#include <string.h> + +UcxMap *ucx_map_new(size_t size) { + return ucx_map_new_a(NULL, size); +} + +UcxMap *ucx_map_new_a(UcxAllocator *allocator, size_t size) { + if(size == 0) { + size = 16; + } + + if(!allocator) { + allocator = ucx_default_allocator(); + } + + UcxMap *map = (UcxMap*)almalloc(allocator, sizeof(UcxMap)); + if (!map) { + return NULL; + } + + map->allocator = allocator; + map->map = (UcxMapElement**)alcalloc( + allocator, size, sizeof(UcxMapElement*)); + if(map->map == NULL) { + alfree(allocator, map); + return NULL; + } + map->size = size; + map->count = 0; + + return map; +} + +static void ucx_map_free_elmlist_contents(UcxMap *map) { + for (size_t n = 0 ; n < map->size ; n++) { + UcxMapElement *elem = map->map[n]; + if (elem != NULL) { + do { + UcxMapElement *next = elem->next; + alfree(map->allocator, elem->key.data); + alfree(map->allocator, elem); + elem = next; + } while (elem != NULL); + } + } +} + +void ucx_map_free(UcxMap *map) { + ucx_map_free_elmlist_contents(map); + alfree(map->allocator, map->map); + alfree(map->allocator, map); +} + +void ucx_map_free_content(UcxMap *map, ucx_destructor destr) { + UcxMapIterator iter = ucx_map_iterator(map); + void *val; + UCX_MAP_FOREACH(key, val, iter) { + destr(val); + } +} + +void ucx_map_clear(UcxMap *map) { + if (map->count == 0) { + return; // nothing to do + } + ucx_map_free_elmlist_contents(map); + memset(map->map, 0, map->size*sizeof(UcxMapElement*)); + map->count = 0; +} + +int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to, + copy_func fnc, void *data) { + UcxMapIterator i = ucx_map_iterator(from); + void *value; + UCX_MAP_FOREACH(key, value, i) { + if (ucx_map_put(to, key, fnc ? fnc(value, data) : value)) { + return 1; + } + } + return 0; +} + +UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data) { + size_t bs = (map->count * 5) >> 1; + UcxMap *newmap = ucx_map_new(bs > map->size ? bs : map->size); + if (!newmap) { + return NULL; + } + ucx_map_copy(map, newmap, fnc, data); + return newmap; +} + +int ucx_map_rehash(UcxMap *map) { + size_t load = (map->size * 3) >> 2; + if (map->count > load) { + UcxMap oldmap; + oldmap.map = map->map; + oldmap.size = map->size; + oldmap.count = map->count; + oldmap.allocator = map->allocator; + + map->size = (map->count * 5) >> 1; + map->map = (UcxMapElement**)alcalloc( + map->allocator, map->size, sizeof(UcxMapElement*)); + if (!map->map) { + *map = oldmap; + return 1; + } + map->count = 0; + ucx_map_copy(&oldmap, map, NULL, NULL); + + /* free the UcxMapElement list of oldmap */ + ucx_map_free_elmlist_contents(&oldmap); + alfree(map->allocator, oldmap.map); + } + return 0; +} + +int ucx_map_put(UcxMap *map, UcxKey key, void *data) { + UcxAllocator *allocator = map->allocator; + + if (key.hash == 0) { + key.hash = ucx_hash((char*)key.data, key.len); + } + + size_t slot = key.hash%map->size; + UcxMapElement *restrict elm = map->map[slot]; + UcxMapElement *restrict prev = NULL; + + while (elm && elm->key.hash < key.hash) { + prev = elm; + elm = elm->next; + } + + if (!elm || elm->key.hash != key.hash) { + UcxMapElement *e = (UcxMapElement*)almalloc( + allocator, sizeof(UcxMapElement)); + if (!e) { + return -1; + } + e->key.data = NULL; + if (prev) { + prev->next = e; + } else { + map->map[slot] = e; + } + e->next = elm; + elm = e; + } + + if (!elm->key.data) { + void *kd = almalloc(allocator, key.len); + if (!kd) { + return -1; + } + memcpy(kd, key.data, key.len); + key.data = kd; + elm->key = key; + map->count++; + } + elm->data = data; + + return 0; +} + +void* ucx_map_get_and_remove(UcxMap *map, UcxKey key, _Bool remove) { + if(key.hash == 0) { + key.hash = ucx_hash((char*)key.data, key.len); + } + + size_t slot = key.hash%map->size; + UcxMapElement *restrict elm = map->map[slot]; + UcxMapElement *restrict pelm = NULL; + while (elm && elm->key.hash <= key.hash) { + if(elm->key.hash == key.hash) { + int n = (key.len > elm->key.len) ? elm->key.len : key.len; + if (memcmp(elm->key.data, key.data, n) == 0) { + void *data = elm->data; + if (remove) { + if (pelm) { + pelm->next = elm->next; + } else { + map->map[slot] = elm->next; + } + alfree(map->allocator, elm->key.data); + alfree(map->allocator, elm); + map->count--; + } + + return data; + } + } + pelm = elm; + elm = pelm->next; + } + + return NULL; +} + +void *ucx_map_get(UcxMap *map, UcxKey key) { + return ucx_map_get_and_remove(map, key, 0); +} + +void *ucx_map_remove(UcxMap *map, UcxKey key) { + return ucx_map_get_and_remove(map, key, 1); +} + +UcxKey ucx_key(void *data, size_t len) { + UcxKey key; + key.data = data; + key.len = len; + key.hash = ucx_hash((const char*) data, len); + return key; +} + + +int ucx_hash(const char *data, size_t len) { + /* murmur hash 2 */ + + int m = 0x5bd1e995; + int r = 24; + + int h = 25 ^ len; + + int i = 0; + while (len >= 4) { + int k = data[i + 0] & 0xFF; + k |= (data[i + 1] & 0xFF) << 8; + k |= (data[i + 2] & 0xFF) << 16; + k |= (data[i + 3] & 0xFF) << 24; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + i += 4; + len -= 4; + } + + switch (len) { + case 3: h ^= (data[i + 2] & 0xFF) << 16; + /* no break */ + case 2: h ^= (data[i + 1] & 0xFF) << 8; + /* no break */ + case 1: h ^= (data[i + 0] & 0xFF); h *= m; + /* no break */ + } + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} + +UcxMapIterator ucx_map_iterator(UcxMap *map) { + UcxMapIterator i; + i.map = map; + i.cur = NULL; + i.index = 0; + return i; +} + +int ucx_map_iter_next(UcxMapIterator *i, UcxKey *key, void **elm) { + UcxMapElement *e = i->cur; + + if (e) { + e = e->next; + } else { + e = i->map->map[0]; + } + + while (i->index < i->map->size) { + if (e) { + if (e->data) { + i->cur = e; + *elm = e->data; + *key = e->key; + return 1; + } + + e = e->next; + } else { + i->index++; + + if (i->index < i->map->size) { + e = i->map->map[i->index]; + } + } + } + + return 0; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mempool.c Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,211 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ucx/mempool.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#ifdef __cplusplus +#define __STDC_FORMAT_MACROS +#endif +#include <inttypes.h> + +/** Capsule for destructible memory chunks. */ +typedef struct { + /** The destructor for the memory chunk. */ + ucx_destructor destructor; + /** + * First byte of the memory chunk. + * Note, that the address <code>&c</code> is also the address + * of the whole memory chunk. + */ + char c; +} ucx_memchunk; + +/** Capsule for data and its destructor. */ +typedef struct { + /** The destructor for the data. */ + ucx_destructor destructor; + /** A pointer to the data. */ + void *ptr; +} ucx_regdestr; + +UCX_EXTERN void ucx_mempool_shared_destr(void* ptr) { + ucx_regdestr *rd = (ucx_regdestr*)ptr; + rd->destructor(rd->ptr); +} + +UcxMempool *ucx_mempool_new(size_t n) { + UcxMempool *pool = (UcxMempool*)malloc(sizeof(UcxMempool)); + if (!pool) { + return NULL; + } + + pool->data = (void**) malloc(n * sizeof(void*)); + if (pool->data == NULL) { + free(pool); + return NULL; + } + + pool->ndata = 0; + pool->size = n; + + UcxAllocator *allocator = (UcxAllocator*)malloc(sizeof(UcxAllocator)); + if(!allocator) { + free(pool->data); + free(pool); + return NULL; + } + allocator->malloc = (ucx_allocator_malloc)ucx_mempool_malloc; + allocator->calloc = (ucx_allocator_calloc)ucx_mempool_calloc; + allocator->realloc = (ucx_allocator_realloc)ucx_mempool_realloc; + allocator->free = (ucx_allocator_free)ucx_mempool_free; + allocator->pool = pool; + pool->allocator = allocator; + + return pool; +} + +int ucx_mempool_chcap(UcxMempool *pool, size_t newcap) { + if (newcap < pool->ndata) { + return 1; + } + + void **data = (void**) realloc(pool->data, newcap*sizeof(void*)); + if (data) { + pool->data = data; + pool->size = newcap; + return 0; + } else { + return 1; + } +} + +void *ucx_mempool_malloc(UcxMempool *pool, size_t n) { + if (pool->ndata >= pool->size) { + size_t newcap = pool->size*2; + if (newcap < pool->size || ucx_mempool_chcap(pool, newcap)) { + return NULL; + } + } + + void *p = malloc(sizeof(ucx_destructor) + n); + ucx_memchunk *mem = (ucx_memchunk*)p; + if (!mem) { + return NULL; + } + + mem->destructor = NULL; + pool->data[pool->ndata] = mem; + pool->ndata++; + + return &(mem->c); +} + +void *ucx_mempool_calloc(UcxMempool *pool, size_t nelem, size_t elsize) { + void *ptr = ucx_mempool_malloc(pool, nelem*elsize); + if (!ptr) { + return NULL; + } + memset(ptr, 0, nelem * elsize); + return ptr; +} + +void *ucx_mempool_realloc(UcxMempool *pool, void *ptr, size_t n) { + char *mem = ((char*)ptr) - sizeof(ucx_destructor); + char *newm = (char*) realloc(mem, n + sizeof(ucx_destructor)); + if (!newm) { + return NULL; + } + if (mem != newm) { + for(size_t i=0 ; i < pool->ndata ; i++) { + if(pool->data[i] == mem) { + pool->data[i] = newm; + return newm + sizeof(ucx_destructor); + } + } + fprintf(stderr, "FATAL: 0x%08" PRIxPTR" not in mpool 0x%08" PRIxPTR"\n", + (intptr_t)ptr, (intptr_t)pool); + abort(); + } else { + return newm + sizeof(ucx_destructor); + } +} + +void ucx_mempool_free(UcxMempool *pool, void *ptr) { + ucx_memchunk *chunk = (ucx_memchunk*)((char*)ptr-sizeof(ucx_destructor)); + for(size_t i=0 ; i<pool->ndata ; i++) { + if(chunk == pool->data[i]) { + if(chunk->destructor != NULL) { + chunk->destructor(&(chunk->c)); + } + free(chunk); + size_t last_index = pool->ndata - 1; + if(i != last_index) { + pool->data[i] = pool->data[last_index]; + pool->data[last_index] = NULL; + } + pool->ndata--; + return; + } + } + fprintf(stderr, "FATAL: 0x%08" PRIxPTR" not in mpool 0x%08" PRIxPTR"\n", + (intptr_t)ptr, (intptr_t)pool); + abort(); +} + +void ucx_mempool_destroy(UcxMempool *pool) { + ucx_memchunk *chunk; + for(size_t i=0 ; i<pool->ndata ; i++) { + chunk = (ucx_memchunk*) pool->data[i]; + if(chunk) { + if(chunk->destructor) { + chunk->destructor(&(chunk->c)); + } + free(chunk); + } + } + free(pool->data); + free(pool->allocator); + free(pool); +} + +void ucx_mempool_set_destr(void *ptr, ucx_destructor func) { + *(ucx_destructor*)((char*)ptr-sizeof(ucx_destructor)) = func; +} + +void ucx_mempool_reg_destr(UcxMempool *pool, void *ptr, ucx_destructor destr) { + ucx_regdestr *rd = (ucx_regdestr*)ucx_mempool_malloc( + pool, + sizeof(ucx_regdestr)); + rd->destructor = destr; + rd->ptr = ptr; + ucx_mempool_set_destr(rd, ucx_mempool_shared_destr); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/properties.c Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,264 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ucx/properties.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +UcxProperties *ucx_properties_new() { + UcxProperties *parser = (UcxProperties*)malloc( + sizeof(UcxProperties)); + if(!parser) { + return NULL; + } + + parser->buffer = NULL; + parser->buflen = 0; + parser->pos = 0; + parser->tmp = NULL; + parser->tmplen = 0; + parser->tmpcap = 0; + parser->error = 0; + parser->delimiter = '='; + parser->comment1 = '#'; + parser->comment2 = 0; + parser->comment3 = 0; + + return parser; +} + +void ucx_properties_free(UcxProperties *parser) { + if(parser->tmp) { + free(parser->tmp); + } + free(parser); +} + +void ucx_properties_fill(UcxProperties *parser, char *buf, size_t len) { + parser->buffer = buf; + parser->buflen = len; + parser->pos = 0; +} + +static void parser_tmp_append(UcxProperties *parser, char *buf, size_t len) { + if(parser->tmpcap - parser->tmplen < len) { + size_t newcap = parser->tmpcap + len + 64; + parser->tmp = (char*)realloc(parser->tmp, newcap); + parser->tmpcap = newcap; + } + memcpy(parser->tmp + parser->tmplen, buf, len); + parser->tmplen += len; +} + +int ucx_properties_next(UcxProperties *parser, sstr_t *name, sstr_t *value) { + if(parser->tmplen > 0) { + char *buf = parser->buffer + parser->pos; + size_t len = parser->buflen - parser->pos; + sstr_t str = sstrn(buf, len); + sstr_t nl = sstrchr(str, '\n'); + if(nl.ptr) { + size_t newlen = (size_t)(nl.ptr - buf) + 1; + parser_tmp_append(parser, buf, newlen); + // the tmp buffer contains exactly one line now + + char *orig_buf = parser->buffer; + size_t orig_len = parser->buflen; + + parser->buffer = parser->tmp; + parser->buflen = parser->tmplen; + parser->pos = 0; + parser->tmp = NULL; + parser->tmpcap = 0; + parser->tmplen = 0; + // run ucx_properties_next with the tmp buffer as main buffer + int ret = ucx_properties_next(parser, name, value); + + // restore original buffer + parser->tmp = parser->buffer; + parser->buffer = orig_buf; + parser->buflen = orig_len; + parser->pos = newlen; + + /* + * if ret == 0 the tmp buffer contained just space or a comment + * we parse again with the original buffer to get a name/value + * or a new tmp buffer + */ + return ret ? ret : ucx_properties_next(parser, name, value); + } else { + parser_tmp_append(parser, buf, len); + return 0; + } + } else if(parser->tmp) { + free(parser->tmp); + parser->tmp = NULL; + } + + char comment1 = parser->comment1; + char comment2 = parser->comment2; + char comment3 = parser->comment3; + char delimiter = parser->delimiter; + + // get one line and parse it + while(parser->pos < parser->buflen) { + char *buf = parser->buffer + parser->pos; + size_t len = parser->buflen - parser->pos; + + /* + * First we check if we have at least one line. We also get indices of + * delimiter and comment chars + */ + size_t delimiter_index = 0; + size_t comment_index = 0; + int has_comment = 0; + + size_t i = 0; + char c = 0; + for(;i<len;i++) { + c = buf[i]; + if(c == comment1 || c == comment2 || c == comment3) { + if(comment_index == 0) { + comment_index = i; + has_comment = 1; + } + } else if(c == delimiter) { + if(delimiter_index == 0 && !has_comment) { + delimiter_index = i; + } + } else if(c == '\n') { + break; + } + } + + if(c != '\n') { + // we don't have enough data for a line + // store remaining bytes in temporary buffer for next round + parser->tmpcap = len + 128; + parser->tmp = (char*)malloc(parser->tmpcap); + parser->tmplen = len; + memcpy(parser->tmp, buf, len); + return 0; + } + + sstr_t line = has_comment ? sstrn(buf, comment_index) : sstrn(buf, i); + // check line + if(delimiter_index == 0) { + line = sstrtrim(line); + if(line.length != 0) { + parser->error = 1; + } + } else { + sstr_t n = sstrn(buf, delimiter_index); + sstr_t v = sstrn( + buf + delimiter_index + 1, + line.length - delimiter_index - 1); + n = sstrtrim(n); + v = sstrtrim(v); + if(n.length != 0 || v.length != 0) { + *name = n; + *value = v; + parser->pos += i + 1; + return 1; + } else { + parser->error = 1; + } + } + + parser->pos += i + 1; + } + + return 0; +} + +int ucx_properties2map(UcxProperties *parser, UcxMap *map) { + sstr_t name; + sstr_t value; + while(ucx_properties_next(parser, &name, &value)) { + value = sstrdup_a(map->allocator, value); + if(!value.ptr) { + return 1; + } + if(ucx_map_sstr_put(map, name, value.ptr)) { + alfree(map->allocator, value.ptr); + return 1; + } + } + if (parser->error) { + return parser->error; + } else { + return 0; + } +} + +// buffer size is documented - change doc, when you change bufsize! +#define UCX_PROPLOAD_BUFSIZE 1024 +int ucx_properties_load(UcxMap *map, FILE *file) { + UcxProperties *parser = ucx_properties_new(); + if(!(parser && map && file)) { + return 1; + } + + int error = 0; + size_t r; + char buf[UCX_PROPLOAD_BUFSIZE]; + while((r = fread(buf, 1, UCX_PROPLOAD_BUFSIZE, file)) != 0) { + ucx_properties_fill(parser, buf, r); + error = ucx_properties2map(parser, map); + if (error) { + break; + } + } + ucx_properties_free(parser); + return error; +} + +int ucx_properties_store(UcxMap *map, FILE *file) { + UcxMapIterator iter = ucx_map_iterator(map); + void *v; + sstr_t value; + size_t written; + + UCX_MAP_FOREACH(k, v, iter) { + value = sstr((char*)v); + + written = 0; + written += fwrite(k.data, 1, k.len, file); + written += fwrite(" = ", 1, 3, file); + written += fwrite(value.ptr, 1, value.length, file); + written += fwrite("\n", 1, 1, file); + + if (written != k.len + value.length + 4) { + return 1; + } + } + + return 0; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/stack.c Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,144 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ucx/stack.h" + +#include <string.h> + +static size_t ucx_stack_align(size_t n) { + int align = n % sizeof(void*); + if (align) { + n += sizeof(void*) - align; + } + return n; +} + +void ucx_stack_init(UcxStack *stack, char* space, size_t size) { + stack->size = size - size % sizeof(void*); + stack->space = space; + stack->top = NULL; + + stack->allocator.pool = stack; + stack->allocator.malloc = (ucx_allocator_malloc) ucx_stack_malloc; + stack->allocator.calloc = (ucx_allocator_calloc) ucx_stack_calloc; + stack->allocator.realloc = (ucx_allocator_realloc) ucx_stack_realloc; + stack->allocator.free = (ucx_allocator_free) ucx_stack_free; +} + +void *ucx_stack_malloc(UcxStack *stack, size_t n) { + + if (ucx_stack_avail(stack) < ucx_stack_align(n)) { + return NULL; + } else { + char *prev = stack->top; + if (stack->top) { + stack->top += ucx_stack_align(ucx_stack_topsize(stack)); + } else { + stack->top = stack->space; + } + + ((struct ucx_stack_metadata*)stack->top)->prev = prev; + ((struct ucx_stack_metadata*)stack->top)->size = n; + stack->top += sizeof(struct ucx_stack_metadata); + + return stack->top; + } +} + +void *ucx_stack_calloc(UcxStack *stack, size_t nelem, size_t elsize) { + void *mem = ucx_stack_malloc(stack, nelem*elsize); + memset(mem, 0, nelem*elsize); + return mem; +} + +void *ucx_stack_realloc(UcxStack *stack, void *ptr, size_t n) { + if (ptr == stack->top) { + if (stack->size - (stack->top - stack->space) < ucx_stack_align(n)) { + return NULL; + } else { + ((struct ucx_stack_metadata*)stack->top - 1)->size = n; + return ptr; + } + } else { + if (ucx_stack_align(((struct ucx_stack_metadata*)ptr - 1)->size) < + ucx_stack_align(n)) { + void *nptr = ucx_stack_malloc(stack, n); + if (nptr) { + memcpy(nptr, ptr, n); + ucx_stack_free(stack, ptr); + + return nptr; + } else { + return NULL; + } + } else { + ((struct ucx_stack_metadata*)ptr - 1)->size = n; + return ptr; + } + } +} + +void ucx_stack_free(UcxStack *stack, void *ptr) { + if (ptr == stack->top) { + stack->top = ((struct ucx_stack_metadata*) stack->top - 1)->prev; + } else { + struct ucx_stack_metadata *next = (struct ucx_stack_metadata*)( + (char*)ptr + + ucx_stack_align(((struct ucx_stack_metadata*) ptr - 1)->size) + ); + next->prev = ((struct ucx_stack_metadata*) ptr - 1)->prev; + } +} + +void ucx_stack_popn(UcxStack *stack, void *dest, size_t n) { + if (ucx_stack_empty(stack)) { + return; + } + + size_t len = ucx_stack_topsize(stack); + if (len > n) { + len = n; + } + + memcpy(dest, stack->top, len); + + ucx_stack_free(stack, stack->top); +} + +size_t ucx_stack_avail(UcxStack *stack) { + size_t avail = ((stack->top ? (stack->size + - (stack->top - stack->space) + - ucx_stack_align(ucx_stack_topsize(stack))) + : stack->size)); + + if (avail > sizeof(struct ucx_stack_metadata)) { + return avail - sizeof(struct ucx_stack_metadata); + } else { + return 0; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/string.c Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,463 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ucx/string.h" + +#include "ucx/allocator.h" + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <stdint.h> +#include <ctype.h> + +sstr_t sstr(char *cstring) { + sstr_t string; + string.ptr = cstring; + string.length = strlen(cstring); + return string; +} + +sstr_t sstrn(char *cstring, size_t length) { + sstr_t string; + string.ptr = cstring; + string.length = length; + return string; +} + +size_t sstrnlen(size_t n, sstr_t s, ...) { + va_list ap; + size_t size = s.length; + va_start(ap, s); + + for (size_t i = 1 ; i < n ; i++) { + sstr_t str = va_arg(ap, sstr_t); + size += str.length; + } + va_end(ap); + + return size; +} + +static sstr_t sstrvcat_a( + UcxAllocator *a, + size_t count, + sstr_t s1, + sstr_t s2, + va_list ap) { + sstr_t str; + str.ptr = NULL; + str.length = 0; + if(count < 2) { + return str; + } + + sstr_t *strings = (sstr_t*) calloc(count, sizeof(sstr_t)); + if(!strings) { + return str; + } + + // get all args and overall length + strings[0] = s1; + strings[1] = s2; + size_t strlen = s1.length + s2.length; + for (size_t i=2;i<count;i++) { + sstr_t s = va_arg (ap, sstr_t); + strings[i] = s; + strlen += s.length; + } + + // create new string + str.ptr = (char*) almalloc(a, strlen + 1); + str.length = strlen; + if(!str.ptr) { + free(strings); + str.length = 0; + return str; + } + + // concatenate strings + size_t pos = 0; + for (size_t i=0;i<count;i++) { + sstr_t s = strings[i]; + memcpy(str.ptr + pos, s.ptr, s.length); + pos += s.length; + } + + str.ptr[str.length] = '\0'; + + free(strings); + + return str; +} + +sstr_t sstrcat(size_t count, sstr_t s1, sstr_t s2, ...) { + va_list ap; + va_start(ap, s2); + sstr_t s = sstrvcat_a(ucx_default_allocator(), count, s1, s2, ap); + va_end(ap); + return s; +} + +sstr_t sstrcat_a(UcxAllocator *a, size_t count, sstr_t s1, sstr_t s2, ...) { + va_list ap; + va_start(ap, s2); + sstr_t s = sstrvcat_a(a, count, s1, s2, ap); + va_end(ap); + return s; +} + +sstr_t sstrsubs(sstr_t s, size_t start) { + return sstrsubsl (s, start, s.length-start); +} + +sstr_t sstrsubsl(sstr_t s, size_t start, size_t length) { + sstr_t new_sstr; + if (start >= s.length) { + new_sstr.ptr = NULL; + new_sstr.length = 0; + } else { + if (length > s.length-start) { + length = s.length-start; + } + new_sstr.ptr = &s.ptr[start]; + new_sstr.length = length; + } + return new_sstr; +} + +sstr_t sstrchr(sstr_t s, int c) { + for(size_t i=0;i<s.length;i++) { + if(s.ptr[i] == c) { + return sstrsubs(s, i); + } + } + sstr_t n; + n.ptr = NULL; + n.length = 0; + return n; +} + +sstr_t sstrrchr(sstr_t s, int c) { + if (s.length > 0) { + for(size_t i=s.length;i>0;i--) { + if(s.ptr[i-1] == c) { + return sstrsubs(s, i-1); + } + } + } + sstr_t n; + n.ptr = NULL; + n.length = 0; + return n; +} + +#define ptable_r(dest, useheap, ptable, index) (dest = useheap ? \ + ((size_t*)ptable)[index] : (size_t) ((uint8_t*)ptable)[index]) + +#define ptable_w(useheap, ptable, index, src) do {\ + if (!useheap) ((uint8_t*)ptable)[index] = (uint8_t) src;\ + else ((size_t*)ptable)[index] = src;\ + } while (0); + +sstr_t sstrstr(sstr_t string, sstr_t match) { + if (match.length == 0) { + return string; + } + + /* prepare default return value in case of no match */ + sstr_t result = sstrn(NULL, 0); + + /* + * IMPORTANT: + * our prefix table contains the prefix length PLUS ONE + * this is our decision, because we want to use the full range of size_t + * the original algorithm needs a (-1) at one single place + * and we want to avoid that + */ + + /* static prefix table */ + static uint8_t s_prefix_table[256]; + + /* check pattern length and use appropriate prefix table */ + /* if the pattern exceeds static prefix table, allocate on the heap */ + register int useheap = match.length > 255; + register void* ptable = useheap ? + calloc(match.length+1, sizeof(size_t)): s_prefix_table; + + /* keep counter in registers */ + register size_t i, j; + + /* fill prefix table */ + i = 0; j = 0; + ptable_w(useheap, ptable, i, j); + while (i < match.length) { + while (j >= 1 && match.ptr[j-1] != match.ptr[i]) { + ptable_r(j, useheap, ptable, j-1); + } + i++; j++; + ptable_w(useheap, ptable, i, j); + } + + /* search */ + i = 0; j = 1; + while (i < string.length) { + while (j >= 1 && string.ptr[i] != match.ptr[j-1]) { + ptable_r(j, useheap, ptable, j-1); + } + i++; j++; + if (j-1 == match.length) { + size_t start = i - match.length; + result.ptr = string.ptr + start; + result.length = string.length - start; + break; + } + } + + /* if prefix table was allocated on the heap, free it */ + if (ptable != s_prefix_table) { + free(ptable); + } + + return result; +} + +#undef ptable_r +#undef ptable_w + +sstr_t* sstrsplit(sstr_t s, sstr_t d, ssize_t *n) { + return sstrsplit_a(ucx_default_allocator(), s, d, n); +} + +sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t s, sstr_t d, ssize_t *n) { + if (s.length == 0 || d.length == 0) { + *n = -1; + return NULL; + } + + /* special cases: delimiter is at least as large as the string */ + if (d.length >= s.length) { + /* exact match */ + if (sstrcmp(s, d) == 0) { + *n = 0; + return NULL; + } else /* no match possible */ { + *n = 1; + sstr_t *result = (sstr_t*) almalloc(allocator, sizeof(sstr_t)); + *result = sstrdup_a(allocator, s); + return result; + } + } + + ssize_t nmax = *n; + size_t arrlen = 16; + sstr_t* result = (sstr_t*) almalloc(allocator, arrlen*sizeof(sstr_t)); + + if (result) { + sstr_t curpos = s; + ssize_t j = 1; + while (1) { + sstr_t match; + /* optimize for one byte delimiters */ + if (d.length == 1) { + match = curpos; + for (size_t i = 0 ; i < curpos.length ; i++) { + if (curpos.ptr[i] == *(d.ptr)) { + match.ptr = curpos.ptr + i; + break; + } + match.length--; + } + } else { + match = sstrstr(curpos, d); + } + if (match.length > 0) { + /* is this our last try? */ + if (nmax == 0 || j < nmax) { + /* copy the current string to the array */ + sstr_t item = sstrn(curpos.ptr, match.ptr - curpos.ptr); + result[j-1] = sstrdup_a(allocator, item); + size_t processed = item.length + d.length; + curpos.ptr += processed; + curpos.length -= processed; + + /* allocate memory for the next string */ + j++; + if (j > arrlen) { + arrlen *= 2; + sstr_t* reallocated = (sstr_t*) alrealloc( + allocator, result, arrlen*sizeof(sstr_t)); + if (reallocated) { + result = reallocated; + } else { + for (ssize_t i = 0 ; i < j-1 ; i++) { + alfree(allocator, result[i].ptr); + } + alfree(allocator, result); + *n = -2; + return NULL; + } + } + } else { + /* nmax reached, copy the _full_ remaining string */ + result[j-1] = sstrdup_a(allocator, curpos); + break; + } + } else { + /* no more matches, copy last string */ + result[j-1] = sstrdup_a(allocator, curpos); + break; + } + } + *n = j; + } else { + *n = -2; + } + + return result; +} + +int sstrcmp(sstr_t s1, sstr_t s2) { + if (s1.length == s2.length) { + return memcmp(s1.ptr, s2.ptr, s1.length); + } else if (s1.length > s2.length) { + return 1; + } else { + return -1; + } +} + +int sstrcasecmp(sstr_t s1, sstr_t s2) { + if (s1.length == s2.length) { +#ifdef _WIN32 + return _strnicmp(s1.ptr, s2.ptr, s1.length); +#else + return strncasecmp(s1.ptr, s2.ptr, s1.length); +#endif + } else if (s1.length > s2.length) { + return 1; + } else { + return -1; + } +} + +sstr_t sstrdup(sstr_t s) { + return sstrdup_a(ucx_default_allocator(), s); +} + +sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t s) { + sstr_t newstring; + newstring.ptr = (char*)almalloc(allocator, s.length + 1); + if (newstring.ptr) { + newstring.length = s.length; + newstring.ptr[newstring.length] = 0; + + memcpy(newstring.ptr, s.ptr, s.length); + } else { + newstring.length = 0; + } + + return newstring; +} + +sstr_t sstrtrim(sstr_t string) { + sstr_t newstr = string; + + while (newstr.length > 0 && isspace(*newstr.ptr)) { + newstr.ptr++; + newstr.length--; + } + while (newstr.length > 0 && isspace(newstr.ptr[newstr.length-1])) { + newstr.length--; + } + + return newstr; +} + +int sstrprefix(sstr_t string, sstr_t prefix) { + if (string.length == 0) { + return prefix.length == 0; + } + if (prefix.length == 0) { + return 1; + } + + if (prefix.length > string.length) { + return 0; + } else { + return memcmp(string.ptr, prefix.ptr, prefix.length) == 0; + } +} + +int sstrsuffix(sstr_t string, sstr_t suffix) { + if (string.length == 0) { + return suffix.length == 0; + } + if (suffix.length == 0) { + return 1; + } + + if (suffix.length > string.length) { + return 0; + } else { + return memcmp(string.ptr+string.length-suffix.length, + suffix.ptr, suffix.length) == 0; + } +} + +sstr_t sstrlower(sstr_t string) { + sstr_t ret = sstrdup(string); + for (size_t i = 0; i < ret.length ; i++) { + ret.ptr[i] = tolower(ret.ptr[i]); + } + return ret; +} + +sstr_t sstrlower_a(UcxAllocator *allocator, sstr_t string) { + sstr_t ret = sstrdup_a(allocator, string); + for (size_t i = 0; i < ret.length ; i++) { + ret.ptr[i] = tolower(ret.ptr[i]); + } + return ret; +} + +sstr_t sstrupper(sstr_t string) { + sstr_t ret = sstrdup(string); + for (size_t i = 0; i < ret.length ; i++) { + ret.ptr[i] = toupper(ret.ptr[i]); + } + return ret; +} + +sstr_t sstrupper_a(UcxAllocator *allocator, sstr_t string) { + sstr_t ret = sstrdup_a(allocator, string); + for (size_t i = 0; i < ret.length ; i++) { + ret.ptr[i] = toupper(ret.ptr[i]); + } + return ret; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/test.c Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,91 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ucx/test.h" + +UcxTestSuite* ucx_test_suite_new() { + UcxTestSuite* suite = (UcxTestSuite*) malloc(sizeof(UcxTestSuite)); + if (suite != NULL) { + suite->success = 0; + suite->failure = 0; + suite->tests = NULL; + } + + return suite; +} + +void ucx_test_suite_free(UcxTestSuite* suite) { + UcxTestList *l = suite->tests; + while (l != NULL) { + UcxTestList *e = l; + l = l->next; + free(e); + } + free(suite); +} + +int ucx_test_register(UcxTestSuite* suite, UcxTest test) { + if (suite->tests) { + UcxTestList *newelem = (UcxTestList*) malloc(sizeof(UcxTestList)); + if (newelem) { + newelem->test = test; + newelem->next = NULL; + + UcxTestList *last = suite->tests; + while (last->next) { + last = last->next; + } + last->next = newelem; + + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } + } else { + suite->tests = (UcxTestList*) malloc(sizeof(UcxTestList)); + if (suite->tests) { + suite->tests->test = test; + suite->tests->next = NULL; + + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } + } +} + +void ucx_test_run(UcxTestSuite* suite, FILE* output) { + suite->success = 0; + suite->failure = 0; + for (UcxTestList* elem = suite->tests ; elem ; elem = elem->next) { + elem->test(suite, output); + } + fwrite("\nAll test completed.\n", 1, 21, output); + fprintf(output, " Total: %u\n Success: %u\n Failure: %u\n", + suite->success+suite->failure, suite->success, suite->failure); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx.c Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,37 @@ +/** + * @mainpage UAP Common Extensions + * Library with common and useful functions, macros and data structures. + * <p> + * Latest available source:<br/> + * <a href="https://develop.uap-core.de/hg/ucx"> + * https://develop.uap-core.de/hg/ucx</a> + * </p> + * + * <h2>LICENCE</h2> + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ucx/ucx.h"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/allocator.h Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,206 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/** + * Allocator for custom memory management. + * + * A UCX allocator consists of a pointer to the memory area / pool and four + * function pointers to memory management functions operating on this memory + * area / pool. These functions shall behave equivalent to the standard libc + * functions <code>malloc(), calloc(), realloc()</code> and <code>free()</code>. + * + * The signature of the memory management functions is based on the signature + * of the respective libc function but each of them takes the pointer to the + * memory area / pool as first argument. + * + * As the pointer to the memory area / pool can be arbitrarily chosen, any data + * can be provided to the memory management functions. A UcxMempool is just + * one example. + * + * @see mempool.h + * @see UcxMap + * + * @file allocator.h + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_ALLOCATOR_H +#define UCX_ALLOCATOR_H + +#include <ucx/ucx.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A function pointer to the allocators <code>malloc()</code> function. + * @see UcxAllocator + */ +typedef void*(*ucx_allocator_malloc)(void *pool, size_t n); + +/** + * A function pointer to the allocators <code>calloc()</code> function. + * @see UcxAllocator + */ +typedef void*(*ucx_allocator_calloc)(void *pool, size_t n, size_t size); + +/** + * A function pointer to the allocators <code>realloc()</code> function. + * @see UcxAllocator + */ +typedef void*(*ucx_allocator_realloc)(void *pool, void *data, size_t n); + +/** + * A function pointer to the allocators <code>free()</code> function. + * @see UcxAllocator + */ +typedef void(*ucx_allocator_free)(void *pool, void *data); + +/** + * UCX allocator data structure containing memory management functions. + */ +typedef struct { + /** Pointer to an area of memory or a complex memory pool. + * This pointer will be passed to any memory management function as first + * argument. + */ + void *pool; + /** + * The <code>malloc()</code> function for this allocator. + */ + ucx_allocator_malloc malloc; + /** + * The <code>calloc()</code> function for this allocator. + */ + ucx_allocator_calloc calloc; + /** + * The <code>realloc()</code> function for this allocator. + */ + ucx_allocator_realloc realloc; + /** + * The <code>free()</code> function for this allocator. + */ + ucx_allocator_free free; +} UcxAllocator; + +/** + * Returns a pointer to the default allocator. + * + * The default allocator contains wrappers to the standard libc memory + * management functions. Use this function to get a pointer to a globally + * available allocator. You may also define an own UcxAllocator by assigning + * #UCX_ALLOCATOR_DEFAULT to a variable and pass the address of this variable + * to any function that takes a UcxAllocator as argument. Note that using + * this function is the recommended way of passing a default allocator, thus + * it never runs out of scope. + * + * @return a pointer to the default allocator + * + * @see UCX_ALLOCATOR_DEFAULT + */ +UcxAllocator *ucx_default_allocator(); + +/** + * A wrapper for the standard libc <code>malloc()</code> function. + * @param ignore ignored (may be used by allocators for pooled memory) + * @param n argument passed to <code>malloc()</code> + * @return return value of <code>malloc()</code> + */ +void *ucx_default_malloc(void *ignore, size_t n); +/** + * A wrapper for the standard libc <code>calloc()</code> function. + * @param ignore ignored (may be used by allocators for pooled memory) + * @param n argument passed to <code>calloc()</code> + * @param size argument passed to <code>calloc()</code> + * @return return value of <code>calloc()</code> + */ +void *ucx_default_calloc(void *ignore, size_t n, size_t size); +/** + * A wrapper for the standard libc <code>realloc()</code> function. + * @param ignore ignored (may be used by allocators for pooled memory) + * @param data argumend passed to <code>realloc()</code> + * @param n argument passed to <code>realloc()</code> + * @return return value of <code>realloc()</code> + */ +void *ucx_default_realloc(void *ignore, void *data, size_t n); +/** + * A wrapper for the standard libc <code>free()</code> function. + * @param ignore ignored (may be used by allocators for pooled memory) + * @param data argument passed to <code>free()</code> + */ +void ucx_default_free(void *ignore, void *data); + +/** + * Shorthand for calling an allocators malloc function. + * @param allocator the allocator to use + * @param n size of space to allocate + * @return a pointer to the allocated memory area + */ +#define almalloc(allocator, n) ((allocator)->malloc((allocator)->pool, n)) + +/** + * Shorthand for calling an allocators calloc function. + * @param allocator the allocator to use + * @param n the count of elements the space should be allocated for + * @param size the size of each element + * @return a pointer to the allocated memory area + */ +#define alcalloc(allocator, n, size) \ + ((allocator)->calloc((allocator)->pool, n, size)) + +/** + * Shorthand for calling an allocators realloc function. + * @param allocator the allocator to use + * @param ptr the pointer to the memory area that shall be reallocated + * @param n the new size of the allocated memory area + * @return a pointer to the reallocated memory area + */ +#define alrealloc(allocator, ptr, n) \ + ((allocator)->realloc((allocator)->pool, ptr, n)) + +/** + * Shorthand for calling an allocators free function. + * @param allocator the allocator to use + * @param ptr the pointer to the memory area that shall be freed + */ +#define alfree(allocator, ptr) ((allocator)->free((allocator)->pool, ptr)) + +/** + * Convenient macro for a default allocator <code>struct</code> definition. + */ +#define UCX_ALLOCATOR_DEFAULT {NULL, \ + ucx_default_malloc, ucx_default_calloc, ucx_default_realloc, \ + ucx_default_free } + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_ALLOCATOR_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/avl.h Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,327 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @file avl.h + * + * AVL tree implementation. + * + * This binary search tree implementation allows average O(1) insertion and + * removal of elements (excluding binary search time). + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_AVL_H +#define UCX_AVL_H + +#include <ucx/ucx.h> +#include <ucx/allocator.h> +#include <inttypes.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * UCX AVL Node type. + * + * @see UcxAVLNode + */ +typedef struct UcxAVLNode UcxAVLNode; + +/** + * UCX AVL Node. + */ +struct UcxAVLNode { + /** + * The key for this node. + */ + intptr_t key; + /** + * Data contained by this node. + */ + void *value; + /** + * The height of this (sub)-tree. + */ + size_t height; + /** + * Parent node. + */ + UcxAVLNode *parent; + /** + * Root node of left subtree. + */ + UcxAVLNode *left; + /** + * Root node of right subtree. + */ + UcxAVLNode *right; +}; + +/** + * UCX AVL Tree. + */ +typedef struct { + /** + * The UcxAllocator that shall be used to manage the memory for node data. + */ + UcxAllocator *allocator; + /** + * Root node of the tree. + */ + UcxAVLNode *root; + /** + * Compare function that shall be used to compare the UcxAVLNode keys. + * @see UcxAVLNode.key + */ + cmp_func cmpfunc; + /** + * Custom user data. + * This data will also be provided to the cmpfunc. + */ + void *userdata; +} UcxAVLTree; + +/** + * Initializes a new UcxAVLTree with a default allocator. + * + * @param cmpfunc the compare function that shall be used + * @return a new UcxAVLTree object + * @see ucx_avl_new_a() + */ +UcxAVLTree *ucx_avl_new(cmp_func cmpfunc); + +/** + * Initializes a new UcxAVLTree with the specified allocator. + * + * The cmpfunc should be capable of comparing two keys within this AVL tree. + * So if you want to use null terminated strings as keys, you could use the + * ucx_strcmp() function here. + * + * @param cmpfunc the compare function that shall be used + * @param allocator the UcxAllocator that shall be used + * @return a new UcxAVLTree object + */ +UcxAVLTree *ucx_avl_new_a(cmp_func cmpfunc, UcxAllocator *allocator); + +/** + * Destroys a UcxAVLTree. + * @param tree the tree to destroy + */ +void ucx_avl_free(UcxAVLTree *tree); + +/** + * Macro for initializing a new UcxAVLTree with the default allocator and a + * ucx_ptrcmp() compare function. + * + * @return a new default UcxAVLTree object + */ +#define ucx_avl_default_new() ucx_avl_new_a(ucx_ptrcmp, ucx_default_allocator()) + +/** + * Gets the node from the tree, that is associated with the specified key. + * @param tree the UcxAVLTree + * @param key the key + * @return the node (or <code>NULL</code>, if the key is not present) + */ +UcxAVLNode *ucx_avl_get_node(UcxAVLTree *tree, intptr_t key); + +/** + * Gets the value from the tree, that is associated with the specified key. + * @param tree the UcxAVLTree + * @param key the key + * @return the value (or <code>NULL</code>, if the key is not present) + */ +void *ucx_avl_get(UcxAVLTree *tree, intptr_t key); + +/** + * A mode for #ucx_avl_find_node() with the same behavior as + * #ucx_avl_get_node(). + */ +#define UCX_AVL_FIND_EXACT 0 +/** + * A mode for #ucx_avl_find_node() finding the node whose key is at least + * as large as the specified key. + */ +#define UCX_AVL_FIND_LOWER_BOUNDED 1 +/** + * A mode for #ucx_avl_find_node() finding the node whose key is at most + * as large as the specified key. + */ +#define UCX_AVL_FIND_UPPER_BOUNDED 2 +/** + * A mode for #ucx_avl_find_node() finding the node with a key that is as close + * to the specified key as possible. If the key is present, the behavior is + * like #ucx_avl_get_node(). This mode only returns <code>NULL</code> on + * empty trees. + */ +#define UCX_AVL_FIND_CLOSEST 3 + +/** + * Finds a node within the tree. The following modes are supported: + * <ul> + * <li>#UCX_AVL_FIND_EXACT: the same behavior as #ucx_avl_get_node()</li> + * <li>#UCX_AVL_FIND_LOWER_BOUNDED: finds the node whose key is at least + * as large as the specified key</li> + * <li>#UCX_AVL_FIND_UPPER_BOUNDED: finds the node whose key is at most + * as large as the specified key</li> + * <li>#UCX_AVL_FIND_CLOSEST: finds the node with a key that is as close to + * the specified key as possible. If the key is present, the behavior is + * like #ucx_avl_get_node(). This mode only returns <code>NULL</code> on + * empty trees.</li> + * </ul> + * + * The distance function provided MUST agree with the compare function of + * the AVL tree. + * + * @param tree the UcxAVLTree + * @param key the key + * @param dfnc the distance function + * @param mode the find mode + * @return the node (or <code>NULL</code>, if no node can be found) + */ +UcxAVLNode *ucx_avl_find_node(UcxAVLTree *tree, intptr_t key, + distance_func dfnc, int mode); + +/** + * Finds a value within the tree. + * See #ucx_avl_find_node() for details. + * + * @param tree the UcxAVLTree + * @param key the key + * @param dfnc the distance function + * @param mode the find mode + * @return the value (or <code>NULL</code>, if no value can be found) + */ +void *ucx_avl_find(UcxAVLTree *tree, intptr_t key, + distance_func dfnc, int mode); + +/** + * Puts a key/value pair into the tree. + * + * Attention: use this function only, if a possible old value does not need + * to be preserved. + * + * @param tree the UcxAVLTree + * @param key the key + * @param value the new value + * @return zero, if and only if the operation succeeded + */ +int ucx_avl_put(UcxAVLTree *tree, intptr_t key, void *value); + +/** + * Puts a key/value pair into the tree. + * + * This is a secure function which saves the old value to the variable pointed + * at by oldvalue. + * + * @param tree the UcxAVLTree + * @param key the key + * @param value the new value + * @param oldvalue optional: a pointer to the location where a possible old + * value shall be stored + * @return zero, if and only if the operation succeeded + */ +int ucx_avl_put_s(UcxAVLTree *tree, intptr_t key, void *value, void **oldvalue); + +/** + * Removes a node from the AVL tree. + * + * Note: the specified node is logically removed. The tree implementation + * decides which memory area is freed. In most cases the here provided node + * is freed, so its further use is generally undefined. + * + * @param tree the UcxAVLTree + * @param node the node to remove + * @return zero, if and only if an element has been removed + */ +int ucx_avl_remove_node(UcxAVLTree *tree, UcxAVLNode *node); + +/** + * Removes an element from the AVL tree. + * + * @param tree the UcxAVLTree + * @param key the key + * @return zero, if and only if an element has been removed + */ +int ucx_avl_remove(UcxAVLTree *tree, intptr_t key); + +/** + * Removes an element from the AVL tree. + * + * This is a secure function which saves the old key and value data from node + * to the variables at the location of oldkey and oldvalue (if specified), so + * they can be freed afterwards (if necessary). + * + * Note: the returned key in oldkey is possibly not the same as the provided + * key for the lookup (in terms of memory location). + * + * @param tree the UcxAVLTree + * @param key the key of the element to remove + * @param oldkey optional: a pointer to the location where the old key shall be + * stored + * @param oldvalue optional: a pointer to the location where the old value + * shall be stored + * @return zero, if and only if an element has been removed + */ +int ucx_avl_remove_s(UcxAVLTree *tree, intptr_t key, + intptr_t *oldkey, void **oldvalue); + +/** + * Counts the nodes in the specified UcxAVLTree. + * @param tree the AVL tree + * @return the node count + */ +size_t ucx_avl_count(UcxAVLTree *tree); + +/** + * Finds the in-order predecessor of the given node. + * @param node an AVL node + * @return the in-order predecessor of the given node, or <code>NULL</code> if + * the given node is the in-order minimum + */ +UcxAVLNode* ucx_avl_pred(UcxAVLNode* node); + +/** + * Finds the in-order successor of the given node. + * @param node an AVL node + * @return the in-order successor of the given node, or <code>NULL</code> if + * the given node is the in-order maximum + */ +UcxAVLNode* ucx_avl_succ(UcxAVLNode* node); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_AVL_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/buffer.h Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,270 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file buffer.h + * + * Advanced buffer implementation. + * + * Instances of UcxBuffer can be used to read from or to write to like one + * would do with a stream. This allows the use of ucx_stream_copy() to copy + * contents from one buffer to another. + * + * Some features for convenient use of the buffer + * can be enabled. See the documentation of the macro constants for more + * information. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_BUFFER_H +#define UCX_BUFFER_H + +#include <ucx/ucx.h> +#include <sys/types.h> +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * No buffer features enabled (all flags cleared). + */ +#define UCX_BUFFER_DEFAULT 0x00 + +/** + * If this flag is enabled, the buffer will automatically free its contents. + */ +#define UCX_BUFFER_AUTOFREE 0x01 + +/** + * If this flag is enabled, the buffer will automatically extends its capacity. + */ +#define UCX_BUFFER_AUTOEXTEND 0x02 + +/** UCX Buffer. */ +typedef struct { + /** A pointer to the buffer contents. */ + char *space; + /** Current position of the buffer. */ + size_t pos; + /** Current capacity (i.e. maximum size) of the buffer. */ + size_t capacity; + /** Current size of the buffer content. */ + size_t size; + /** + * Flag register for buffer features. + * @see #UCX_BUFFER_DEFAULT + * @see #UCX_BUFFER_AUTOFREE + * @see #UCX_BUFFER_AUTOEXTEND + */ + int flags; +} UcxBuffer; + +/** + * Creates a new buffer. + * + * <b>Note:</b> you may provide <code>NULL</code> as argument for + * <code>space</code>. Then this function will allocate the space and enforce + * the #UCX_BUFFER_AUTOFREE flag. + * + * @param space pointer to the memory area, or <code>NULL</code> to allocate + * new memory + * @param capacity the capacity of the buffer + * @param flags buffer features (see UcxBuffer.flags) + * @return the new buffer + */ +UcxBuffer *ucx_buffer_new(void *space, size_t capacity, int flags); + +/** + * Destroys a buffer. + * + * If the #UCX_BUFFER_AUTOFREE feature is enabled, the contents of the buffer + * are also freed. + * + * @param buffer the buffer to destroy + */ +void ucx_buffer_free(UcxBuffer* buffer); + +/** + * Creates a new buffer and fills it with extracted content from another buffer. + * + * <b>Note:</b> the #UCX_BUFFER_AUTOFREE feature is enforced for the new buffer. + * + * @param src the source buffer + * @param start the start position of extraction + * @param length the count of bytes to extract (must not be zero) + * @param flags feature mask for the new buffer + * @return a new buffer containing the extraction + */ +UcxBuffer* ucx_buffer_extract(UcxBuffer *src, + size_t start, size_t length, int flags); + +/** + * A shorthand macro for the full extraction of the buffer. + * + * @param src the source buffer + * @param flags feature mask for the new buffer + * @return a new buffer with the extracted content + */ +#define ucx_buffer_clone(src,flags) \ + ucx_buffer_extract(src, 0, (src)->capacity, flags) + +/** + * Moves the position of the buffer. + * + * The new position is relative to the <code>whence</code> argument. + * + * SEEK_SET marks the start of the buffer. + * SEEK_CUR marks the current position. + * SEEK_END marks the end of the buffer. + * + * With an offset of zero, this function sets the buffer position to zero + * (SEEK_SET), the buffer size (SEEK_END) or leaves the buffer position + * unchanged (SEEK_CUR). + * + * @param buffer + * @param offset position offset relative to <code>whence</code> + * @param whence one of SEEK_SET, SEEK_CUR or SEEK_END + * @return 0 on success, non-zero if the position is invalid + * + */ +int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence); + +/** + * Clears the buffer by resetting the position and deleting the data. + * + * The data is deleted by a zeroing it with call to <code>memset()</code>. + * + * @param buffer the buffer to be cleared + */ +#define ucx_buffer_clear(buffer) memset(buffer->space, 0, buffer->size); \ + buffer->size = 0; buffer->pos = 0; + +/** + * Tests, if the buffer position has exceeded the buffer capacity. + * + * @param buffer the buffer to test + * @return non-zero, if the current buffer position has exceeded the last + * available byte of the buffer. + */ +int ucx_buffer_eof(UcxBuffer *buffer); + + +/** + * Extends the capacity of the buffer. + * + * <b>Note:</b> The buffer capacity increased by a power of two. I.e. + * the buffer capacity is doubled, as long as it would not hold the current + * content plus the additional required bytes. + * + * <b>Attention:</b> the argument provided is the number of <i>additional</i> + * bytes the buffer shall hold. It is <b>NOT</b> the total number of bytes the + * buffer shall hold. + * + * @param buffer the buffer to extend + * @param additional_bytes the number of additional bytes the buffer shall + * <i>at least</i> hold + * @return 0 on success or a non-zero value on failure + */ +int ucx_buffer_extend(UcxBuffer *buffer, size_t additional_bytes); + +/** + * Writes data to a UcxBuffer. + * + * The position of the buffer is increased by the number of bytes written. + * + * @param ptr a pointer to the memory area containing the bytes to be written + * @param size the length of one element + * @param nitems the element count + * @param buffer the UcxBuffer to write to + * @return the total count of bytes written + */ +size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, + UcxBuffer *buffer); + +/** + * Reads data from a UcxBuffer. + * + * The position of the buffer is increased by the number of bytes read. + * + * @param ptr a pointer to the memory area where to store the read data + * @param size the length of one element + * @param nitems the element count + * @param buffer the UcxBuffer to read from + * @return the total number of elements read + */ +size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, + UcxBuffer *buffer); + +/** + * Writes a character to a buffer. + * + * The least significant byte of the argument is written to the buffer. If the + * end of the buffer is reached and #UCX_BUFFER_AUTOEXTEND feature is enabled, + * the buffer capacity is extended by ucx_buffer_extend(). If the feature is + * disabled or buffer extension fails, <code>EOF</code> is returned. + * + * On successful write the position of the buffer is increased. + * + * @param buffer the buffer to write to + * @param c the character to write as <code>int</code> value + * @return the byte that has bean written as <code>int</code> value or + * <code>EOF</code> when the end of the stream is reached and automatic + * extension is not enabled or not possible + */ +int ucx_buffer_putc(UcxBuffer *buffer, int c); + +/** + * Gets a character from a buffer. + * + * The current position of the buffer is increased after a successful read. + * + * @param buffer the buffer to read from + * @return the character as <code>int</code> value or <code>EOF</code>, if the + * end of the buffer is reached + */ +int ucx_buffer_getc(UcxBuffer *buffer); + +/** + * Writes a string to a buffer. + * + * @param buffer the buffer + * @param str the string + * @return the number of bytes written + */ +size_t ucx_buffer_puts(UcxBuffer *buffer, char *str); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_BUFFER_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/list.h Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,428 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/** + * Doubly linked list implementation. + * + * @file list.h + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_LIST_H +#define UCX_LIST_H + +#include <ucx/ucx.h> +#include <ucx/allocator.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Loop statement for UCX lists. + * + * The first argument is the name of the iteration variable. The scope of + * this variable is limited to the <code>UCX_FOREACH</code> statement. + * + * The second argument is a pointer to the list. In most cases this will be the + * pointer to the first element of the list, but it may also be an arbitrary + * element of the list. The iteration will then start with that element. + * + * @param list The first element of the list + * @param elem The variable name of the element + */ +#define UCX_FOREACH(elem,list) \ + for (UcxList* elem = list ; elem != NULL ; elem = elem->next) + +/** + * UCX list type. + * @see UcxList + */ +typedef struct UcxList UcxList; + +/** + * UCX list structure. + */ +struct UcxList { + /** + * List element payload. + */ + void *data; + /** + * Pointer to the next list element or <code>NULL</code>, if this is the + * last element. + */ + UcxList *next; + /** + * Pointer to the previous list element or <code>NULL</code>, if this is + * the first element. + */ + UcxList *prev; +}; + +/** + * Creates an element-wise copy of a list. + * + * This function clones the specified list by creating new list elements and + * copying the data with the specified copy_func(). If no copy_func() is + * specified, a shallow copy is created and the new list will reference the + * same data as the source list. + * + * @param list the list to copy + * @param cpyfnc a pointer to the function that shall copy an element (may be + * <code>NULL</code>) + * @param data additional data for the copy_func() + * @return a pointer to the copy + */ +UcxList *ucx_list_clone(UcxList *list, copy_func cpyfnc, void* data); + +/** + * Creates an element-wise copy of a list using a UcxAllocator. + * + * See ucx_list_clone() for details. + * + * You might want to pass the allocator via the <code>data</code> parameter, + * to access it within the copy function for making deep copies. + * + * @param allocator the allocator to use + * @param list the list to copy + * @param cpyfnc a pointer to the function that shall copy an element (may be + * <code>NULL</code>) + * @param data additional data for the copy_func() + * @return a pointer to the copy + * @see ucx_list_clone() + */ +UcxList *ucx_list_clone_a(UcxAllocator *allocator, UcxList *list, + copy_func cpyfnc, void* data); + +/** + * Compares two UCX lists element-wise by using a compare function. + * + * Each element of the two specified lists are compared by using the specified + * compare function and the additional data. The type and content of this + * additional data depends on the cmp_func() used. + * + * If the list pointers denote elements within a list, the lists are compared + * starting with the denoted elements. Thus any previous elements are not taken + * into account. This might be useful to check, if certain list tails match + * each other. + * + * @param list1 the first list + * @param list2 the second list + * @param cmpfnc the compare function + * @param data additional data for the compare function + * @return 1, if and only if the two lists equal element-wise, 0 otherwise + */ +int ucx_list_equals(const UcxList *list1, const UcxList *list2, + cmp_func cmpfnc, void* data); + +/** + * Destroys the entire list. + * + * The members of the list are not automatically freed, so ensure they are + * otherwise referenced or destroyed by ucx_list_free_contents(). + * Otherwise, a memory leak is likely to occur. + * + * <b>Caution:</b> the argument <b>MUST</b> denote an entire list (i.e. a call + * to ucx_list_first() on the argument must return the argument itself) + * + * @param list the list to free + * @see ucx_list_free_contents() + */ +void ucx_list_free(UcxList *list); + +/** + * Destroys the entire list using a UcxAllocator. + * + * See ucx_list_free() for details. + * + * @param allocator the allocator to use + * @param list the list to free + * @see ucx_list_free() + */ +void ucx_list_free_a(UcxAllocator *allocator, UcxList *list); + +/** + * Destroys the contents of the specified list by calling the specified + * destructor on each of them. + * + * Note, that the contents are not usable afterwards and the list should be + * destroyed with ucx_list_free(). + * + * @param list the list for which the contents shall be freed + * @param destr the destructor function (e.g. stdlib free()) + * @see ucx_list_free() + */ +void ucx_list_free_content(UcxList* list, ucx_destructor destr); + + +/** + * Inserts an element at the end of the list. + * + * This is generally an O(n) operation, as the end of the list is retrieved with + * ucx_list_last(). + * + * @param list the list where to append the data, or <code>NULL</code> to + * create a new list + * @param data the data to insert + * @return <code>list</code>, if it is not <code>NULL</code> or a pointer to + * the newly created list otherwise + */ +UcxList *ucx_list_append(UcxList *list, void *data); + +/** + * Inserts an element at the end of the list using a UcxAllocator. + * + * See ucx_list_append() for details. + * + * @param allocator the allocator to use + * @param list the list where to append the data, or <code>NULL</code> to + * create a new list + * @param data the data to insert + * @return <code>list</code>, if it is not <code>NULL</code> or a pointer to + * the newly created list otherwise + * @see ucx_list_append() + */ +UcxList *ucx_list_append_a(UcxAllocator *allocator, UcxList *list, void *data); + +/** + * Inserts an element at the end of the list, if it is not present in the list. + * + * + * @param list the list where to append the data, or <code>NULL</code> to + * create a new list + * @param data the data to insert + * @param cmpfnc the compare function + * @param cmpdata additional data for the compare function + * @return <code>list</code>, if it is not <code>NULL</code> or a pointer to + * the newly created list otherwise + * @see ucx_list_append() + */ +UcxList *ucx_list_append_once(UcxList *list, void *data, + cmp_func cmpfnc, void *cmpdata); + +/** + * Inserts an element at the end of the list, if it is not present in the list, + * using a UcxAllocator. + * + * See ucx_list_append() for details. + * + * @param allocator the allocator to use + * @param list the list where to append the data, or <code>NULL</code> to + * create a new list + * @param data the data to insert + * @param cmpfnc the compare function + * @param cmpdata additional data for the compare function + * @return <code>list</code>, if it is not <code>NULL</code> or a pointer to + * the newly created list otherwise + * @see ucx_list_append_a() + */ +UcxList *ucx_list_append_once_a(UcxAllocator *allocator, + UcxList *list, void *data, cmp_func cmpfnc, void *cmpdata); + +/** + * Inserts an element at the beginning of the list. + * + * You <i>should</i> overwrite the old list pointer by calling + * <code>mylist = ucx_list_prepend(mylist, mydata);</code>. However, you may + * also perform successive calls of ucx_list_prepend() on the same list pointer, + * as this function always searchs for the head of the list with + * ucx_list_first(). + * + * @param list the list where to insert the data or <code>NULL</code> to create + * a new list + * @param data the data to insert + * @return a pointer to the new list head + */ +UcxList *ucx_list_prepend(UcxList *list, void *data); + +/** + * Inserts an element at the beginning of the list using a UcxAllocator. + * + * See ucx_list_prepend() for details. + * + * @param allocator the allocator to use + * @param list the list where to insert the data or <code>NULL</code> to create + * a new list + * @param data the data to insert + * @return a pointer to the new list head + * @see ucx_list_prepend() + */ +UcxList *ucx_list_prepend_a(UcxAllocator *allocator, UcxList *list, void *data); + +/** + * Concatenates two lists. + * + * Either of the two arguments may be <code>NULL</code>. + * + * This function modifies the references to the next/previous element of + * the last/first element of <code>list1</code>/<code> + * list2</code>. + * + * @param list1 first list + * @param list2 second list + * @return if <code>list1</code> is <code>NULL</code>, <code>list2</code> is + * returned, otherwise <code>list1</code> is returned + */ +UcxList *ucx_list_concat(UcxList *list1, UcxList *list2); + +/** + * Returns the first element of a list. + * + * If the argument is the list pointer, it is directly returned. Otherwise + * this function traverses to the first element of the list and returns the + * list pointer. + * + * @param elem one element of the list + * @return the first element of the list, the specified element is a member of + */ +UcxList *ucx_list_first(const UcxList *elem); + +/** + * Returns the last element of a list. + * + * If the argument has no successor, it is the last element and therefore + * directly returned. Otherwise this function traverses to the last element of + * the list and returns it. + * + * @param elem one element of the list + * @return the last element of the list, the specified element is a member of + */ +UcxList *ucx_list_last(const UcxList *elem); + +/** + * Returns the list element at the specified index. + * + * @param list the list to retrieve the element from + * @param index index of the element to return + * @return the element at the specified index or <code>NULL</code>, if the + * index is greater than the list size + */ +UcxList *ucx_list_get(const UcxList *list, size_t index); + +/** + * Returns the index of an element. + * + * @param list the list where to search for the element + * @param elem the element to find + * @return the index of the element or -1 if the list does not contain the + * element + */ +ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem); + +/** + * Returns the element count of the list. + * + * @param list the list whose elements are counted + * @return the element count + */ +size_t ucx_list_size(const UcxList *list); + +/** + * Returns the index of an element containing the specified data. + * + * This function uses a cmp_func() to compare the data of each list element + * with the specified data. If no cmp_func is provided, the pointers are + * compared. + * + * If the list contains the data more than once, the index of the first + * occurrence is returned. + * + * @param list the list where to search for the data + * @param elem the element data + * @param cmpfnc the compare function + * @param data additional data for the compare function + * @return the index of the element containing the specified data or -1 if the + * data is not found in this list + */ +ssize_t ucx_list_find(UcxList *list, void *elem, cmp_func cmpfnc, void *data); + +/** + * Checks, if a list contains a specific element. + * + * An element is found, if ucx_list_find() returns a value greater than -1. + * + * @param list the list where to search for the data + * @param elem the element data + * @param cmpfnc the compare function + * @param data additional data for the compare function + * @return 1, if and only if the list contains the specified element data + * @see ucx_list_find() + */ +int ucx_list_contains(UcxList *list, void *elem, cmp_func cmpfnc, void *data); + +/** + * Sorts a UcxList with natural merge sort. + * + * This function uses O(n) additional temporary memory for merge operations + * that is automatically freed after each merge. + * + * As the head of the list might change, you <b>MUST</b> call this function + * as follows: <code>mylist = ucx_list_sort(mylist, mycmpfnc, mydata);</code>. + * + * @param list the list to sort + * @param cmpfnc the function that shall be used to compare the element data + * @param data additional data for the cmp_func() + * @return the sorted list + */ +UcxList *ucx_list_sort(UcxList *list, cmp_func cmpfnc, void *data); + +/** + * Removes an element from the list. + * + * If the first element is removed, the list pointer changes. So it is + * <i>highly recommended</i> to <i>always</i> update the pointer by calling + * <code>mylist = ucx_list_remove(mylist, myelem);</code>. + * + * @param list the list from which the element shall be removed + * @param element the element to remove + * @return returns the updated list pointer or <code>NULL</code>, if the list + * is now empty + */ +UcxList *ucx_list_remove(UcxList *list, UcxList *element); + +/** + * Removes an element from the list using a UcxAllocator. + * + * See ucx_list_remove() for details. + * + * @param allocator the allocator to use + * @param list the list from which the element shall be removed + * @param element the element to remove + * @return returns the updated list pointer or <code>NULL</code>, if the list + * @see ucx_list_remove() + */ +UcxList *ucx_list_remove_a(UcxAllocator *allocator, UcxList *list, + UcxList *element); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_LIST_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/logging.h Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,238 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/** + * Logging API. + * + * @file logging.h + * @author Mike Becker, Olaf Wintermann + */ +#ifndef UCX_LOGGING_H +#define UCX_LOGGING_H + +#include <ucx/ucx.h> +#include <ucx/map.h> +#include <ucx/string.h> +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* leave enough space for custom log levels */ + +/** Log level for error messages. */ +#define UCX_LOGGER_ERROR 0x00 + +/** Log level for warning messages. */ +#define UCX_LOGGER_WARN 0x10 + +/** Log level for information messages. */ +#define UCX_LOGGER_INFO 0x20 + +/** Log level for debug messages. */ +#define UCX_LOGGER_DEBUG 0x30 + +/** Log level for trace messages. */ +#define UCX_LOGGER_TRACE 0x40 + +/** + * Output flag for the log level. + * If this flag is set, the log message will contain the log level. + * @see UcxLogger.mask + */ +#define UCX_LOGGER_LEVEL 0x01 + +/** + * Output flag for the timestmap. + * If this flag is set, the log message will contain the timestmap. + * @see UcxLogger.mask + */ +#define UCX_LOGGER_TIMESTAMP 0x02 + +/** + * Output flag for the source. + * If this flag is set, the log message will contain the source file and line + * number. + * @see UcxLogger.mask + */ +#define UCX_LOGGER_SOURCE 0x04 + +/** + * The UCX Logger object. + */ +typedef struct { + /** The stream this logger writes its messages to.*/ + void *stream; + + /** + * The write function that shall be used. + * For standard file or stdout loggers this might be standard fwrite + * (default). + */ + write_func writer; + + /** + * The date format for timestamp outputs including the delimiter + * (default: <code>"%F %T %z "</code>). + * @see UCX_LOGGER_TIMESTAMP + */ + char *dateformat; + + /** + * The level, this logger operates on. + * If a log command is issued, the message will only be logged, if the log + * level of the message is less or equal than the log level of the logger. + */ + unsigned int level; + + /** + * A configuration mask for automatic output. + * For each flag that is set, the logger automatically outputs some extra + * information like the timestamp or the source file and line number. + * See the documentation for the flags for details. + */ + unsigned int mask; + + /** + * A map of valid log levels for this logger. + * + * The keys represent all valid log levels and the values provide string + * representations, that are used, if the UCX_LOGGER_LEVEL flag is set. + * + * The exact data types are <code>unsigned int</code> for the key and + * <code>const char*</code> for the value. + * + * @see UCX_LOGGER_LEVEL + */ + UcxMap* levels; +} UcxLogger; + +/** + * Creates a new logger. + * @param stream the stream, which the logger shall write to + * @param level the level on which the logger shall operate + * @param mask configuration mask (cf. UcxLogger.mask) + * @return a new logger object + */ +UcxLogger *ucx_logger_new(void *stream, unsigned int level, unsigned int mask); + +/** + * Destroys the logger. + * + * The map containing the valid log levels is also automatically destroyed. + * + * @param logger the logger to destroy + */ +void ucx_logger_free(UcxLogger* logger); + +/** + * Internal log function - use macros instead. + * + * This function uses the <code>format</code> and variadic arguments for a + * printf()-style output of the log message. + * + * Dependent on the UcxLogger.mask some information is prepended. The complete + * format is: + * + * <code>[LEVEL] [TIMESTAMP] [SOURCEFILE]:[LINENO] message</code> + * + * <b>Attention:</b> the message (including automatically generated information) + * is limited to 4096 characters. The level description is limited to + * 256 characters and the timestamp string is limited to 128 characters. + * + * @param logger the logger to use + * @param level the level to log on + * @param file information about the source file + * @param line information about the source line number + * @param format format string + * @param ... arguments + * @see ucx_logger_log() + */ +void ucx_logger_logf(UcxLogger *logger, unsigned int level, const char* file, + const unsigned int line, const char* format, ...); + +/** + * Logs a message at the specified level. + * @param logger the logger to use + * @param level the level to log the message on + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_log(logger, level, ...) \ + ucx_logger_logf(logger, level, __FILE__, __LINE__, __VA_ARGS__) + +/** + * Shortcut for logging an error message. + * @param logger the logger to use + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_error(logger, ...) \ + ucx_logger_log(logger, UCX_LOGGER_ERROR, __VA_ARGS__) + +/** + * Shortcut for logging an information message. + * @param logger the logger to use + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_info(logger, ...) \ + ucx_logger_log(logger, UCX_LOGGER_INFO, __VA_ARGS__) + +/** + * Shortcut for logging a warning message. + * @param logger the logger to use + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_warn(logger, ...) \ + ucx_logger_log(logger, UCX_LOGGER_WARN, __VA_ARGS__) + +/** + * Shortcut for logging a debug message. + * @param logger the logger to use + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_debug(logger, ...) \ + ucx_logger_log(logger, UCX_LOGGER_DEBUG, __VA_ARGS__) + +/** + * Shortcut for logging a trace message. + * @param logger the logger to use + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_trace(logger, ...) \ + ucx_logger_log(logger, UCX_LOGGER_TRACE, __VA_ARGS__) + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_LOGGING_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/map.h Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,423 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file map.h + * + * Hash map implementation. + * + * This implementation uses murmur hash 2 and separate chaining with linked + * lists. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_MAP_H +#define UCX_MAP_H + +#include <ucx/ucx.h> +#include <ucx/string.h> +#include <ucx/allocator.h> +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Loop statement for UCX maps. + * + * The <code>key</code> variable is implicitly defined, but the + * <code>value</code> variable must be already declared as type information + * cannot be inferred. + * + * @param key the variable name for the key + * @param value the variable name for the value + * @param iter a UcxMapIterator + * @see ucx_map_iterator() + */ +#define UCX_MAP_FOREACH(key,value,iter) \ + for(UcxKey key;ucx_map_iter_next(&iter,&key, (void**)&value);) + +/** Type for the UCX map. @see UcxMap */ +typedef struct UcxMap UcxMap; + +/** Type for a key of a UcxMap. @see UcxKey */ +typedef struct UcxKey UcxKey; + +/** Type for an element of a UcxMap. @see UcxMapElement */ +typedef struct UcxMapElement UcxMapElement; + +/** Type for an iterator over a UcxMap. @see UcxMapIterator */ +typedef struct UcxMapIterator UcxMapIterator; + +/** Structure for the UCX map. */ +struct UcxMap { + /** An allocator that is used for the map elements. */ + UcxAllocator *allocator; + /** The array of map element lists. */ + UcxMapElement **map; + /** The size of the map is the length of the element list array. */ + size_t size; + /** The count of elements currently stored in this map. */ + size_t count; +}; + +/** Structure for a key of a UcxMap. */ +struct UcxKey { + /** The key data. */ + void *data; + /** The length of the key data. */ + size_t len; + /** The hash value of the key data. */ + int hash; +}; + +/** Structure for an element of a UcxMap. */ +struct UcxMapElement { + /** The value data. */ + void *data; + + /** A pointer to the next element in the current list. */ + UcxMapElement *next; + + /** The corresponding key. */ + UcxKey key; +}; + +/** Structure for an iterator over a UcxMap. */ +struct UcxMapIterator { + /** The map to iterate over. */ + UcxMap *map; + + /** The current map element. */ + UcxMapElement *cur; + + /** + * The current index of the element list array. + * <b>Attention: </b> this is <b>NOT</b> the element index! Do <b>NOT</b> + * manually iterate over the map by increasing this index. Use + * ucx_map_iter_next(). + * @see UcxMap.map*/ + size_t index; +}; + +/** + * Creates a new hash map with the specified size. + * @param size the size of the hash map + * @return a pointer to the new hash map + */ +UcxMap *ucx_map_new(size_t size); + +/** + * Creates a new hash map with the specified size using a UcxAllocator. + * @param allocator the allocator to use + * @param size the size of the hash map + * @return a pointer to the new hash map + */ +UcxMap *ucx_map_new_a(UcxAllocator *allocator, size_t size); + +/** + * Frees a hash map. + * + * <b>Note:</b> the contents are <b>not</b> freed, use ucx_map_free_content() + * before calling this function to achieve that. + * + * @param map the map to be freed + * @see ucx_map_free_content() + */ +void ucx_map_free(UcxMap *map); + +/** + * Frees the contents of a hash map. + * + * This is a convenience function that iterates over the map and passes all + * values to the specified destructor function (e.g. stdlib free()). + * + * You must ensure, that it is valid to pass each value in the map to the same + * destructor function. + * + * You should free or clear the map afterwards, as the contents will be invalid. + * + * @param map for which the contents shall be freed + * @param destr pointer to the destructor function + * @see ucx_map_free() + * @see ucx_map_clear() + */ +void ucx_map_free_content(UcxMap *map, ucx_destructor destr); + +/** + * Clears a hash map. + * + * <b>Note:</b> the contents are <b>not</b> freed, use ucx_map_free_content() + * before calling this function to achieve that. + * + * @param map the map to be cleared + * @see ucx_map_free_content() + */ +void ucx_map_clear(UcxMap *map); + + +/** + * Copies contents from a map to another map using a copy function. + * + * <b>Note:</b> The destination map does not need to be empty. However, if it + * contains data with keys that are also present in the source map, the contents + * are overwritten. + * + * @param from the source map + * @param to the destination map + * @param fnc the copy function or <code>NULL</code> if the pointer address + * shall be copied + * @param data additional data for the copy function + * @return 0 on success or a non-zero value on memory allocation errors + */ +int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to, + copy_func fnc, void *data); + +/** + * Clones the map and rehashes if necessary. + * + * <b>Note:</b> In contrast to ucx_map_rehash() the load factor is irrelevant. + * This function <i>always</i> ensures a new UcxMap.size of at least + * 2.5*UcxMap.count. + * + * @param map the map to clone + * @param fnc the copy function to use or <code>NULL</code> if the new and + * the old map shall share the data pointers + * @param data additional data for the copy function + * @return the cloned map + * @see ucx_map_copy() + */ +UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data); + +/** + * Increases size of the hash map, if necessary. + * + * The load value is 0.75*UcxMap.size. If the element count exceeds the load + * value, the map needs to be rehashed. Otherwise no action is performed and + * this function simply returns 0. + * + * The rehashing process ensures, that the UcxMap.size is at least + * 2.5*UcxMap.count. So there is enough room for additional elements without + * the need of another soon rehashing. + * + * You can use this function to dramatically increase access performance. + * + * @param map the map to rehash + * @return 1, if a memory allocation error occurred, 0 otherwise + */ +int ucx_map_rehash(UcxMap *map); + +/** + * Puts a key/value-pair into the map. + * + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + */ +int ucx_map_put(UcxMap *map, UcxKey key, void *value); + +/** + * Retrieves a value by using a key. + * + * @param map the map + * @param key the key + * @return the value + */ +void* ucx_map_get(UcxMap *map, UcxKey key); + +/** + * Removes a key/value-pair from the map by using the key. + * + * @param map the map + * @param key the key + * @return the removed value + */ +void* ucx_map_remove(UcxMap *map, UcxKey key); + +/** + * Shorthand for putting data with a sstr_t key into the map. + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + * @see ucx_map_put() + */ +#define ucx_map_sstr_put(map, key, value) \ + ucx_map_put(map, ucx_key(key.ptr, key.length), (void*)value) + +/** + * Shorthand for putting data with a C string key into the map. + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + * @see ucx_map_put() + */ +#define ucx_map_cstr_put(map, key, value) \ + ucx_map_put(map, ucx_key((void*)key, strlen(key)), (void*)value) + +/** + * Shorthand for putting data with an integer key into the map. + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + * @see ucx_map_put() + */ +#define ucx_map_int_put(map, key, value) \ + ucx_map_put(map, ucx_key((void*)&key, sizeof(key)), (void*)value) + +/** + * Shorthand for getting data from the map with a sstr_t key. + * @param map the map + * @param key the key + * @return the value + * @see ucx_map_get() + */ +#define ucx_map_sstr_get(map, key) \ + ucx_map_get(map, ucx_key(key.ptr, key.length)) + +/** + * Shorthand for getting data from the map with a C string key. + * @param map the map + * @param key the key + * @return the value + * @see ucx_map_get() + */ +#define ucx_map_cstr_get(map, key) \ + ucx_map_get(map, ucx_key((void*)key, strlen(key))) + +/** + * Shorthand for getting data from the map with an integer key. + * @param map the map + * @param key the key + * @return the value + * @see ucx_map_get() + */ +#define ucx_map_int_get(map, key) \ + ucx_map_get(map, ucx_key((void*)&key, sizeof(int))) + +/** + * Shorthand for removing data from the map with a sstr_t key. + * @param map the map + * @param key the key + * @return the removed value + * @see ucx_map_remove() + */ +#define ucx_map_sstr_remove(map, key) \ + ucx_map_remove(map, ucx_key(key.ptr, key.length)) + +/** + * Shorthand for removing data from the map with a C string key. + * @param map the map + * @param key the key + * @return the removed value + * @see ucx_map_remove() + */ +#define ucx_map_cstr_remove(map, key) \ + ucx_map_remove(map, ucx_key((void*)key, strlen(key))) + +/** + * Shorthand for removing data from the map with an integer key. + * @param map the map + * @param key the key + * @return the removed value + * @see ucx_map_remove() + */ +#define ucx_map_int_remove(map, key) \ + ucx_map_remove(map, ucx_key((void*)&key, sizeof(key))) + +/** + * Creates a UcxKey based on the given data. + * + * This function implicitly computes the hash. + * + * @param data the data for the key + * @param len the length of the data + * @return a UcxKey with implicitly computed hash + * @see ucx_hash() + */ +UcxKey ucx_key(void *data, size_t len); + +/** + * Computes a murmur hash-2. + * + * @param data the data to hash + * @param len the length of the data + * @return the murmur hash-2 of the data + */ +int ucx_hash(const char *data, size_t len); + +/** + * Creates an iterator for a map. + * + * <b>Note:</b> A UcxMapIterator iterates over all elements in all element + * lists successively. Therefore the order highly depends on the key hashes and + * may vary under different map sizes. So generally you may <b>NOT</b> rely on + * the iteration order. + * + * <b>Note:</b> The iterator is <b>NOT</b> initialized. You need to call + * ucx_map_iter_next() at least once before accessing any information. However, + * it is not recommended to access the fields of a UcxMapIterator directly. + * + * @param map the map to create the iterator for + * @return an iterator initialized on the first element of the + * first element list + * @see ucx_map_iter_next() + */ +UcxMapIterator ucx_map_iterator(UcxMap *map); + +/** + * Proceeds to the next element of the map (if any). + * + * Subsequent calls on the same iterator proceed to the next element and + * store the key/value-pair into the memory specified as arguments of this + * function. + * + * If no further elements are found, this function returns zero and leaves the + * last found key/value-pair in memory. + * + * @param iterator the iterator to use + * @param key a pointer to the memory where to store the key + * @param value a pointer to the memory where to store the value + * @return 1, if another element was found, 0 if all elements has been processed + * @see ucx_map_iterator() + */ +int ucx_map_iter_next(UcxMapIterator *iterator, UcxKey *key, void **value); + + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_MAP_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/mempool.h Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,200 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file mempool.h + * + * Memory pool implementation. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_MEMPOOL_H +#define UCX_MEMPOOL_H + +#include <ucx/ucx.h> +#include <ucx/allocator.h> +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * UCX mempool structure. + */ +typedef struct { + /** UcxAllocator based on this pool */ + UcxAllocator *allocator; + + /** List of pointers to pooled memory. */ + void **data; + + /** Count of pooled memory items. */ + size_t ndata; + + /** Memory pool size. */ + size_t size; +} UcxMempool; + +/** Shorthand for a new default memory pool with a capacity of 16 elements. */ +#define ucx_mempool_new_default() ucx_mempool_new(16) + + +/** + * Creates a memory pool with the specified initial size. + * + * As the created memory pool automatically grows in size by factor two when + * trying to allocate memory on a full pool, it is recommended that you use + * a power of two for the initial size. + * + * @param n initial pool size (should be a power of two, e.g. 16) + * @return a pointer to the new memory pool + * @see ucx_mempool_new_default() + */ +UcxMempool *ucx_mempool_new(size_t n); + +/** + * Resizes a memory pool. + * + * This function will fail if the new capacity is not sufficient for the + * present data. + * + * @param pool the pool to resize + * @param newcap the new capacity + * @return zero on success or non-zero on failure + */ +int ucx_mempool_chcap(UcxMempool *pool, size_t newcap); + +/** + * Allocates pooled memory. + * + * @param pool the memory pool + * @param n amount of memory to allocate + * @return a pointer to the allocated memory + * @see ucx_allocator_malloc() + */ +void *ucx_mempool_malloc(UcxMempool *pool, size_t n); +/** + * Allocates a pooled memory array. + * + * The content of the allocated memory is set to zero. + * + * @param pool the memory pool + * @param nelem amount of elements to allocate + * @param elsize amount of memory per element + * @return a pointer to the allocated memory + * @see ucx_allocator_calloc() + */ +void *ucx_mempool_calloc(UcxMempool *pool, size_t nelem, size_t elsize); + +/** + * Reallocates pooled memory. + * + * If the memory to be reallocated is not contained by the specified pool, the + * behavior is undefined. + * + * @param pool the memory pool + * @param ptr a pointer to the memory that shall be reallocated + * @param n the new size of the memory + * @return a pointer to the new location of the memory + * @see ucx_allocator_realloc() + */ +void *ucx_mempool_realloc(UcxMempool *pool, void *ptr, size_t n); + +/** + * Frees pooled memory. + * + * Before freeing the memory, the specified destructor function (if any) + * is called. + * + * If you specify memory, that is not pooled by the specified memory pool, the + * program will terminate with a call to <code>abort()</code>. + * + * @param pool the memory pool + * @param ptr a pointer to the memory that shall be freed + * @see ucx_mempool_set_destr() + */ +void ucx_mempool_free(UcxMempool *pool, void *ptr); + +/** + * Destroys a memory pool. + * + * For each element the destructor function (if any) is called and the element + * is freed. + * + * Each of the registered destructor function that has no corresponding element + * within the pool (namely those registered by ucx_mempool_reg_destr) is + * called interleaving with the element destruction, but with guarantee to the + * order in which they were registered (FIFO order). + * + * + * @param pool the mempool to destroy + */ +void ucx_mempool_destroy(UcxMempool *pool); + +/** + * Sets a destructor function for the specified memory. + * + * The destructor is automatically called when the memory is freed or the + * pool is destroyed. + * + * The only requirement for the specified memory is, that it <b>MUST</b> be + * pooled memory by a UcxMempool or an element-compatible mempool. The pointer + * to the destructor function is saved in a reserved area before the actual + * memory. + * + * @param ptr pooled memory + * @param func a pointer to the destructor function + * @see ucx_mempool_free() + * @see ucx_mempool_destroy() + */ +void ucx_mempool_set_destr(void *ptr, ucx_destructor func); + +/** + * Registers a destructor function for the specified (non-pooled) memory. + * + * This is useful, if you have memory that has not been allocated by a mempool, + * but shall be managed by a mempool. + * + * This function creates an entry in the specified mempool and the memory will + * therefore (logically) convert to pooled memory. + * + * @param pool the memory pool + * @param ptr data the destructor is registered for + * @param destr a pointer to the destructor function + */ +void ucx_mempool_reg_destr(UcxMempool *pool, void *ptr, ucx_destructor destr); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_MEMPOOL_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/properties.h Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,218 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/** + * @file properties.h + * + * Load / store utilities for properties files. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_PROPERTIES_H +#define UCX_PROPERTIES_H + +#include <ucx/ucx.h> +#include <ucx/map.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * UcxProperties object for parsing properties data. + * Most of the fields are for internal use only. You may configure the + * properties parser, e.g. by changing the used delimiter or specifying + * up to three different characters that shall introduce comments. + */ +typedef struct { + /** + * Input buffer (don't set manually). + * Automatically set by calls to ucx_properties_fill(). + */ + char *buffer; + + /** + * Length of the input buffer (don't set manually). + * Automatically set by calls to ucx_properties_fill(). + */ + size_t buflen; + + /** + * Current buffer position (don't set manually). + * Used by ucx_properties_next(). + */ + size_t pos; + + /** + * Internal temporary buffer (don't set manually). + * Used by ucx_properties_next(). + */ + char *tmp; + + /** + * Internal temporary buffer length (don't set manually). + * Used by ucx_properties_next(). + */ + size_t tmplen; + + /** + * Internal temporary buffer capacity (don't set manually). + * Used by ucx_properties_next(). + */ + size_t tmpcap; + + /** + * Parser error code. + * This is always 0 on success and a nonzero value on syntax errors. + * The value is set by ucx_properties_next(). + */ + int error; + + /** + * The delimiter that shall be used. + * This is '=' by default. + */ + char delimiter; + + /** + * The first comment character. + * This is '#' by default. + */ + char comment1; + + /** + * The second comment character. + * This is not set by default. + */ + char comment2; + + /** + * The third comment character. + * This is not set by default. + */ + char comment3; +} UcxProperties; + + +/** + * Constructs a new UcxProperties object. + * @return a pointer to the new UcxProperties object + */ +UcxProperties *ucx_properties_new(); + +/** + * Destroys a UcxProperties object. + * @param prop the UcxProperties object to destroy + */ +void ucx_properties_free(UcxProperties *prop); + +/** + * Sets the input buffer for the properties parser. + * + * After calling this function, you may parse the data by calling + * ucx_properties_next() until it returns 0. The function ucx_properties2map() + * is a convenience function that reads as much data as possible by using this + * function. + * + * + * @param prop the UcxProperties object + * @param buf a pointer to the new buffer + * @param len the payload length of the buffer + * @see ucx_properties_next() + * @see ucx_properties2map() + */ +void ucx_properties_fill(UcxProperties *prop, char *buf, size_t len); + +/** + * Retrieves the next key/value-pair. + * + * This function returns a nonzero value as long as there are key/value-pairs + * found. If no more key/value-pairs are found, you may refill the input buffer + * with ucx_properties_fill(). + * + * <b>Attention:</b> the sstr_t.ptr pointers of the output parameters point to + * memory within the input buffer of the parser and will get invalid some time. + * If you want long term copies of the key/value-pairs, use sstrdup() after + * calling this function. + * + * @param prop the UcxProperties object + * @param name a pointer to the sstr_t that shall contain the property name + * @param value a pointer to the sstr_t that shall contain the property value + * @return Nonzero, if a key/value-pair was successfully retrieved + * @see ucx_properties_fill() + */ +int ucx_properties_next(UcxProperties *prop, sstr_t *name, sstr_t *value); + +/** + * Retrieves all available key/value-pairs and puts them into a UcxMap. + * + * This is done by successive calls to ucx_properties_next() until no more + * key/value-pairs can be retrieved. + * + * @param prop the UcxProperties object + * @param map the target map + * @return The UcxProperties.error code (i.e. 0 on success). + * @see ucx_properties_fill() + */ +int ucx_properties2map(UcxProperties *prop, UcxMap *map); + +/** + * Loads a properties file to a UcxMap. + * + * This is a convenience function that reads data from an input + * stream until the end of the stream is reached. + * + * @param map the map object to write the key/value-pairs to + * @param file the <code>FILE*</code> stream to read from + * @return 0 on success, or a non-zero value on error + * + * @see ucx_properties_fill() + * @see ucx_properties2map() + */ +int ucx_properties_load(UcxMap *map, FILE *file); + +/** + * Stores a UcxMap to a file. + * + * The key/value-pairs are written by using the following format: + * + * <code>[key] = [value]\\n</code> + * + * @param map the map to store + * @param file the <code>FILE*</code> stream to write to + * @return 0 on success, or a non-zero value on error + */ +int ucx_properties_store(UcxMap *map, FILE *file); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_PROPERTIES_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/stack.h Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,232 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file stack.h + * + * Default stack memory allocation implementation. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_STACK_H +#define UCX_STACK_H + +#include <ucx/ucx.h> +#include <ucx/allocator.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * UCX stack structure. + */ +typedef struct { + /** UcxAllocator based on this stack */ + UcxAllocator allocator; + + /** Stack size. */ + size_t size; + + /** Pointer to the bottom of the stack */ + char *space; + + /** Pointer to the top of the stack */ + char *top; +} UcxStack; + +/** + * Metadata for each UCX stack element. + */ +struct ucx_stack_metadata { + /** + * Location of the previous element (<code>NULL</code> if this is the first) + */ + char *prev; + + /** Size of this element */ + size_t size; +}; + +/** + * Initializes UcxStack structure with memory. + * + * @param stack a pointer to an uninitialized stack structure + * @param space the memory area that shall be managed + * @param size size of the memory area + * @return a new UcxStack structure + */ +void ucx_stack_init(UcxStack *stack, char* space, size_t size); + +/** + * Allocates stack memory. + * + * @param stack a pointer to the stack + * @param n amount of memory to allocate + * @return a pointer to the allocated memory + * @see ucx_allocator_malloc() + */ +void *ucx_stack_malloc(UcxStack *stack, size_t n); + +/** + * Alias for #ucx_stack_malloc(). + * @param stack a pointer to the stack + * @param n amount of memory to allocate + * @return a pointer to the allocated memory + * @see ucx_stack_malloc + */ +#define ucx_stack_push(stack, n) ucx_stack_malloc(stack, n) + +/** + * Allocates an array of stack memory + * + * The content of the allocated memory is set to zero. + * + * @param stack a pointer to the stack + * @param nelem amount of elements to allocate + * @param elsize amount of memory per element + * @return a pointer to the allocated memory + * @see ucx_allocator_calloc() + */ +void *ucx_stack_calloc(UcxStack *stack, size_t nelem, size_t elsize); + +/** + * Alias for #ucx_stack_calloc(). + * + * @param stack a pointer to the stack + * @param n amount of elements to allocate + * @param elsize amount of memory per element + * @return a pointer to the allocated memory + * @see ucx_stack_calloc + */ +#define ucx_stack_pusharr(stack,n,elsize) ucx_stack_calloc(stack,n,elssize) + +/** + * Reallocates memory on the stack. + * + * Shrinking memory is always safe. Extending memory can be very expensive. + * + * @param stack the stack + * @param ptr a pointer to the memory that shall be reallocated + * @param n the new size of the memory + * @return a pointer to the new location of the memory + * @see ucx_allocator_realloc() + */ +void *ucx_stack_realloc(UcxStack *stack, void *ptr, size_t n); + +/** + * Frees memory on the stack. + * + * Freeing stack memory behaves in a special way. + * + * If the element, that should be freed, is the top most element of the stack, + * it is removed from the stack. Otherwise it is marked as freed. Marked + * elements are removed, when they become the top most elements of the stack. + * + * @param stack a pointer to the stack + * @param ptr a pointer to the memory that shall be freed + */ +void ucx_stack_free(UcxStack *stack, void *ptr); + + +/** + * Returns the size of the top most element. + * @param stack a pointer to the stack + * @return the size of the top most element + */ +#define ucx_stack_topsize(stack) ((stack)->top ? ((struct ucx_stack_metadata*)\ + (stack)->top - 1)->size : 0) + +/** + * Removes the top most element from the stack and copies the content to <code> + * dest</code>, if specified. + * + * Use #ucx_stack_topsize()# to get the amount of memory that must be available + * at the location of <code>dest</code>. + * + * @param stack a pointer to the stack + * @param dest the location where the contents shall be written to, or <code> + * NULL</code>, if the element shall only be removed. + * @see ucx_stack_free + * @see ucx_stack_popn + */ +#define ucx_stack_pop(stack, dest) ucx_stack_popn(stack, dest, (size_t)-1) + +/** + * Removes the top most element from the stack and copies the content to <code> + * dest</code>. + * + * In contrast to #ucx_stack_pop() the <code>dest</code> pointer <code>MUST + * NOT</code> be <code>NULL</code>. + * + * @param stack a pointer to the stack + * @param dest the location where the contents shall be written to + * @param n copies at most n elements to <code>dest</code> + * @see ucx_stack_pop + */ +void ucx_stack_popn(UcxStack *stack, void *dest, size_t n); + +/** + * Returns the remaining available memory on the specified stack. + * + * @param stack a pointer to the stack + * @return the remaining available memory + */ +size_t ucx_stack_avail(UcxStack *stack); + +/** + * Checks, if the stack is empty. + * + * @param stack a pointer to the stack + * @return nonzero, if the stack is empty, zero otherwise + */ +#define ucx_stack_empty(stack) (!(stack)->top) + +/** + * Computes a recommended size for the stack memory area. Note, that + * reallocations have not been taken into account, so you might need to reserve + * twice as much memory to allow many reallocations. + * + * @param size the approximate payload + * @param elems the approximate count of element allocations + * @return a recommended size for the stack space based on the information + * provided + */ +#define ucx_stack_dim(size, elems) (size+sizeof(struct ucx_stack_metadata) * \ + (elems + 1)) + + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_STACK_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/string.h Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,460 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/** + * Bounded string implementation. + * + * The UCX strings (<code>sstr_t</code>) provide an alternative to C strings. + * The main difference to C strings is, that <code>sstr_t</code> does <b>not + * need to be <code>NULL</code>-terminated</b>. Instead the length is stored + * within the structure. + * + * When using <code>sstr_t</code>, developers must be full aware of what type + * of string (<code>NULL</code>-terminated) or not) they are using, when + * accessing the <code>char* ptr</code> directly. + * + * The UCX string module provides some common string functions, known from + * standard libc, working with <code>sstr_t</code>. + * + * @file string.h + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_STRING_H +#define UCX_STRING_H + +#include <ucx/ucx.h> +#include <ucx/allocator.h> +#include <stddef.h> + +/** Shortcut for a <code>sstr_t struct</code> literal. */ +#define ST(s) { (char*)s, sizeof(s)-1 } + +/** Shortcut for the conversion of a C string to a <code>sstr_t</code>. */ +#define S(s) sstrn((char*)s, sizeof(s)-1) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The UCX string structure. + */ +typedef struct { + /** A reference to the string (<b>not necessarily <code>NULL</code> + * -terminated</b>) */ + char *ptr; + /** The length of the string */ + size_t length; +} sstr_t; + +/** + * Creates a new sstr_t based on a C string. + * + * The length is implicitly inferred by using a call to <code>strlen()</code>. + * + * <b>Note:</b> the sstr_t will hold a <i>reference</i> to the C string. If you + * do want a copy, use sstrdup() on the return value of this function. + * + * @param cstring the C string to wrap + * @return a new sstr_t containing the C string + * + * @see sstrn() + */ +sstr_t sstr(char *cstring); + +/** + * Creates a new sstr_t of the specified length based on a C string. + * + * <b>Note:</b> the sstr_t will hold a <i>reference</i> to the C string. If you + * do want a copy, use sstrdup() on the return value of this function. + * + * @param cstring the C string to wrap + * @param length the length of the string + * @return a new sstr_t containing the C string + * + * @see sstr() + * @see S() + */ +sstr_t sstrn(char *cstring, size_t length); + + +/** + * Returns the cumulated length of all specified strings. + * + * At least one string must be specified. + * + * <b>Attention:</b> if the count argument does not match the count of the + * specified strings, the behavior is undefined. + * + * @param count the total number of specified strings (so at least 1) + * @param string the first string + * @param ... all other strings + * @return the cumulated length of all strings + */ +size_t sstrnlen(size_t count, sstr_t string, ...); + +/** + * Concatenates two or more strings. + * + * The resulting string will be allocated by standard <code>malloc()</code>. + * So developers <b>MUST</b> pass the sstr_t.ptr to <code>free()</code>. + * + * The sstr_t.ptr of the return value will <i>always</i> be <code>NULL</code>- + * terminated. + * + * @param count the total number of strings to concatenate + * @param s1 first string + * @param s2 second string + * @param ... all remaining strings + * @return the concatenated string + */ +sstr_t sstrcat(size_t count, sstr_t s1, sstr_t s2, ...); + +/** + * Concatenates two or more strings using a UcxAllocator. + * + * See sstrcat() for details. + * + * @param a the allocator to use + * @param count the total number of strings to concatenate + * @param s1 first string + * @param s2 second string + * @param ... all remaining strings + * @return the concatenated string + */ +sstr_t sstrcat_a(UcxAllocator *a, size_t count, sstr_t s1, sstr_t s2, ...); + + +/** + * Returns a substring starting at the specified location. + * + * <b>Attention:</b> the new string references the same memory area as the + * input string and will <b>NOT</b> be <code>NULL</code>-terminated. + * Use sstrdup() to get a copy. + * + * @param string input string + * @param start start location of the substring + * @return a substring of <code>string</code> starting at <code>start</code> + * + * @see sstrsubsl() + * @see sstrchr() + */ +sstr_t sstrsubs(sstr_t string, size_t start); + +/** + * Returns a substring with a maximum length starting at the specified location. + * + * <b>Attention:</b> the new string references the same memory area as the + * input string and will <b>NOT</b> be <code>NULL</code>-terminated. + * Use sstrdup() to get a copy. + * + * @param string input string + * @param start start location of the substring + * @param length the maximum length of the substring + * @return a substring of <code>string</code> starting at <code>start</code> + * with a maximum length of <code>length</code> + * + * @see sstrsubs() + * @see sstrchr() + */ +sstr_t sstrsubsl(sstr_t string, size_t start, size_t length); + +/** + * Returns a substring starting at the location of the first occurrence of the + * specified character. + * + * If the string does not contain the character, an empty string is returned. + * + * @param string the string where to locate the character + * @param chr the character to locate + * @return a substring starting at the first location of <code>chr</code> + * + * @see sstrsubs() + */ +sstr_t sstrchr(sstr_t string, int chr); + +/** + * Returns a substring starting at the location of the last occurrence of the + * specified character. + * + * If the string does not contain the character, an empty string is returned. + * + * @param string the string where to locate the character + * @param chr the character to locate + * @return a substring starting at the last location of <code>chr</code> + * + * @see sstrsubs() + */ +sstr_t sstrrchr(sstr_t string, int chr); + +/** + * Returns a substring starting at the location of the first occurrence of the + * specified string. + * + * If the string does not contain the other string, an empty string is returned. + * + * If <code>match</code> is an empty string, the complete <code>string</code> is + * returned. + * + * @param string the string to be scanned + * @param match string containing the sequence of characters to match + * @return a substring starting at the first occurrence of + * <code>match</code>, or an empty string, if the sequence is not + * present in <code>string</code> + */ +sstr_t sstrstr(sstr_t string, sstr_t match); + +/** + * Splits a string into parts by using a delimiter string. + * + * This function will return <code>NULL</code>, if one of the following happens: + * <ul> + * <li>the string length is zero</li> + * <li>the delimeter length is zero</li> + * <li>the string equals the delimeter</li> + * <li>memory allocation fails</li> + * </ul> + * + * The integer referenced by <code>count</code> is used as input and determines + * the maximum size of the resulting array, i.e. the maximum count of splits to + * perform + 1. + * + * The integer referenced by <code>count</code> is also used as output and is + * set to + * <ul> + * <li>-2, on memory allocation errors</li> + * <li>-1, if either the string or the delimiter is an empty string</li> + * <li>0, if the string equals the delimiter</li> + * <li>1, if the string does not contain the delimiter</li> + * <li>the count of array items, otherwise</li> + * </ul> + * + * If the string starts with the delimiter, the first item of the resulting + * array will be an empty string. + * + * If the string ends with the delimiter and the maximum list size is not + * exceeded, the last array item will be an empty string. + * In case the list size would be exceeded, the last array item will be the + * remaining string after the last split, <i>including</i> the terminating + * delimiter. + * + * <b>Attention:</b> The array pointer <b>AND</b> all sstr_t.ptr of the array + * items must be manually passed to <code>free()</code>. Use sstrsplit_a() with + * an allocator to managed memory, to avoid this. + * + * @param string the string to split + * @param delim the delimiter string + * @param count IN: the maximum size of the resulting array (0 = no limit), + * OUT: the actual size of the array + * @return a sstr_t array containing the split strings or + * <code>NULL</code> on error + * + * @see sstrsplit_a() + */ +sstr_t* sstrsplit(sstr_t string, sstr_t delim, ssize_t *count); + +/** + * Performing sstrsplit() using a UcxAllocator. + * + * <i>Read the description of sstrsplit() for details.</i> + * + * The memory for the sstr_t.ptr pointers of the array items and the memory for + * the sstr_t array itself are allocated by using the UcxAllocator.malloc() + * function. + * + * <b>Note:</b> the allocator is not used for memory that is freed within the + * same call of this function (locally scoped variables). + * + * @param allocator the UcxAllocator used for allocating memory + * @param string the string to split + * @param delim the delimiter string + * @param count IN: the maximum size of the resulting array (0 = no limit), + * OUT: the actual size of the array + * @return a sstr_t array containing the split strings or + * <code>NULL</code> on error + * + * @see sstrsplit() + */ +sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t string, sstr_t delim, + ssize_t *count); + +/** + * Compares two UCX strings with standard <code>memcmp()</code>. + * + * At first it compares the sstr_t.length attribute of the two strings. The + * <code>memcmp()</code> function is called, if and only if the lengths match. + * + * @param s1 the first string + * @param s2 the second string + * @return -1, if the length of s1 is less than the length of s2 or 1, if the + * length of s1 is greater than the length of s2 or the result of + * <code>memcmp()</code> otherwise (i.e. 0 if the strings match) + */ +int sstrcmp(sstr_t s1, sstr_t s2); + +/** + * Compares two UCX strings ignoring the case. + * + * At first it compares the sstr_t.length attribute of the two strings. If and + * only if the lengths match, both strings are compared char by char ignoring + * the case. + * + * @param s1 the first string + * @param s2 the second string + * @return -1, if the length of s1 is less than the length of s2 or 1, if the + * length of s1 is greater than the length of s2 or the difference between the + * first two differing characters otherwise (i.e. 0 if the strings match and + * no characters differ) + */ +int sstrcasecmp(sstr_t s1, sstr_t s2); + +/** + * Creates a duplicate of the specified string. + * + * The new sstr_t will contain a copy allocated by standard + * <code>malloc()</code>. So developers <b>MUST</b> pass the sstr_t.ptr to + * <code>free()</code>. + * + * The sstr_t.ptr of the return value will <i>always</i> be <code>NULL</code>- + * terminated. + * + * @param string the string to duplicate + * @return a duplicate of the string + * @see sstrdup_a() + */ +sstr_t sstrdup(sstr_t string); + +/** + * Creates a duplicate of the specified string using a UcxAllocator. + * + * The new sstr_t will contain a copy allocated by the allocators + * ucx_allocator_malloc function. So it is implementation depended, whether the + * returned sstr_t.ptr pointer must be passed to the allocators + * ucx_allocator_free function manually. + * + * The sstr_t.ptr of the return value will <i>always</i> be <code>NULL</code>- + * terminated. + * + * @param allocator a valid instance of a UcxAllocator + * @param string the string to duplicate + * @return a duplicate of the string + * @see sstrdup() + */ +sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t string); + +/** + * Omits leading and trailing spaces. + * + * This function returns a new sstr_t containing a trimmed version of the + * specified string. + * + * <b>Note:</b> the new sstr_t references the same memory, thus you + * <b>MUST NOT</b> pass the sstr_t.ptr of the return value to + * <code>free()</code>. It is also highly recommended to avoid assignments like + * <code>mystr = sstrtrim(mystr);</code> as you lose the reference to the + * source string. Assignments of this type are only permitted, if the + * sstr_t.ptr of the source string does not need to be freed or if another + * reference to the source string exists. + * + * @param string the string that shall be trimmed + * @return a new sstr_t containing the trimmed string + */ +sstr_t sstrtrim(sstr_t string); + +/** + * Checks, if a string has a specific prefix. + * @param string the string to check + * @param prefix the prefix the string should have + * @return 1, if and only if the string has the specified prefix, 0 otherwise + */ +int sstrprefix(sstr_t string, sstr_t prefix); + +/** + * Checks, if a string has a specific suffix. + * @param string the string to check + * @param suffix the suffix the string should have + * @return 1, if and only if the string has the specified suffix, 0 otherwise + */ +int sstrsuffix(sstr_t string, sstr_t suffix); + +/** + * Returns a lower case version of a string. + * + * This function creates a duplicate of the input string, first. See the + * documentation of sstrdup() for the implications. + * + * @param string the input string + * @return the resulting lower case string + * @see sstrdup() + */ +sstr_t sstrlower(sstr_t string); + +/** + * Returns a lower case version of a string. + * + * This function creates a duplicate of the input string, first. See the + * documentation of sstrdup_a() for the implications. + * + * @param allocator the allocator used for duplicating the string + * @param string the input string + * @return the resulting lower case string + * @see sstrdup_a() + */ +sstr_t sstrlower_a(UcxAllocator *allocator, sstr_t string); + +/** + * Returns a upper case version of a string. + * + * This function creates a duplicate of the input string, first. See the + * documentation of sstrdup() for the implications. + * + * @param string the input string + * @return the resulting upper case string + * @see sstrdup() + */ +sstr_t sstrupper(sstr_t string); + +/** + * Returns a upper case version of a string. + * + * This function creates a duplicate of the input string, first. See the + * documentation of sstrdup_a() for the implications. + * + * @param allocator the allocator used for duplicating the string + * @param string the input string + * @return the resulting upper case string + * @see sstrdup_a() + */ +sstr_t sstrupper_a(UcxAllocator *allocator, sstr_t string); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_STRING_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/test.h Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,241 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file: test.h + * + * UCX Test Framework. + * + * Usage of this test framework: + * + * **** IN HEADER FILE: **** + * + * <pre> + * UCX_TEST(function_name) + * UCX_TEST_SUBROUTINE(subroutine_name, paramlist) // optional + * </pre> + * + * **** IN SOURCE FILE: **** + * <pre> + * UCX_TEST_SUBROUTINE(subroutine_name, paramlist) { + * // tests with UCX_TEST_ASSERT() + * } + * + * UCX_TEST(function_name) { + * // memory allocation and other stuff here + * #UCX_TEST_BEGIN + * // tests with UCX_TEST_ASSERT() and/or + * // calls with UCX_TEST_CALL_SUBROUTINE() here + * #UCX_TEST_END + * // cleanup of memory here + * } + * </pre> + * + * <b>Note:</b> if a test fails, a longjump is performed + * back to the #UCX_TEST_BEGIN macro! + * + * <b>Attention:</b> Do not call own functions within a test, that use + * UCX_TEST_ASSERT() macros and are not defined by using UCX_TEST_SUBROUTINE(). + * + * + * @author Mike Becker + * @author Olaf Wintermann + * + */ + +#ifndef UCX_TEST_H +#define UCX_TEST_H + +#include <ucx/ucx.h> +#include <stdio.h> +#include <string.h> +#include <setjmp.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __FUNCTION__ + +/** + * Alias for the <code>__func__</code> preprocessor macro. + * Some compilers use <code>__func__</code> and others use __FUNCTION__. + * We use __FUNCTION__ so we define it for those compilers which use + * <code>__func__</code>. + */ +#define __FUNCTION__ __func__ +#endif + +/** Type for the UcxTestSuite. */ +typedef struct UcxTestSuite UcxTestSuite; + +/** Pointer to a test function. */ +typedef void(*UcxTest)(UcxTestSuite*,FILE*); + +/** Type for the internal list of test cases. */ +typedef struct UcxTestList UcxTestList; + +/** Structure for the internal list of test cases. */ +struct UcxTestList { + + /** Test case. */ + UcxTest test; + + /** Pointer to the next list element. */ + UcxTestList *next; +}; + +/** + * A test suite containing multiple test cases. + */ +struct UcxTestSuite { + + /** The number of successful tests after the suite has been run. */ + unsigned int success; + + /** The number of failed tests after the suite has been run. */ + unsigned int failure; + + /** + * Internal list of test cases. + * Use ucx_test_register() to add tests to this list. + */ + UcxTestList *tests; +}; + +/** + * Creates a new test suite. + * @return a new test suite + */ +UcxTestSuite* ucx_test_suite_new(); + +/** + * Destroys a test suite. + * @param suite the test suite to destroy + */ +void ucx_test_suite_free(UcxTestSuite* suite); + +/** + * Registers a test function with the specified test suite. + * + * @param suite the suite, the test function shall be added to + * @param test the test function to register + * @return <code>EXIT_SUCCESS</code> on success or + * <code>EXIT_FAILURE</code> on failure + */ +int ucx_test_register(UcxTestSuite* suite, UcxTest test); + +/** + * Runs a test suite and writes the test log to the specified stream. + * @param suite the test suite to run + * @param outstream the stream the log shall be written to + */ +void ucx_test_run(UcxTestSuite* suite, FILE* outstream); + +/** + * Macro for a #UcxTest function header. + * + * Use this macro to declare and/or define a #UcxTest function. + * + * @param name the name of the test function + */ +#define UCX_TEST(name) void name(UcxTestSuite* _suite_,FILE *_output_) + +/** + * Marks the begin of a test. + * <b>Note:</b> Any UCX_TEST_ASSERT() calls must be performed <b>after</b> + * #UCX_TEST_BEGIN. + * + * @see #UCX_TEST_END + */ +#define UCX_TEST_BEGIN fwrite("Running ", 1, 8, _output_);\ + fwrite(__FUNCTION__, 1, strlen(__FUNCTION__), _output_);\ + fwrite("... ", 1, 4, _output_);\ + jmp_buf _env_; \ + if (!setjmp(_env_)) { + +/** + * Checks a test assertion. + * If the assertion is correct, the test carries on. If the assertion is not + * correct, the specified message (terminated by a dot and a line break) is + * written to the test suites output stream. + * @param condition the condition to check + * @param message the message that shall be printed out on failure + */ +#define UCX_TEST_ASSERT(condition,message) if (!(condition)) { \ + fwrite(message".\n", 1, 2+strlen(message), _output_); \ + _suite_->failure++; \ + longjmp(_env_, 1);\ + } + +/** + * Macro for a test subroutine function header. + * + * Use this to declare and/or define a subroutine that can be called by using + * UCX_TEST_CALL_SUBROUTINE(). + * + * @param name the name of the subroutine + * @param ... the parameter list + * + * @see UCX_TEST_CALL_SUBROUTINE() + */ +#define UCX_TEST_SUBROUTINE(name,...) void name(UcxTestSuite* _suite_,\ + FILE *_output_, jmp_buf _env_, __VA_ARGS__) + +/** + * Macro for calling a test subroutine. + * + * Subroutines declared with UCX_TEST_SUBROUTINE() can be called by using this + * macro. + * + * <b>Note:</b> You may <b>only</b> call subroutines within a #UCX_TEST_BEGIN- + * #UCX_TEST_END-block. + * + * @param name the name of the subroutine + * @param ... the argument list + * + * @see UCX_TEST_SUBROUTINE() + */ +#define UCX_TEST_CALL_SUBROUTINE(name,...) \ + name(_suite_,_output_,_env_,__VA_ARGS__); + +/** + * Marks the end of a test. + * <b>Note:</b> Any UCX_TEST_ASSERT() calls must be performed <b>before</b> + * #UCX_TEST_END. + * + * @see #UCX_TEST_BEGIN + */ +#define UCX_TEST_END fwrite("success.\n", 1, 9, _output_); _suite_->success++;} + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_TEST_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx.h Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,145 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/** + * Main UCX Header providing most common definitions. + * + * @file ucx.h + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_H +#define UCX_H + +/** Major UCX version as integer constant. */ +#define UCX_VERSION_MAJOR 0 + +/** Minor UCX version as integer constant. */ +#define UCX_VERSION_MINOR 13 + +#include <stdlib.h> +#include <stdint.h> + +#ifdef _WIN32 +#if !(defined __ssize_t_defined || defined _SSIZE_T_) +#include <BaseTsd.h> +typedef SSIZE_T ssize_t; +#define __ssize_t_defined +#define _SSIZE_T_ +#endif /* __ssize_t_defined and _SSIZE_T */ +#else /* !_WIN32 */ +#include <sys/types.h> +#endif /* _WIN32 */ + +#ifdef __cplusplus +#ifndef _Bool +#define _Bool bool +#define restrict +#endif +/** Use C naming even when compiling with C++. */ +#define UCX_EXTERN extern "C" +extern "C" { +#else +/** Pointless in C. */ +#define UCX_EXTERN +#endif + + +/** + * A function pointer to a destructor function. + * @see ucx_mempool_setdestr() + * @see ucx_mempool_regdestr() + */ +typedef void(*ucx_destructor)(void*); + +/** + * Function pointer to a compare function. + * + * The compare function shall take three arguments: the two values that shall be + * compared and optional additional data. + * The function shall then return -1 if the first argument is less than the + * second argument, 1 if the first argument is greater than the second argument + * and 0 if both arguments are equal. If the third argument is + * <code>NULL</code>, it shall be ignored. + */ +typedef int(*cmp_func)(const void*,const void*,void*); + +/** + * Function pointer to a distance function. + * + * The distance function shall take three arguments: the two values for which + * the distance shall be computed and optional additional data. + * The function shall then return the signed distance as integer value. + */ +typedef intmax_t(*distance_func)(const void*,const void*,void*); + +/** + * Function pointer to a copy function. + * + * The copy function shall create a copy of the first argument and may use + * additional data provided by the second argument. If the second argument is + * <code>NULL</code>, it shall be ignored. + + * <b>Attention:</b> if pointers returned by functions of this type may be + * passed to <code>free()</code> depends on the implementation of the + * respective <code>copy_func</code>. + */ +typedef void*(*copy_func)(const void*,void*); + +/** + * Function pointer to a write function. + * + * The signature of the write function shall be compatible to the signature + * of standard <code>fwrite</code>, though it may use arbitrary data types for + * source and destination. + * + * The arguments shall contain (in ascending order): a pointer to the source, + * the length of one element, the element count and a pointer to the + * destination. + */ +typedef size_t(*write_func)(const void*, size_t, size_t, void*); + +/** + * Function pointer to a read function. + * + * The signature of the read function shall be compatible to the signature + * of standard <code>fread</code>, though it may use arbitrary data types for + * source and destination. + * + * The arguments shall contain (in ascending order): a pointer to the + * destination, the length of one element, the element count and a pointer to + * the source. + */ +typedef size_t(*read_func)(void*, size_t, size_t, void*); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/utils.h Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,281 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file utils.h + * + * Compare, copy and printf functions. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_UTILS_H +#define UCX_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <ucx/ucx.h> +#include <ucx/string.h> +#include <ucx/allocator.h> +#include <inttypes.h> +#include <string.h> +#include <stdarg.h> + +/** + * Default buffer size for ucx_stream_copy() and ucx_stream_ncopy(). + */ +#define UCX_STREAM_COPY_BUFSIZE 4096 + +/** + * Copies a string. + * @param s the string to copy + * @param data omitted + * @return a pointer to a copy of s1 that can be passed to free(void*) + */ +void *ucx_strcpy(const void *s, void *data); + +/** + * Copies a memory area. + * @param m a pointer to the memory area + * @param n a pointer to the size_t containing the size of the memory area + * @return a pointer to a copy of the specified memory area that can + * be passed to free(void*) + */ +void *ucx_memcpy(const void *m, void *n); + + +/** + * Reads data from a stream and writes it to another stream. + * + * @param src the source stream + * @param dest the destination stream + * @param rfnc the read function + * @param wfnc the write function + * @param buf a pointer to the copy buffer or <code>NULL</code> if a buffer + * shall be implicitly created on the heap + * @param bufsize the size of the copy buffer - if <code>NULL</code> was + * provided for <code>buf</code>, this is the size of the buffer that shall be + * implicitly created + * @param n the maximum number of bytes that shall be copied + * @return the total number of bytes copied + */ +size_t ucx_stream_bncopy(void *src, void *dest, read_func rfnc, write_func wfnc, + char* buf, size_t bufsize, size_t n); + +/** + * Shorthand for an unbounded ucx_stream_bncopy call using a default buffer. + * + * @param src the source stream + * @param dest the destination stream + * @param rfnc the read function + * @param wfnc the write function + * @return total number of bytes copied + * + * @see #UCX_STREAM_COPY_BUFSIZE + */ +#define ucx_stream_copy(src,dest,rfnc,wfnc) ucx_stream_bncopy(\ + src, dest, (read_func)rfnc, (write_func)wfnc, \ + NULL, UCX_STREAM_COPY_BUFSIZE, (size_t)-1) + +/** + * Shorthand for ucx_stream_bncopy using a default copy buffer. + * + * @param src the source stream + * @param dest the destination stream + * @param rfnc the read function + * @param wfnc the write function + * @param n maximum number of bytes that shall be copied + * @return total number of bytes copied + */ +#define ucx_stream_ncopy(src,dest,rfnc,wfnc, n) ucx_stream_bncopy(\ + src, dest, (read_func)rfnc, (write_func)wfnc, \ + NULL, UCX_STREAM_COPY_BUFSIZE, n) + +/** + * Shorthand for an unbounded ucx_stream_bncopy call using the specified buffer. + * + * @param src the source stream + * @param dest the destination stream + * @param rfnc the read function + * @param wfnc the write function + * @param buf a pointer to the copy buffer or <code>NULL</code> if a buffer + * shall be implicitly created on the heap + * @param bufsize the size of the copy buffer - if <code>NULL</code> was + * provided for <code>buf</code>, this is the size of the buffer that shall be + * implicitly created + * @return total number of bytes copied + */ +#define ucx_stream_bcopy(src,dest,rfnc,wfnc, buf, bufsize) ucx_stream_bncopy(\ + src, dest, (read_func)rfnc, (write_func)wfnc, \ + buf, bufsize, (size_t)-1) + +/** + * Wraps the strcmp function. + * @param s1 string one + * @param s2 string two + * @param data omitted + * @return the result of strcmp(s1, s2) + */ +int ucx_strcmp(const void *s1, const void *s2, void *data); + +/** + * Wraps the strncmp function. + * @param s1 string one + * @param s2 string two + * @param n a pointer to the size_t containing the third strncmp parameter + * @return the result of strncmp(s1, s2, *n) + */ +int ucx_strncmp(const void *s1, const void *s2, void *n); + +/** + * Compares two integers of type int. + * @param i1 pointer to integer one + * @param i2 pointer to integer two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_intcmp(const void *i1, const void *i2, void *data); + +/** + * Compares two real numbers of type float. + * @param f1 pointer to float one + * @param f2 pointer to float two + * @param data if provided: a pointer to precision (default: 1e-6f) + * @return -1, if *f1 is less than *f2, 0 if both are equal, + * 1 if *f1 is greater than *f2 + */ + +int ucx_floatcmp(const void *f1, const void *f2, void *data); + +/** + * Compares two real numbers of type double. + * @param d1 pointer to double one + * @param d2 pointer to double two + * @param data if provided: a pointer to precision (default: 1e-14) + * @return -1, if *d1 is less than *d2, 0 if both are equal, + * 1 if *d1 is greater than *d2 + */ +int ucx_doublecmp(const void *d1, const void *d2, void *data); + +/** + * Compares two pointers. + * @param ptr1 pointer one + * @param ptr2 pointer two + * @param data omitted + * @return -1 if ptr1 is less than ptr2, 0 if both are equal, + * 1 if ptr1 is greater than ptr2 + */ +int ucx_ptrcmp(const void *ptr1, const void *ptr2, void *data); + +/** + * Compares two memory areas. + * @param ptr1 pointer one + * @param ptr2 pointer two + * @param n a pointer to the size_t containing the third parameter for memcmp + * @return the result of memcmp(ptr1, ptr2, *n) + */ +int ucx_memcmp(const void *ptr1, const void *ptr2, void *n); + +/** + * A <code>printf()</code> like function which writes the output to a stream by + * using a write_func(). + * @param stream the stream the data is written to + * @param wfc the write function + * @param fmt format string + * @param ... additional arguments + * @return the total number of bytes written + */ +int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...); + +/** + * <code>va_list</code> version of ucx_fprintf(). + * @param stream the stream the data is written to + * @param wfc the write function + * @param fmt format string + * @param ap argument list + * @return the total number of bytes written + * @see ucx_fprintf() + */ +int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap); + +/** + * A <code>printf()</code> like function which allocates space for a sstr_t + * the result is written to. + * + * <b>Attention</b>: The sstr_t data is allocated with the allocators + * ucx_allocator_malloc() function. So it is implementation dependent, if + * the returned sstr_t.ptr pointer must be passed to the allocators + * ucx_allocator_free() function manually. + * + * <b>Note</b>: The sstr_t.ptr of the return value will <i>always</i> be + * <code>NULL</code>-terminated. + * + * @param allocator the UcxAllocator used for allocating the result sstr_t + * @param fmt format string + * @param ... additional arguments + * @return a sstr_t containing the formatted string + */ +sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...); + +/** + * <code>va_list</code> version of ucx_asprintf(). + * + * @param allocator the UcxAllocator used for allocating the result sstr_t + * @param fmt format string + * @param ap argument list + * @return a sstr_t containing the formatted string + * @see ucx_asprintf() + */ +sstr_t ucx_vasprintf(UcxAllocator *allocator, const char *fmt, va_list ap); + +/** Shortcut for ucx_asprintf() with default allocator. */ +#define ucx_sprintf(...) \ + ucx_asprintf(ucx_default_allocator(), __VA_ARGS__) + +/** + * A <code>printf()</code> like function which writes the output to a + * UcxBuffer. + * + * @param buffer the buffer the data is written to + * @param ... format string and additional arguments + * @return the total number of bytes written + * @see ucx_fprintf() + */ +#define ucx_bprintf(buffer, ...) ucx_fprintf((UcxBuffer*)buffer, \ + (write_func)ucx_buffer_write, __VA_ARGS__) + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_UTILS_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/utils.c Tue Oct 17 16:15:41 2017 +0200 @@ -0,0 +1,260 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ucx/utils.h" + +#include <math.h> +#include <stdio.h> +#include <limits.h> +#include <errno.h> + +/* COPY FUCNTIONS */ +void* ucx_strcpy(const void* s, void* data) { + const char *str = (const char*) s; + size_t n = 1+strlen(str); + char *cpy = (char*) malloc(n); + memcpy(cpy, str, n); + return cpy; +} + +void* ucx_memcpy(const void* m, void* n) { + size_t k = *((size_t*)n); + void *cpy = malloc(k); + memcpy(cpy, m, k); + return cpy; +} + +size_t ucx_stream_bncopy(void *src, void *dest, read_func readfnc, + write_func writefnc, char* buf, size_t bufsize, size_t n) { + if(n == 0 || bufsize == 0) { + return 0; + } + + char *lbuf; + size_t ncp = 0; + + if(buf) { + lbuf = buf; + } else { + lbuf = (char*)malloc(bufsize); + if(lbuf == NULL) { + return 0; + } + } + + size_t r; + size_t rn = bufsize > n ? n : bufsize; + while((r = readfnc(lbuf, 1, rn, src)) != 0) { + r = writefnc(lbuf, 1, r, dest); + ncp += r; + n -= r; + rn = bufsize > n ? n : bufsize; + if(r == 0 || n == 0) { + break; + } + } + + if (lbuf != buf) { + free(lbuf); + } + + return ncp; +} + +/* COMPARE FUNCTIONS */ + +int ucx_strcmp(const void *s1, const void *s2, void *data) { + return strcmp((const char*)s1, (const char*)s2); +} + +int ucx_strncmp(const void *s1, const void *s2, void *n) { + return strncmp((const char*)s1, (const char*)s2, *((size_t*) n)); +} + +int ucx_intcmp(const void *i1, const void *i2, void *data) { + int a = *((const int*) i1); + int b = *((const int*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_floatcmp(const void *f1, const void *f2, void *epsilon) { + float a = *((const float*) f1); + float b = *((const float*) f2); + float e = !epsilon ? 1e-6f : *((float*)epsilon); + if (fabsf(a - b) < e) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_doublecmp(const void *d1, const void *d2, void *epsilon) { + double a = *((const double*) d1); + double b = *((const double*) d2); + double e = !epsilon ? 1e-14 : *((double*)epsilon); + if (fabs(a - b) < e) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_ptrcmp(const void *ptr1, const void *ptr2, void *data) { + const intptr_t p1 = (const intptr_t) ptr1; + const intptr_t p2 = (const intptr_t) ptr2; + if (p1 == p2) { + return 0; + } else { + return p1 < p2 ? -1 : 1; + } +} + +int ucx_memcmp(const void *ptr1, const void *ptr2, void *n) { + return memcmp(ptr1, ptr2, *((size_t*)n)); +} + +/* PRINTF FUNCTIONS */ + +#ifdef va_copy +#define UCX_PRINTF_BUFSIZE 256 +#else +#pragma message("WARNING: C99 va_copy macro not supported by this platform" \ + " - limiting ucx_*printf to 2 KiB") +#define UCX_PRINTF_BUFSIZE 0x800 +#endif + +int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = ucx_vfprintf(stream, wfc, fmt, ap); + va_end(ap); + return ret; +} + +int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap) { + char buf[UCX_PRINTF_BUFSIZE]; +#ifdef va_copy + va_list ap2; + va_copy(ap2, ap); + int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); + if (ret < 0) { + return ret; + } else if (ret < UCX_PRINTF_BUFSIZE) { + return (int)wfc(buf, 1, ret, stream); + } else { + if (ret == INT_MAX) { + errno = ENOMEM; + return -1; + } + + int len = ret + 1; + char *newbuf = (char*)malloc(len); + if (!newbuf) { + return -1; + } + + ret = vsnprintf(newbuf, len, fmt, ap2); + if (ret > 0) { + ret = (int)wfc(newbuf, 1, ret, stream); + } + free(newbuf); + } + return ret; +#else + int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); + if (ret < 0) { + return ret; + } else if (ret < UCX_PRINTF_BUFSIZE) { + return (int)wfc(buf, 1, ret, stream); + } else { + errno = ENOMEM; + return -1; + } +#endif +} + +sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...) { + va_list ap; + sstr_t ret; + va_start(ap, fmt); + ret = ucx_vasprintf(allocator, fmt, ap); + va_end(ap); + return ret; +} + +sstr_t ucx_vasprintf(UcxAllocator *a, const char *fmt, va_list ap) { + sstr_t s; + s.ptr = NULL; + s.length = 0; + char buf[UCX_PRINTF_BUFSIZE]; +#ifdef va_copy + va_list ap2; + va_copy(ap2, ap); + int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); + if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) { + s.ptr = (char*)almalloc(a, ret + 1); + if (s.ptr) { + s.length = (size_t)ret; + memcpy(s.ptr, buf, ret); + s.ptr[s.length] = '\0'; + } + } else if (ret == INT_MAX) { + errno = ENOMEM; + } else { + int len = ret + 1; + s.ptr = (char*)almalloc(a, len); + if (s.ptr) { + ret = vsnprintf(s.ptr, len, fmt, ap2); + if (ret < 0) { + free(s.ptr); + s.ptr = NULL; + } else { + s.length = (size_t)ret; + } + } + } +#else + int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); + if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) { + s.ptr = (char*)almalloc(a, ret + 1); + if (s.ptr) { + s.length = (size_t)ret; + memcpy(s.ptr, buf, ret); + s.ptr[s.length] = '\0'; + } + } else { + errno = ENOMEM; + } +#endif + return s; +}
--- a/test/Makefile Tue Oct 17 15:15:54 2017 +0200 +++ b/test/Makefile Tue Oct 17 16:15:41 2017 +0200 @@ -52,7 +52,7 @@ $(OBJ) ../build/release/libucx$(LIB_EXT) ../build/release/test/%$(OBJ_EXT): %.c - $(CC) $(CFLAGS) -I../ -o $@ -c $< + $(CC) $(CFLAGS) -I../src/ -o $@ -c $< ../build/release/test: $(MKDIR) $(MKDIRFLAGS) ../build/release/test @@ -62,7 +62,7 @@ $(OBJ_D) ../build/debug/libucx$(LIB_EXT) ../build/debug/test/%$(OBJ_EXT): %.c - $(CC) $(CFLAGS_D) -I../ -o $@ -c $< + $(CC) $(CFLAGS_D) -I../src/ -o $@ -c $< ../build/debug/test: $(MKDIR) $(MKDIRFLAGS) ../build/debug/test
--- a/test/allocator_tests.h Tue Oct 17 15:15:54 2017 +0200 +++ b/test/allocator_tests.h Tue Oct 17 16:15:41 2017 +0200 @@ -29,8 +29,8 @@ #ifndef ALLOCATOR_TEST_H #define ALLOCATOR_TEST_H -#include "ucx/test.h" -#include "ucx/allocator.h" +#include <ucx/test.h> +#include <ucx/allocator.h> #ifdef __cplusplus extern "C" {
--- a/test/avl_tests.c Tue Oct 17 15:15:54 2017 +0200 +++ b/test/avl_tests.c Tue Oct 17 16:15:41 2017 +0200 @@ -28,7 +28,7 @@ #include "avl_tests.h" -#include "ucx/utils.h" +#include <ucx/utils.h> static int node_height(UcxAVLNode *node) { if(!node) {
--- a/test/avl_tests.h Tue Oct 17 15:15:54 2017 +0200 +++ b/test/avl_tests.h Tue Oct 17 16:15:41 2017 +0200 @@ -29,8 +29,8 @@ #ifndef AVL_TEST_H #define AVL_TEST_H -#include "ucx/test.h" -#include "ucx/avl.h" +#include <ucx/test.h> +#include <ucx/avl.h> #ifdef __cplusplus extern "C" {
--- a/test/buffer_tests.h Tue Oct 17 15:15:54 2017 +0200 +++ b/test/buffer_tests.h Tue Oct 17 16:15:41 2017 +0200 @@ -29,8 +29,8 @@ #ifndef BUFFER_TEST_H #define BUFFER_TEST_H -#include "ucx/test.h" -#include "ucx/buffer.h" +#include <ucx/test.h> +#include <ucx/buffer.h> #ifdef __cplusplus extern "C" {
--- a/test/list_tests.c Tue Oct 17 15:15:54 2017 +0200 +++ b/test/list_tests.c Tue Oct 17 16:15:41 2017 +0200 @@ -27,7 +27,7 @@ */ #include "list_tests.h" -#include "ucx/utils.h" +#include <ucx/utils.h> UCX_TEST(test_ucx_list_append) { UcxList *list, *first;
--- a/test/list_tests.h Tue Oct 17 15:15:54 2017 +0200 +++ b/test/list_tests.h Tue Oct 17 16:15:41 2017 +0200 @@ -29,10 +29,8 @@ #ifndef LIST_TESTS_H #define LIST_TESTS_H -#include "main.h" - -#include "ucx/list.h" -#include "ucx/test.h" +#include <ucx/list.h> +#include <ucx/test.h> #ifdef __cplusplus extern "C" {
--- a/test/logging_tests.h Tue Oct 17 15:15:54 2017 +0200 +++ b/test/logging_tests.h Tue Oct 17 16:15:41 2017 +0200 @@ -29,8 +29,8 @@ #ifndef LOGGING_TESTS_H #define LOGGING_TESTS_H -#include "ucx/test.h" -#include "ucx/logging.h" +#include <ucx/test.h> +#include <ucx/logging.h> #ifdef __cplusplus extern "C" {
--- a/test/main.c Tue Oct 17 15:15:54 2017 +0200 +++ b/test/main.c Tue Oct 17 16:15:41 2017 +0200 @@ -29,7 +29,7 @@ #include <stdio.h> #include <stdlib.h> -#include "ucx/test.h" +#include <ucx/test.h> #include "main.h"
--- a/test/map_tests.h Tue Oct 17 15:15:54 2017 +0200 +++ b/test/map_tests.h Tue Oct 17 16:15:41 2017 +0200 @@ -29,8 +29,8 @@ #ifndef MAP_TESTS_H #define MAP_TESTS_H -#include "ucx/test.h" -#include "ucx/map.h" +#include <ucx/test.h> +#include <ucx/map.h> #ifdef __cplusplus extern "C" {
--- a/test/mpool_tests.h Tue Oct 17 15:15:54 2017 +0200 +++ b/test/mpool_tests.h Tue Oct 17 16:15:41 2017 +0200 @@ -29,8 +29,8 @@ #ifndef MPOOL_TESTS_H #define MPOOL_TESTS_H -#include "ucx/test.h" -#include "ucx/mempool.h" +#include <ucx/test.h> +#include <ucx/mempool.h> #ifdef __cplusplus extern "C" {
--- a/test/prop_tests.c Tue Oct 17 15:15:54 2017 +0200 +++ b/test/prop_tests.c Tue Oct 17 16:15:41 2017 +0200 @@ -27,7 +27,7 @@ */ #include "prop_tests.h" -#include "ucx/mempool.h" +#include <ucx/mempool.h> UCX_TEST(test_ucx_properties_new) { UcxProperties *parser = ucx_properties_new();
--- a/test/prop_tests.h Tue Oct 17 15:15:54 2017 +0200 +++ b/test/prop_tests.h Tue Oct 17 16:15:41 2017 +0200 @@ -29,8 +29,8 @@ #ifndef PROP_TESTS_H #define PROP_TESTS_H -#include "ucx/test.h" -#include "ucx/properties.h" +#include <ucx/test.h> +#include <ucx/properties.h> #ifdef __cplusplus extern "C" {
--- a/test/stack_tests.h Tue Oct 17 15:15:54 2017 +0200 +++ b/test/stack_tests.h Tue Oct 17 16:15:41 2017 +0200 @@ -29,8 +29,8 @@ #ifndef STACK_TESTS_H #define STACK_TESTS_H -#include "ucx/test.h" -#include "ucx/stack.h" +#include <ucx/test.h> +#include <ucx/stack.h> #ifdef __cplusplus extern "C" {
--- a/test/string_tests.h Tue Oct 17 15:15:54 2017 +0200 +++ b/test/string_tests.h Tue Oct 17 16:15:41 2017 +0200 @@ -29,8 +29,8 @@ #ifndef STRING_TESTS_H #define STRING_TESTS_H -#include "ucx/test.h" -#include "ucx/string.h" +#include <ucx/test.h> +#include <ucx/string.h> #ifdef __cplusplus extern "C" {
--- a/test/utils_tests.c Tue Oct 17 15:15:54 2017 +0200 +++ b/test/utils_tests.c Tue Oct 17 16:15:41 2017 +0200 @@ -27,7 +27,7 @@ */ #include "utils_tests.h" -#include "ucx/buffer.h" +#include <ucx/buffer.h> UCX_TEST(test_ucx_fprintf) { UcxBuffer *b1 = ucx_buffer_new(NULL, 32, UCX_BUFFER_AUTOEXTEND);
--- a/test/utils_tests.h Tue Oct 17 15:15:54 2017 +0200 +++ b/test/utils_tests.h Tue Oct 17 16:15:41 2017 +0200 @@ -29,8 +29,8 @@ #ifndef UTILS_TESTS_H #define UTILS_TESTS_H -#include "ucx/test.h" -#include "ucx/utils.h" +#include <ucx/test.h> +#include <ucx/utils.h> #ifdef __cplusplus extern "C" {
--- a/ucx/Makefile Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -# -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. -# -# Copyright 2017 Olaf Wintermann. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# - -include ../$(CONF).mk -include ../cppcheck.mk - -# list of source files -SRC = utils.c -SRC += list.c -SRC += map.c -SRC += avl.c -SRC += properties.c -SRC += mempool.c -SRC += string.c -SRC += test.c -SRC += allocator.c -SRC += logging.c -SRC += buffer.c -SRC += stack.c - -OBJ = $(SRC:%.c=../build/release/ucx/%$(OBJ_EXT)) -OBJ_D = $(SRC:%.c=../build/debug/ucx/%$(OBJ_EXT)) - -all: ../build/release/ucx \ - ../build/release/libucx$(LIB_EXT) ../build/release/libucx$(SO_EXT) -debug: ../build/debug/ucx \ - ../build/debug/libucx$(LIB_EXT) ../build/debug/libucx$(SO_EXT) - -../build/release/libucx$(LIB_EXT): $(OBJ) - $(AR) $(ARFLAGS) ../build/release/libucx$(LIB_EXT) $(OBJ) - -../build/release/libucx$(SO_EXT): $(OBJ) - $(LD) $(SOLDFLAGS) -o ../build/release/libucx$(SO_EXT) $(OBJ) - -../build/release/ucx/%$(OBJ_EXT): %.c - $(CC) $(CFLAGS) -o $@ -c $< - -../build/release/ucx: - $(MKDIR) $(MKDIRFLAGS) ../build/release/ucx - -../build/debug/libucx$(LIB_EXT): $(OBJ_D) - $(AR) $(ARFLAGS) ../build/debug/libucx$(LIB_EXT) $(OBJ_D) - -../build/debug/libucx$(SO_EXT): $(OBJ_D) - $(LD) $(SOLDFLAGS) -o ../build/debug/libucx$(SO_EXT) $(OBJ_D) - -../build/debug/ucx/%$(OBJ_EXT): %.c - $(CC) $(CFLAGS_D) -o $@ -c $< - -../build/debug/ucx: - $(MKDIR) $(MKDIRFLAGS) ../build/debug/ucx - -cppcheck: $(SRC) - $(CPPCHECK) $(CPPCHECK_CONFIG) $(CPPCHECK_FLAGS) $+ 2>> ../$(CPPCHECK_LOG)
--- a/ucx/allocator.c Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stdlib.h> -#include "allocator.h" - -UcxAllocator default_allocator = { - NULL, - ucx_default_malloc, - ucx_default_calloc, - ucx_default_realloc, - ucx_default_free -}; - -UcxAllocator *ucx_default_allocator() { - UcxAllocator *allocator = &default_allocator; - return allocator; -} - -void *ucx_default_malloc(void *ignore, size_t n) { - return malloc(n); -} - -void *ucx_default_calloc(void *ignore, size_t n, size_t size) { - return calloc(n, size); -} - -void *ucx_default_realloc(void *ignore, void *data, size_t n) { - return realloc(data, n); -} - -void ucx_default_free(void *ignore, void *data) { - free(data); -}
--- a/ucx/allocator.h Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/** - * Allocator for custom memory management. - * - * A UCX allocator consists of a pointer to the memory area / pool and four - * function pointers to memory management functions operating on this memory - * area / pool. These functions shall behave equivalent to the standard libc - * functions <code>malloc(), calloc(), realloc()</code> and <code>free()</code>. - * - * The signature of the memory management functions is based on the signature - * of the respective libc function but each of them takes the pointer to the - * memory area / pool as first argument. - * - * As the pointer to the memory area / pool can be arbitrarily chosen, any data - * can be provided to the memory management functions. A UcxMempool is just - * one example. - * - * @see mempool.h - * @see UcxMap - * - * @file allocator.h - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_ALLOCATOR_H -#define UCX_ALLOCATOR_H - -#include "ucx.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * A function pointer to the allocators <code>malloc()</code> function. - * @see UcxAllocator - */ -typedef void*(*ucx_allocator_malloc)(void *pool, size_t n); - -/** - * A function pointer to the allocators <code>calloc()</code> function. - * @see UcxAllocator - */ -typedef void*(*ucx_allocator_calloc)(void *pool, size_t n, size_t size); - -/** - * A function pointer to the allocators <code>realloc()</code> function. - * @see UcxAllocator - */ -typedef void*(*ucx_allocator_realloc)(void *pool, void *data, size_t n); - -/** - * A function pointer to the allocators <code>free()</code> function. - * @see UcxAllocator - */ -typedef void(*ucx_allocator_free)(void *pool, void *data); - -/** - * UCX allocator data structure containing memory management functions. - */ -typedef struct { - /** Pointer to an area of memory or a complex memory pool. - * This pointer will be passed to any memory management function as first - * argument. - */ - void *pool; - /** - * The <code>malloc()</code> function for this allocator. - */ - ucx_allocator_malloc malloc; - /** - * The <code>calloc()</code> function for this allocator. - */ - ucx_allocator_calloc calloc; - /** - * The <code>realloc()</code> function for this allocator. - */ - ucx_allocator_realloc realloc; - /** - * The <code>free()</code> function for this allocator. - */ - ucx_allocator_free free; -} UcxAllocator; - -/** - * Returns a pointer to the default allocator. - * - * The default allocator contains wrappers to the standard libc memory - * management functions. Use this function to get a pointer to a globally - * available allocator. You may also define an own UcxAllocator by assigning - * #UCX_ALLOCATOR_DEFAULT to a variable and pass the address of this variable - * to any function that takes a UcxAllocator as argument. Note that using - * this function is the recommended way of passing a default allocator, thus - * it never runs out of scope. - * - * @return a pointer to the default allocator - * - * @see UCX_ALLOCATOR_DEFAULT - */ -UcxAllocator *ucx_default_allocator(); - -/** - * A wrapper for the standard libc <code>malloc()</code> function. - * @param ignore ignored (may be used by allocators for pooled memory) - * @param n argument passed to <code>malloc()</code> - * @return return value of <code>malloc()</code> - */ -void *ucx_default_malloc(void *ignore, size_t n); -/** - * A wrapper for the standard libc <code>calloc()</code> function. - * @param ignore ignored (may be used by allocators for pooled memory) - * @param n argument passed to <code>calloc()</code> - * @param size argument passed to <code>calloc()</code> - * @return return value of <code>calloc()</code> - */ -void *ucx_default_calloc(void *ignore, size_t n, size_t size); -/** - * A wrapper for the standard libc <code>realloc()</code> function. - * @param ignore ignored (may be used by allocators for pooled memory) - * @param data argumend passed to <code>realloc()</code> - * @param n argument passed to <code>realloc()</code> - * @return return value of <code>realloc()</code> - */ -void *ucx_default_realloc(void *ignore, void *data, size_t n); -/** - * A wrapper for the standard libc <code>free()</code> function. - * @param ignore ignored (may be used by allocators for pooled memory) - * @param data argument passed to <code>free()</code> - */ -void ucx_default_free(void *ignore, void *data); - -/** - * Shorthand for calling an allocators malloc function. - * @param allocator the allocator to use - * @param n size of space to allocate - * @return a pointer to the allocated memory area - */ -#define almalloc(allocator, n) ((allocator)->malloc((allocator)->pool, n)) - -/** - * Shorthand for calling an allocators calloc function. - * @param allocator the allocator to use - * @param n the count of elements the space should be allocated for - * @param size the size of each element - * @return a pointer to the allocated memory area - */ -#define alcalloc(allocator, n, size) \ - ((allocator)->calloc((allocator)->pool, n, size)) - -/** - * Shorthand for calling an allocators realloc function. - * @param allocator the allocator to use - * @param ptr the pointer to the memory area that shall be reallocated - * @param n the new size of the allocated memory area - * @return a pointer to the reallocated memory area - */ -#define alrealloc(allocator, ptr, n) \ - ((allocator)->realloc((allocator)->pool, ptr, n)) - -/** - * Shorthand for calling an allocators free function. - * @param allocator the allocator to use - * @param ptr the pointer to the memory area that shall be freed - */ -#define alfree(allocator, ptr) ((allocator)->free((allocator)->pool, ptr)) - -/** - * Convenient macro for a default allocator <code>struct</code> definition. - */ -#define UCX_ALLOCATOR_DEFAULT {NULL, \ - ucx_default_malloc, ucx_default_calloc, ucx_default_realloc, \ - ucx_default_free } - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_ALLOCATOR_H */ -
--- a/ucx/avl.c Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,356 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <limits.h> - -#include "avl.h" - -#define ptrcast(ptr) ((void*)(ptr)) -#define alloc_tree(al) (UcxAVLTree*) almalloc((al), sizeof(UcxAVLTree)) -#define alloc_node(al) (UcxAVLNode*) almalloc((al), sizeof(UcxAVLNode)) - -static void ucx_avl_connect(UcxAVLTree *tree, - UcxAVLNode *node, UcxAVLNode *child, intptr_t nullkey) { - if (child) { - child->parent = node; - } - // if child is NULL, nullkey decides if left or right pointer is cleared - if (tree->cmpfunc( - ptrcast(child ? child->key : nullkey), - ptrcast(node->key), tree->userdata) > 0) { - node->right = child; - } else { - node->left = child; - } - size_t lh = node->left ? node->left->height : 0; - size_t rh = node->right ? node->right->height : 0; - node->height = 1 + (lh > rh ? lh : rh); -} - -#define avlheight(node) ((node) ? (node)->height : 0) - -static UcxAVLNode* avl_rotright(UcxAVLTree *tree, UcxAVLNode *l0) { - UcxAVLNode *p = l0->parent; - UcxAVLNode *l1 = l0->left; - if (p) { - ucx_avl_connect(tree, p, l1, 0); - } else { - l1->parent = NULL; - } - ucx_avl_connect(tree, l0, l1->right, l1->key); - ucx_avl_connect(tree, l1, l0, 0); - return l1; -} - -static UcxAVLNode* avl_rotleft(UcxAVLTree *tree, UcxAVLNode *l0) { - UcxAVLNode *p = l0->parent; - UcxAVLNode *l1 = l0->right; - if (p) { - ucx_avl_connect(tree, p, l1, 0); - } else { - l1->parent = NULL; - } - ucx_avl_connect(tree, l0, l1->left, l1->key); - ucx_avl_connect(tree, l1, l0, 0); - return l1; -} - -static void ucx_avl_balance(UcxAVLTree *tree, UcxAVLNode *n) { - int lh = avlheight(n->left); - int rh = avlheight(n->right); - n->height = 1 + (lh > rh ? lh : rh); - - if (lh - rh == 2) { - UcxAVLNode *c = n->left; - if (avlheight(c->right) - avlheight(c->left) == 1) { - avl_rotleft(tree, c); - } - n = avl_rotright(tree, n); - } else if (rh - lh == 2) { - UcxAVLNode *c = n->right; - if (avlheight(c->left) - avlheight(c->right) == 1) { - avl_rotright(tree, c); - } - n = avl_rotleft(tree, n); - } - - if (n->parent) { - ucx_avl_balance(tree, n->parent); - } else { - tree->root = n; - } -} - -UcxAVLTree *ucx_avl_new(cmp_func cmpfunc) { - return ucx_avl_new_a(cmpfunc, ucx_default_allocator()); -} - -UcxAVLTree *ucx_avl_new_a(cmp_func cmpfunc, UcxAllocator *allocator) { - UcxAVLTree* tree = alloc_tree(allocator); - if (tree) { - tree->allocator = allocator; - tree->cmpfunc = cmpfunc; - tree->root = NULL; - tree->userdata = NULL; - } - - return tree; -} - -static void ucx_avl_free_node(UcxAllocator *al, UcxAVLNode *node) { - if (node) { - ucx_avl_free_node(al, node->left); - ucx_avl_free_node(al, node->right); - alfree(al, node); - } -} - -void ucx_avl_free(UcxAVLTree *tree) { - UcxAllocator *al = tree->allocator; - ucx_avl_free_node(al, tree->root); - alfree(al, tree); -} - -UcxAVLNode *ucx_avl_get_node(UcxAVLTree *tree, intptr_t key) { - UcxAVLNode *n = tree->root; - int cmpresult; - while (n && (cmpresult = tree->cmpfunc( - ptrcast(key), ptrcast(n->key), tree->userdata))) { - n = cmpresult > 0 ? n->right : n->left; - } - return n; -} - -void *ucx_avl_get(UcxAVLTree *tree, intptr_t key) { - UcxAVLNode *n = ucx_avl_get_node(tree, key); - return n ? n->value : NULL; -} - -UcxAVLNode *ucx_avl_find_node(UcxAVLTree *tree, intptr_t key, - distance_func dfnc, int mode) { - UcxAVLNode *n = tree->root; - UcxAVLNode *closest = NULL; - - intmax_t cmpresult; - intmax_t closest_dist; - closest_dist = mode == UCX_AVL_FIND_LOWER_BOUNDED ? INTMAX_MIN : INTMAX_MAX; - - while (n && (cmpresult = dfnc( - ptrcast(key), ptrcast(n->key), tree->userdata))) { - if (mode == UCX_AVL_FIND_CLOSEST) { - intmax_t dist = cmpresult; - if (dist < 0) dist *= -1; - if (dist < closest_dist) { - closest_dist = dist; - closest = n; - } - } else if (mode == UCX_AVL_FIND_LOWER_BOUNDED && cmpresult <= 0) { - if (cmpresult > closest_dist) { - closest_dist = cmpresult; - closest = n; - } - } else if (mode == UCX_AVL_FIND_UPPER_BOUNDED && cmpresult >= 0) { - if (cmpresult < closest_dist) { - closest_dist = cmpresult; - closest = n; - } - } - n = cmpresult > 0 ? n->right : n->left; - } - return n ? n : closest; -} - -void *ucx_avl_find(UcxAVLTree *tree, intptr_t key, - distance_func dfnc, int mode) { - UcxAVLNode *n = ucx_avl_find_node(tree, key, dfnc, mode); - return n ? n->value : NULL; -} - -int ucx_avl_put(UcxAVLTree *tree, intptr_t key, void *value) { - return ucx_avl_put_s(tree, key, value, NULL); -} - -int ucx_avl_put_s(UcxAVLTree *tree, intptr_t key, void *value, - void **oldvalue) { - if (tree->root) { - UcxAVLNode *n = tree->root; - int cmpresult; - while ((cmpresult = tree->cmpfunc( - ptrcast(key), ptrcast(n->key), tree->userdata))) { - UcxAVLNode *m = cmpresult > 0 ? n->right : n->left; - if (m) { - n = m; - } else { - break; - } - } - - if (cmpresult) { - UcxAVLNode* e = alloc_node(tree->allocator); - if (e) { - e->key = key; e->value = value; e->height = 1; - e->parent = e->left = e->right = NULL; - ucx_avl_connect(tree, n, e, 0); - ucx_avl_balance(tree, n); - return 0; - } else { - return 1; - } - } else { - if (oldvalue) { - *oldvalue = n->value; - } - n->value = value; - return 0; - } - } else { - tree->root = alloc_node(tree->allocator); - if (tree->root) { - tree->root->key = key; tree->root->value = value; - tree->root->height = 1; - tree->root->parent = tree->root->left = tree->root->right = NULL; - - if (oldvalue) { - *oldvalue = NULL; - } - - return 0; - } else { - return 1; - } - } -} - -int ucx_avl_remove(UcxAVLTree *tree, intptr_t key) { - return ucx_avl_remove_s(tree, key, NULL, NULL); -} - -int ucx_avl_remove_node(UcxAVLTree *tree, UcxAVLNode *node) { - return ucx_avl_remove_s(tree, node->key, NULL, NULL); -} - -int ucx_avl_remove_s(UcxAVLTree *tree, intptr_t key, - intptr_t *oldkey, void **oldvalue) { - - UcxAVLNode *n = tree->root; - int cmpresult; - while (n && (cmpresult = tree->cmpfunc( - ptrcast(key), ptrcast(n->key), tree->userdata))) { - n = cmpresult > 0 ? n->right : n->left; - } - if (n) { - if (oldkey) { - *oldkey = n->key; - } - if (oldvalue) { - *oldvalue = n->value; - } - - UcxAVLNode *p = n->parent; - if (n->left && n->right) { - UcxAVLNode *s = n->right; - while (s->left) { - s = s->left; - } - ucx_avl_connect(tree, s->parent, s->right, s->key); - n->key = s->key; n->value = s->value; - p = s->parent; - alfree(tree->allocator, s); - } else { - if (p) { - ucx_avl_connect(tree, p, n->right ? n->right:n->left, n->key); - } else { - tree->root = n->right ? n->right : n->left; - if (tree->root) { - tree->root->parent = NULL; - } - } - alfree(tree->allocator, n); - } - - if (p) { - ucx_avl_balance(tree, p); - } - - return 0; - } else { - return 1; - } -} - -static size_t ucx_avl_countn(UcxAVLNode *node) { - if (node) { - return 1 + ucx_avl_countn(node->left) + ucx_avl_countn(node->right); - } else { - return 0; - } -} - -size_t ucx_avl_count(UcxAVLTree *tree) { - return ucx_avl_countn(tree->root); -} - -UcxAVLNode* ucx_avl_pred(UcxAVLNode* node) { - if (node->left) { - UcxAVLNode* n = node->left; - while (n->right) { - n = n->right; - } - return n; - } else { - UcxAVLNode* n = node; - while (n->parent) { - if (n->parent->right == n) { - return n->parent; - } else { - n = n->parent; - } - } - return NULL; - } -} - -UcxAVLNode* ucx_avl_succ(UcxAVLNode* node) { - if (node->right) { - UcxAVLNode* n = node->right; - while (n->left) { - n = n->left; - } - return n; - } else { - UcxAVLNode* n = node; - while (n->parent) { - if (n->parent->left == n) { - return n->parent; - } else { - n = n->parent; - } - } - return NULL; - } -}
--- a/ucx/avl.h Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,327 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - - -/** - * @file avl.h - * - * AVL tree implementation. - * - * This binary search tree implementation allows average O(1) insertion and - * removal of elements (excluding binary search time). - * - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_AVL_H -#define UCX_AVL_H - -#include "ucx.h" -#include "allocator.h" -#include <inttypes.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * UCX AVL Node type. - * - * @see UcxAVLNode - */ -typedef struct UcxAVLNode UcxAVLNode; - -/** - * UCX AVL Node. - */ -struct UcxAVLNode { - /** - * The key for this node. - */ - intptr_t key; - /** - * Data contained by this node. - */ - void *value; - /** - * The height of this (sub)-tree. - */ - size_t height; - /** - * Parent node. - */ - UcxAVLNode *parent; - /** - * Root node of left subtree. - */ - UcxAVLNode *left; - /** - * Root node of right subtree. - */ - UcxAVLNode *right; -}; - -/** - * UCX AVL Tree. - */ -typedef struct { - /** - * The UcxAllocator that shall be used to manage the memory for node data. - */ - UcxAllocator *allocator; - /** - * Root node of the tree. - */ - UcxAVLNode *root; - /** - * Compare function that shall be used to compare the UcxAVLNode keys. - * @see UcxAVLNode.key - */ - cmp_func cmpfunc; - /** - * Custom user data. - * This data will also be provided to the cmpfunc. - */ - void *userdata; -} UcxAVLTree; - -/** - * Initializes a new UcxAVLTree with a default allocator. - * - * @param cmpfunc the compare function that shall be used - * @return a new UcxAVLTree object - * @see ucx_avl_new_a() - */ -UcxAVLTree *ucx_avl_new(cmp_func cmpfunc); - -/** - * Initializes a new UcxAVLTree with the specified allocator. - * - * The cmpfunc should be capable of comparing two keys within this AVL tree. - * So if you want to use null terminated strings as keys, you could use the - * ucx_strcmp() function here. - * - * @param cmpfunc the compare function that shall be used - * @param allocator the UcxAllocator that shall be used - * @return a new UcxAVLTree object - */ -UcxAVLTree *ucx_avl_new_a(cmp_func cmpfunc, UcxAllocator *allocator); - -/** - * Destroys a UcxAVLTree. - * @param tree the tree to destroy - */ -void ucx_avl_free(UcxAVLTree *tree); - -/** - * Macro for initializing a new UcxAVLTree with the default allocator and a - * ucx_ptrcmp() compare function. - * - * @return a new default UcxAVLTree object - */ -#define ucx_avl_default_new() ucx_avl_new_a(ucx_ptrcmp, ucx_default_allocator()) - -/** - * Gets the node from the tree, that is associated with the specified key. - * @param tree the UcxAVLTree - * @param key the key - * @return the node (or <code>NULL</code>, if the key is not present) - */ -UcxAVLNode *ucx_avl_get_node(UcxAVLTree *tree, intptr_t key); - -/** - * Gets the value from the tree, that is associated with the specified key. - * @param tree the UcxAVLTree - * @param key the key - * @return the value (or <code>NULL</code>, if the key is not present) - */ -void *ucx_avl_get(UcxAVLTree *tree, intptr_t key); - -/** - * A mode for #ucx_avl_find_node() with the same behavior as - * #ucx_avl_get_node(). - */ -#define UCX_AVL_FIND_EXACT 0 -/** - * A mode for #ucx_avl_find_node() finding the node whose key is at least - * as large as the specified key. - */ -#define UCX_AVL_FIND_LOWER_BOUNDED 1 -/** - * A mode for #ucx_avl_find_node() finding the node whose key is at most - * as large as the specified key. - */ -#define UCX_AVL_FIND_UPPER_BOUNDED 2 -/** - * A mode for #ucx_avl_find_node() finding the node with a key that is as close - * to the specified key as possible. If the key is present, the behavior is - * like #ucx_avl_get_node(). This mode only returns <code>NULL</code> on - * empty trees. - */ -#define UCX_AVL_FIND_CLOSEST 3 - -/** - * Finds a node within the tree. The following modes are supported: - * <ul> - * <li>#UCX_AVL_FIND_EXACT: the same behavior as #ucx_avl_get_node()</li> - * <li>#UCX_AVL_FIND_LOWER_BOUNDED: finds the node whose key is at least - * as large as the specified key</li> - * <li>#UCX_AVL_FIND_UPPER_BOUNDED: finds the node whose key is at most - * as large as the specified key</li> - * <li>#UCX_AVL_FIND_CLOSEST: finds the node with a key that is as close to - * the specified key as possible. If the key is present, the behavior is - * like #ucx_avl_get_node(). This mode only returns <code>NULL</code> on - * empty trees.</li> - * </ul> - * - * The distance function provided MUST agree with the compare function of - * the AVL tree. - * - * @param tree the UcxAVLTree - * @param key the key - * @param dfnc the distance function - * @param mode the find mode - * @return the node (or <code>NULL</code>, if no node can be found) - */ -UcxAVLNode *ucx_avl_find_node(UcxAVLTree *tree, intptr_t key, - distance_func dfnc, int mode); - -/** - * Finds a value within the tree. - * See #ucx_avl_find_node() for details. - * - * @param tree the UcxAVLTree - * @param key the key - * @param dfnc the distance function - * @param mode the find mode - * @return the value (or <code>NULL</code>, if no value can be found) - */ -void *ucx_avl_find(UcxAVLTree *tree, intptr_t key, - distance_func dfnc, int mode); - -/** - * Puts a key/value pair into the tree. - * - * Attention: use this function only, if a possible old value does not need - * to be preserved. - * - * @param tree the UcxAVLTree - * @param key the key - * @param value the new value - * @return zero, if and only if the operation succeeded - */ -int ucx_avl_put(UcxAVLTree *tree, intptr_t key, void *value); - -/** - * Puts a key/value pair into the tree. - * - * This is a secure function which saves the old value to the variable pointed - * at by oldvalue. - * - * @param tree the UcxAVLTree - * @param key the key - * @param value the new value - * @param oldvalue optional: a pointer to the location where a possible old - * value shall be stored - * @return zero, if and only if the operation succeeded - */ -int ucx_avl_put_s(UcxAVLTree *tree, intptr_t key, void *value, void **oldvalue); - -/** - * Removes a node from the AVL tree. - * - * Note: the specified node is logically removed. The tree implementation - * decides which memory area is freed. In most cases the here provided node - * is freed, so its further use is generally undefined. - * - * @param tree the UcxAVLTree - * @param node the node to remove - * @return zero, if and only if an element has been removed - */ -int ucx_avl_remove_node(UcxAVLTree *tree, UcxAVLNode *node); - -/** - * Removes an element from the AVL tree. - * - * @param tree the UcxAVLTree - * @param key the key - * @return zero, if and only if an element has been removed - */ -int ucx_avl_remove(UcxAVLTree *tree, intptr_t key); - -/** - * Removes an element from the AVL tree. - * - * This is a secure function which saves the old key and value data from node - * to the variables at the location of oldkey and oldvalue (if specified), so - * they can be freed afterwards (if necessary). - * - * Note: the returned key in oldkey is possibly not the same as the provided - * key for the lookup (in terms of memory location). - * - * @param tree the UcxAVLTree - * @param key the key of the element to remove - * @param oldkey optional: a pointer to the location where the old key shall be - * stored - * @param oldvalue optional: a pointer to the location where the old value - * shall be stored - * @return zero, if and only if an element has been removed - */ -int ucx_avl_remove_s(UcxAVLTree *tree, intptr_t key, - intptr_t *oldkey, void **oldvalue); - -/** - * Counts the nodes in the specified UcxAVLTree. - * @param tree the AVL tree - * @return the node count - */ -size_t ucx_avl_count(UcxAVLTree *tree); - -/** - * Finds the in-order predecessor of the given node. - * @param node an AVL node - * @return the in-order predecessor of the given node, or <code>NULL</code> if - * the given node is the in-order minimum - */ -UcxAVLNode* ucx_avl_pred(UcxAVLNode* node); - -/** - * Finds the in-order successor of the given node. - * @param node an AVL node - * @return the in-order successor of the given node, or <code>NULL</code> if - * the given node is the in-order maximum - */ -UcxAVLNode* ucx_avl_succ(UcxAVLNode* node); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_AVL_H */ -
--- a/ucx/buffer.c Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,235 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "buffer.h" -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> - -UcxBuffer *ucx_buffer_new(void *space, size_t capacity, int flags) { - UcxBuffer *buffer = (UcxBuffer*) malloc(sizeof(UcxBuffer)); - if (buffer) { - buffer->flags = flags; - if (!space) { - buffer->space = (char*)malloc(capacity); - if (!buffer->space) { - free(buffer); - return NULL; - } - memset(buffer->space, 0, capacity); - buffer->flags |= UCX_BUFFER_AUTOFREE; - } else { - buffer->space = (char*)space; - } - buffer->capacity = capacity; - buffer->size = 0; - - buffer->pos = 0; - } - - return buffer; -} - -void ucx_buffer_free(UcxBuffer *buffer) { - if ((buffer->flags & UCX_BUFFER_AUTOFREE) == UCX_BUFFER_AUTOFREE) { - free(buffer->space); - } - free(buffer); -} - -UcxBuffer* ucx_buffer_extract( - UcxBuffer *src, size_t start, size_t length, int flags) { - if (src->size == 0 || length == 0 || - ((size_t)-1) - start < length || start+length > src->capacity) - { - return NULL; - } - - UcxBuffer *dst = (UcxBuffer*) malloc(sizeof(UcxBuffer)); - if (dst) { - dst->space = (char*)malloc(length); - if (!dst->space) { - free(dst); - return NULL; - } - dst->capacity = length; - dst->size = length; - dst->flags = flags | UCX_BUFFER_AUTOFREE; - dst->pos = 0; - memcpy(dst->space, src->space+start, length); - } - return dst; -} - -int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence) { - size_t npos; - switch (whence) { - case SEEK_CUR: - npos = buffer->pos; - break; - case SEEK_END: - npos = buffer->size; - break; - case SEEK_SET: - npos = 0; - break; - default: - return -1; - } - - size_t opos = npos; - npos += offset; - - if ((offset > 0 && npos < opos) || (offset < 0 && npos > opos)) { - return -1; - } - - if (npos >= buffer->size) { - return -1; - } else { - buffer->pos = npos; - return 0; - } - -} - -int ucx_buffer_eof(UcxBuffer *buffer) { - return buffer->pos >= buffer->size; -} - -int ucx_buffer_extend(UcxBuffer *buffer, size_t len) { - size_t newcap = buffer->capacity; - - if (buffer->capacity + len < buffer->capacity) { - return -1; - } - - while (buffer->capacity + len > newcap) { - newcap <<= 1; - if (newcap < buffer->capacity) { - return -1; - } - } - - char *newspace = (char*)realloc(buffer->space, newcap); - if (newspace) { - memset(newspace+buffer->size, 0, newcap-buffer->size); - buffer->space = newspace; - buffer->capacity = newcap; - } else { - return -1; - } - - return 0; -} - -size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, - UcxBuffer *buffer) { - size_t len = size * nitems; - size_t required = buffer->pos + len; - if (buffer->pos > required) { - return 0; - } - - if (required > buffer->capacity) { - if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) { - if (ucx_buffer_extend(buffer, required - buffer->capacity)) { - return 0; - } - } else { - len = buffer->capacity - buffer->pos; - if (size > 1) { - len -= len%size; - } - } - } - - if (len == 0) { - return len; - } - - memcpy(buffer->space + buffer->pos, ptr, len); - buffer->pos += len; - if(buffer->pos > buffer->size) { - buffer->size = buffer->pos; - } - - return len / size; -} - -size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, - UcxBuffer *buffer) { - size_t len = size * nitems; - if (buffer->pos + len > buffer->size) { - len = buffer->size - buffer->pos; - if (size > 1) len -= len%size; - } - - if (len <= 0) { - return len; - } - - memcpy(ptr, buffer->space + buffer->pos, len); - buffer->pos += len; - - return len / size; -} - -int ucx_buffer_putc(UcxBuffer *buffer, int c) { - if(buffer->pos >= buffer->capacity) { - if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) { - if(ucx_buffer_extend(buffer, 1)) { - return EOF; - } - } else { - return EOF; - } - } - - c &= 0xFF; - buffer->space[buffer->pos] = (char) c; - buffer->pos++; - if(buffer->pos > buffer->size) { - buffer->size = buffer->pos; - } - return c; -} - -int ucx_buffer_getc(UcxBuffer *buffer) { - if (ucx_buffer_eof(buffer)) { - return EOF; - } else { - int c = buffer->space[buffer->pos]; - buffer->pos++; - return c; - } -} - -size_t ucx_buffer_puts(UcxBuffer *buffer, char *str) { - return ucx_buffer_write((const void*)str, 1, strlen(str), buffer); -}
--- a/ucx/buffer.h Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,270 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file buffer.h - * - * Advanced buffer implementation. - * - * Instances of UcxBuffer can be used to read from or to write to like one - * would do with a stream. This allows the use of ucx_stream_copy() to copy - * contents from one buffer to another. - * - * Some features for convenient use of the buffer - * can be enabled. See the documentation of the macro constants for more - * information. - * - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_BUFFER_H -#define UCX_BUFFER_H - -#include "ucx.h" -#include <sys/types.h> -#include <stdio.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * No buffer features enabled (all flags cleared). - */ -#define UCX_BUFFER_DEFAULT 0x00 - -/** - * If this flag is enabled, the buffer will automatically free its contents. - */ -#define UCX_BUFFER_AUTOFREE 0x01 - -/** - * If this flag is enabled, the buffer will automatically extends its capacity. - */ -#define UCX_BUFFER_AUTOEXTEND 0x02 - -/** UCX Buffer. */ -typedef struct { - /** A pointer to the buffer contents. */ - char *space; - /** Current position of the buffer. */ - size_t pos; - /** Current capacity (i.e. maximum size) of the buffer. */ - size_t capacity; - /** Current size of the buffer content. */ - size_t size; - /** - * Flag register for buffer features. - * @see #UCX_BUFFER_DEFAULT - * @see #UCX_BUFFER_AUTOFREE - * @see #UCX_BUFFER_AUTOEXTEND - */ - int flags; -} UcxBuffer; - -/** - * Creates a new buffer. - * - * <b>Note:</b> you may provide <code>NULL</code> as argument for - * <code>space</code>. Then this function will allocate the space and enforce - * the #UCX_BUFFER_AUTOFREE flag. - * - * @param space pointer to the memory area, or <code>NULL</code> to allocate - * new memory - * @param capacity the capacity of the buffer - * @param flags buffer features (see UcxBuffer.flags) - * @return the new buffer - */ -UcxBuffer *ucx_buffer_new(void *space, size_t capacity, int flags); - -/** - * Destroys a buffer. - * - * If the #UCX_BUFFER_AUTOFREE feature is enabled, the contents of the buffer - * are also freed. - * - * @param buffer the buffer to destroy - */ -void ucx_buffer_free(UcxBuffer* buffer); - -/** - * Creates a new buffer and fills it with extracted content from another buffer. - * - * <b>Note:</b> the #UCX_BUFFER_AUTOFREE feature is enforced for the new buffer. - * - * @param src the source buffer - * @param start the start position of extraction - * @param length the count of bytes to extract (must not be zero) - * @param flags feature mask for the new buffer - * @return a new buffer containing the extraction - */ -UcxBuffer* ucx_buffer_extract(UcxBuffer *src, - size_t start, size_t length, int flags); - -/** - * A shorthand macro for the full extraction of the buffer. - * - * @param src the source buffer - * @param flags feature mask for the new buffer - * @return a new buffer with the extracted content - */ -#define ucx_buffer_clone(src,flags) \ - ucx_buffer_extract(src, 0, (src)->capacity, flags) - -/** - * Moves the position of the buffer. - * - * The new position is relative to the <code>whence</code> argument. - * - * SEEK_SET marks the start of the buffer. - * SEEK_CUR marks the current position. - * SEEK_END marks the end of the buffer. - * - * With an offset of zero, this function sets the buffer position to zero - * (SEEK_SET), the buffer size (SEEK_END) or leaves the buffer position - * unchanged (SEEK_CUR). - * - * @param buffer - * @param offset position offset relative to <code>whence</code> - * @param whence one of SEEK_SET, SEEK_CUR or SEEK_END - * @return 0 on success, non-zero if the position is invalid - * - */ -int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence); - -/** - * Clears the buffer by resetting the position and deleting the data. - * - * The data is deleted by a zeroing it with call to <code>memset()</code>. - * - * @param buffer the buffer to be cleared - */ -#define ucx_buffer_clear(buffer) memset(buffer->space, 0, buffer->size); \ - buffer->size = 0; buffer->pos = 0; - -/** - * Tests, if the buffer position has exceeded the buffer capacity. - * - * @param buffer the buffer to test - * @return non-zero, if the current buffer position has exceeded the last - * available byte of the buffer. - */ -int ucx_buffer_eof(UcxBuffer *buffer); - - -/** - * Extends the capacity of the buffer. - * - * <b>Note:</b> The buffer capacity increased by a power of two. I.e. - * the buffer capacity is doubled, as long as it would not hold the current - * content plus the additional required bytes. - * - * <b>Attention:</b> the argument provided is the number of <i>additional</i> - * bytes the buffer shall hold. It is <b>NOT</b> the total number of bytes the - * buffer shall hold. - * - * @param buffer the buffer to extend - * @param additional_bytes the number of additional bytes the buffer shall - * <i>at least</i> hold - * @return 0 on success or a non-zero value on failure - */ -int ucx_buffer_extend(UcxBuffer *buffer, size_t additional_bytes); - -/** - * Writes data to a UcxBuffer. - * - * The position of the buffer is increased by the number of bytes written. - * - * @param ptr a pointer to the memory area containing the bytes to be written - * @param size the length of one element - * @param nitems the element count - * @param buffer the UcxBuffer to write to - * @return the total count of bytes written - */ -size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, - UcxBuffer *buffer); - -/** - * Reads data from a UcxBuffer. - * - * The position of the buffer is increased by the number of bytes read. - * - * @param ptr a pointer to the memory area where to store the read data - * @param size the length of one element - * @param nitems the element count - * @param buffer the UcxBuffer to read from - * @return the total number of elements read - */ -size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, - UcxBuffer *buffer); - -/** - * Writes a character to a buffer. - * - * The least significant byte of the argument is written to the buffer. If the - * end of the buffer is reached and #UCX_BUFFER_AUTOEXTEND feature is enabled, - * the buffer capacity is extended by ucx_buffer_extend(). If the feature is - * disabled or buffer extension fails, <code>EOF</code> is returned. - * - * On successful write the position of the buffer is increased. - * - * @param buffer the buffer to write to - * @param c the character to write as <code>int</code> value - * @return the byte that has bean written as <code>int</code> value or - * <code>EOF</code> when the end of the stream is reached and automatic - * extension is not enabled or not possible - */ -int ucx_buffer_putc(UcxBuffer *buffer, int c); - -/** - * Gets a character from a buffer. - * - * The current position of the buffer is increased after a successful read. - * - * @param buffer the buffer to read from - * @return the character as <code>int</code> value or <code>EOF</code>, if the - * end of the buffer is reached - */ -int ucx_buffer_getc(UcxBuffer *buffer); - -/** - * Writes a string to a buffer. - * - * @param buffer the buffer - * @param str the string - * @return the number of bytes written - */ -size_t ucx_buffer_puts(UcxBuffer *buffer, char *str); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_BUFFER_H */ -
--- a/ucx/list.c Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,370 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "list.h" - -UcxList *ucx_list_clone(UcxList *l, copy_func fnc, void *data) { - return ucx_list_clone_a(ucx_default_allocator(), l, fnc, data); -} - -UcxList *ucx_list_clone_a(UcxAllocator *alloc, UcxList *l, - copy_func fnc, void *data) { - UcxList *ret = NULL; - while (l) { - if (fnc) { - ret = ucx_list_append_a(alloc, ret, fnc(l->data, data)); - } else { - ret = ucx_list_append_a(alloc, ret, l->data); - } - l = l->next; - } - return ret; -} - -int ucx_list_equals(const UcxList *l1, const UcxList *l2, - cmp_func fnc, void* data) { - if (l1 == l2) return 1; - - while (l1 != NULL && l2 != NULL) { - if (fnc == NULL) { - if (l1->data != l2->data) return 0; - } else { - if (fnc(l1->data, l2->data, data) != 0) return 0; - } - l1 = l1->next; - l2 = l2->next; - } - - return (l1 == NULL && l2 == NULL); -} - -void ucx_list_free(UcxList *l) { - ucx_list_free_a(ucx_default_allocator(), l); -} - -void ucx_list_free_a(UcxAllocator *alloc, UcxList *l) { - UcxList *e = l, *f; - while (e != NULL) { - f = e; - e = e->next; - alfree(alloc, f); - } -} - -void ucx_list_free_content(UcxList* list, ucx_destructor destr) { - while (list != NULL) { - destr(list->data); - list = list->next; - } -} - -UcxList *ucx_list_append(UcxList *l, void *data) { - return ucx_list_append_a(ucx_default_allocator(), l, data); -} - -UcxList *ucx_list_append_a(UcxAllocator *alloc, UcxList *l, void *data) { - UcxList *nl = (UcxList*) almalloc(alloc, sizeof(UcxList)); - if (!nl) { - return NULL; - } - - nl->data = data; - nl->next = NULL; - if (l) { - UcxList *t = ucx_list_last(l); - t->next = nl; - nl->prev = t; - return l; - } else { - nl->prev = NULL; - return nl; - } -} - -UcxList *ucx_list_append_once(UcxList *l, void *data, - cmp_func cmpfnc, void *cmpdata) { - return ucx_list_append_once_a(ucx_default_allocator(), l, - data, cmpfnc, cmpdata); -} - -UcxList *ucx_list_append_once_a(UcxAllocator *alloc, UcxList *l, void *data, - cmp_func cmpfnc, void *cmpdata) { - - UcxList *last = NULL; - { - UcxList *e = l; - while (e) { - if (cmpfnc(e->data, data, cmpdata) == 0) { - return l; - } - last = e; - e = e->next; - } - } - - UcxList *nl = ucx_list_append_a(alloc, NULL, data); - if (!nl) { - return NULL; - } - - if (last == NULL) { - return nl; - } else { - nl->prev = last; - last->next = nl; - return l; - } -} - -UcxList *ucx_list_prepend(UcxList *l, void *data) { - return ucx_list_prepend_a(ucx_default_allocator(), l, data); -} - -UcxList *ucx_list_prepend_a(UcxAllocator *alloc, UcxList *l, void *data) { - UcxList *nl = ucx_list_append_a(alloc, NULL, data); - if (!nl) { - return NULL; - } - l = ucx_list_first(l); - - if (l) { - nl->next = l; - l->prev = nl; - } - return nl; -} - -UcxList *ucx_list_concat(UcxList *l1, UcxList *l2) { - if (l1) { - UcxList *last = ucx_list_last(l1); - last->next = l2; - if (l2) { - l2->prev = last; - } - return l1; - } else { - return l2; - } -} - -UcxList *ucx_list_last(const UcxList *l) { - if (l == NULL) return NULL; - - const UcxList *e = l; - while (e->next != NULL) { - e = e->next; - } - return (UcxList*)e; -} - -ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem) { - ssize_t index = 0; - while (list) { - if (list == elem) { - return index; - } - list = list->next; - index++; - } - return -1; -} - -UcxList *ucx_list_get(const UcxList *l, size_t index) { - if (l == NULL) return NULL; - - const UcxList *e = l; - while (e->next && index > 0) { - e = e->next; - index--; - } - - return (UcxList*)(index == 0 ? e : NULL); -} - -ssize_t ucx_list_find(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) { - ssize_t index = 0; - UCX_FOREACH(e, l) { - if (fnc) { - if (fnc(elem, e->data, cmpdata) == 0) { - return index; - } - } else { - if (elem == e->data) { - return index; - } - } - index++; - } - return -1; -} - -int ucx_list_contains(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) { - return ucx_list_find(l, elem, fnc, cmpdata) > -1; -} - -size_t ucx_list_size(const UcxList *l) { - if (l == NULL) return 0; - - const UcxList *e = l; - size_t s = 1; - while (e->next != NULL) { - e = e->next; - s++; - } - - return s; -} - -static UcxList *ucx_list_sort_merge(int length, - UcxList* restrict ls, UcxList* restrict le, UcxList* restrict re, - cmp_func fnc, void* data) { - - UcxList** sorted = (UcxList**) malloc(sizeof(UcxList*)*length); - UcxList *rc, *lc; - - lc = ls; rc = le; - int n = 0; - while (lc && lc != le && rc != re) { - if (fnc(lc->data, rc->data, data) <= 0) { - sorted[n] = lc; - lc = lc->next; - } else { - sorted[n] = rc; - rc = rc->next; - } - n++; - } - while (lc && lc != le) { - sorted[n] = lc; - lc = lc->next; - n++; - } - while (rc && rc != re) { - sorted[n] = rc; - rc = rc->next; - n++; - } - - // Update pointer - sorted[0]->prev = NULL; - for (int i = 0 ; i < length-1 ; i++) { - sorted[i]->next = sorted[i+1]; - sorted[i+1]->prev = sorted[i]; - } - sorted[length-1]->next = NULL; - - UcxList *ret = sorted[0]; - free(sorted); - return ret; -} - -UcxList *ucx_list_sort(UcxList *l, cmp_func fnc, void *data) { - if (l == NULL) { - return NULL; - } - - UcxList *lc; - int ln = 1; - - UcxList *restrict ls = l, *restrict le, *restrict re; - - // check how many elements are already sorted - lc = ls; - while (lc->next != NULL && fnc(lc->next->data, lc->data, data) > 0) { - lc = lc->next; - ln++; - } - le = lc->next; - - if (le == NULL) { - return l; // this list is already sorted :) - } else { - UcxList *rc; - int rn = 1; - rc = le; - // skip already sorted elements - while (rc->next != NULL && fnc(rc->next->data, rc->data, data) > 0) { - rc = rc->next; - rn++; - } - re = rc->next; - - // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them - UcxList *sorted = ucx_list_sort_merge(ln+rn, - ls, le, re, - fnc, data); - - // Something left? Sort it! - size_t remainder_length = ucx_list_size(re); - if (remainder_length > 0) { - UcxList *remainder = ucx_list_sort(re, fnc, data); - - // merge sorted list with (also sorted) remainder - l = ucx_list_sort_merge(ln+rn+remainder_length, - sorted, remainder, NULL, fnc, data); - } else { - // no remainder - we've got our sorted list - l = sorted; - } - - return l; - } -} - -UcxList *ucx_list_first(const UcxList *l) { - if (!l) { - return NULL; - } - - const UcxList *e = l; - while (e->prev) { - e = e->prev; - } - return (UcxList *)e; -} - -UcxList *ucx_list_remove(UcxList *l, UcxList *e) { - return ucx_list_remove_a(ucx_default_allocator(), l, e); -} - -UcxList *ucx_list_remove_a(UcxAllocator *alloc, UcxList *l, UcxList *e) { - if (l == e) { - l = e->next; - } - - if (e->next) { - e->next->prev = e->prev; - } - - if (e->prev) { - e->prev->next = e->next; - } - - alfree(alloc, e); - return l; -}
--- a/ucx/list.h Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,428 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/** - * Doubly linked list implementation. - * - * @file list.h - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_LIST_H -#define UCX_LIST_H - -#include "ucx.h" -#include "allocator.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Loop statement for UCX lists. - * - * The first argument is the name of the iteration variable. The scope of - * this variable is limited to the <code>UCX_FOREACH</code> statement. - * - * The second argument is a pointer to the list. In most cases this will be the - * pointer to the first element of the list, but it may also be an arbitrary - * element of the list. The iteration will then start with that element. - * - * @param list The first element of the list - * @param elem The variable name of the element - */ -#define UCX_FOREACH(elem,list) \ - for (UcxList* elem = list ; elem != NULL ; elem = elem->next) - -/** - * UCX list type. - * @see UcxList - */ -typedef struct UcxList UcxList; - -/** - * UCX list structure. - */ -struct UcxList { - /** - * List element payload. - */ - void *data; - /** - * Pointer to the next list element or <code>NULL</code>, if this is the - * last element. - */ - UcxList *next; - /** - * Pointer to the previous list element or <code>NULL</code>, if this is - * the first element. - */ - UcxList *prev; -}; - -/** - * Creates an element-wise copy of a list. - * - * This function clones the specified list by creating new list elements and - * copying the data with the specified copy_func(). If no copy_func() is - * specified, a shallow copy is created and the new list will reference the - * same data as the source list. - * - * @param list the list to copy - * @param cpyfnc a pointer to the function that shall copy an element (may be - * <code>NULL</code>) - * @param data additional data for the copy_func() - * @return a pointer to the copy - */ -UcxList *ucx_list_clone(UcxList *list, copy_func cpyfnc, void* data); - -/** - * Creates an element-wise copy of a list using a UcxAllocator. - * - * See ucx_list_clone() for details. - * - * You might want to pass the allocator via the <code>data</code> parameter, - * to access it within the copy function for making deep copies. - * - * @param allocator the allocator to use - * @param list the list to copy - * @param cpyfnc a pointer to the function that shall copy an element (may be - * <code>NULL</code>) - * @param data additional data for the copy_func() - * @return a pointer to the copy - * @see ucx_list_clone() - */ -UcxList *ucx_list_clone_a(UcxAllocator *allocator, UcxList *list, - copy_func cpyfnc, void* data); - -/** - * Compares two UCX lists element-wise by using a compare function. - * - * Each element of the two specified lists are compared by using the specified - * compare function and the additional data. The type and content of this - * additional data depends on the cmp_func() used. - * - * If the list pointers denote elements within a list, the lists are compared - * starting with the denoted elements. Thus any previous elements are not taken - * into account. This might be useful to check, if certain list tails match - * each other. - * - * @param list1 the first list - * @param list2 the second list - * @param cmpfnc the compare function - * @param data additional data for the compare function - * @return 1, if and only if the two lists equal element-wise, 0 otherwise - */ -int ucx_list_equals(const UcxList *list1, const UcxList *list2, - cmp_func cmpfnc, void* data); - -/** - * Destroys the entire list. - * - * The members of the list are not automatically freed, so ensure they are - * otherwise referenced or destroyed by ucx_list_free_contents(). - * Otherwise, a memory leak is likely to occur. - * - * <b>Caution:</b> the argument <b>MUST</b> denote an entire list (i.e. a call - * to ucx_list_first() on the argument must return the argument itself) - * - * @param list the list to free - * @see ucx_list_free_contents() - */ -void ucx_list_free(UcxList *list); - -/** - * Destroys the entire list using a UcxAllocator. - * - * See ucx_list_free() for details. - * - * @param allocator the allocator to use - * @param list the list to free - * @see ucx_list_free() - */ -void ucx_list_free_a(UcxAllocator *allocator, UcxList *list); - -/** - * Destroys the contents of the specified list by calling the specified - * destructor on each of them. - * - * Note, that the contents are not usable afterwards and the list should be - * destroyed with ucx_list_free(). - * - * @param list the list for which the contents shall be freed - * @param destr the destructor function (e.g. stdlib free()) - * @see ucx_list_free() - */ -void ucx_list_free_content(UcxList* list, ucx_destructor destr); - - -/** - * Inserts an element at the end of the list. - * - * This is generally an O(n) operation, as the end of the list is retrieved with - * ucx_list_last(). - * - * @param list the list where to append the data, or <code>NULL</code> to - * create a new list - * @param data the data to insert - * @return <code>list</code>, if it is not <code>NULL</code> or a pointer to - * the newly created list otherwise - */ -UcxList *ucx_list_append(UcxList *list, void *data); - -/** - * Inserts an element at the end of the list using a UcxAllocator. - * - * See ucx_list_append() for details. - * - * @param allocator the allocator to use - * @param list the list where to append the data, or <code>NULL</code> to - * create a new list - * @param data the data to insert - * @return <code>list</code>, if it is not <code>NULL</code> or a pointer to - * the newly created list otherwise - * @see ucx_list_append() - */ -UcxList *ucx_list_append_a(UcxAllocator *allocator, UcxList *list, void *data); - -/** - * Inserts an element at the end of the list, if it is not present in the list. - * - * - * @param list the list where to append the data, or <code>NULL</code> to - * create a new list - * @param data the data to insert - * @param cmpfnc the compare function - * @param cmpdata additional data for the compare function - * @return <code>list</code>, if it is not <code>NULL</code> or a pointer to - * the newly created list otherwise - * @see ucx_list_append() - */ -UcxList *ucx_list_append_once(UcxList *list, void *data, - cmp_func cmpfnc, void *cmpdata); - -/** - * Inserts an element at the end of the list, if it is not present in the list, - * using a UcxAllocator. - * - * See ucx_list_append() for details. - * - * @param allocator the allocator to use - * @param list the list where to append the data, or <code>NULL</code> to - * create a new list - * @param data the data to insert - * @param cmpfnc the compare function - * @param cmpdata additional data for the compare function - * @return <code>list</code>, if it is not <code>NULL</code> or a pointer to - * the newly created list otherwise - * @see ucx_list_append_a() - */ -UcxList *ucx_list_append_once_a(UcxAllocator *allocator, - UcxList *list, void *data, cmp_func cmpfnc, void *cmpdata); - -/** - * Inserts an element at the beginning of the list. - * - * You <i>should</i> overwrite the old list pointer by calling - * <code>mylist = ucx_list_prepend(mylist, mydata);</code>. However, you may - * also perform successive calls of ucx_list_prepend() on the same list pointer, - * as this function always searchs for the head of the list with - * ucx_list_first(). - * - * @param list the list where to insert the data or <code>NULL</code> to create - * a new list - * @param data the data to insert - * @return a pointer to the new list head - */ -UcxList *ucx_list_prepend(UcxList *list, void *data); - -/** - * Inserts an element at the beginning of the list using a UcxAllocator. - * - * See ucx_list_prepend() for details. - * - * @param allocator the allocator to use - * @param list the list where to insert the data or <code>NULL</code> to create - * a new list - * @param data the data to insert - * @return a pointer to the new list head - * @see ucx_list_prepend() - */ -UcxList *ucx_list_prepend_a(UcxAllocator *allocator, UcxList *list, void *data); - -/** - * Concatenates two lists. - * - * Either of the two arguments may be <code>NULL</code>. - * - * This function modifies the references to the next/previous element of - * the last/first element of <code>list1</code>/<code> - * list2</code>. - * - * @param list1 first list - * @param list2 second list - * @return if <code>list1</code> is <code>NULL</code>, <code>list2</code> is - * returned, otherwise <code>list1</code> is returned - */ -UcxList *ucx_list_concat(UcxList *list1, UcxList *list2); - -/** - * Returns the first element of a list. - * - * If the argument is the list pointer, it is directly returned. Otherwise - * this function traverses to the first element of the list and returns the - * list pointer. - * - * @param elem one element of the list - * @return the first element of the list, the specified element is a member of - */ -UcxList *ucx_list_first(const UcxList *elem); - -/** - * Returns the last element of a list. - * - * If the argument has no successor, it is the last element and therefore - * directly returned. Otherwise this function traverses to the last element of - * the list and returns it. - * - * @param elem one element of the list - * @return the last element of the list, the specified element is a member of - */ -UcxList *ucx_list_last(const UcxList *elem); - -/** - * Returns the list element at the specified index. - * - * @param list the list to retrieve the element from - * @param index index of the element to return - * @return the element at the specified index or <code>NULL</code>, if the - * index is greater than the list size - */ -UcxList *ucx_list_get(const UcxList *list, size_t index); - -/** - * Returns the index of an element. - * - * @param list the list where to search for the element - * @param elem the element to find - * @return the index of the element or -1 if the list does not contain the - * element - */ -ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem); - -/** - * Returns the element count of the list. - * - * @param list the list whose elements are counted - * @return the element count - */ -size_t ucx_list_size(const UcxList *list); - -/** - * Returns the index of an element containing the specified data. - * - * This function uses a cmp_func() to compare the data of each list element - * with the specified data. If no cmp_func is provided, the pointers are - * compared. - * - * If the list contains the data more than once, the index of the first - * occurrence is returned. - * - * @param list the list where to search for the data - * @param elem the element data - * @param cmpfnc the compare function - * @param data additional data for the compare function - * @return the index of the element containing the specified data or -1 if the - * data is not found in this list - */ -ssize_t ucx_list_find(UcxList *list, void *elem, cmp_func cmpfnc, void *data); - -/** - * Checks, if a list contains a specific element. - * - * An element is found, if ucx_list_find() returns a value greater than -1. - * - * @param list the list where to search for the data - * @param elem the element data - * @param cmpfnc the compare function - * @param data additional data for the compare function - * @return 1, if and only if the list contains the specified element data - * @see ucx_list_find() - */ -int ucx_list_contains(UcxList *list, void *elem, cmp_func cmpfnc, void *data); - -/** - * Sorts a UcxList with natural merge sort. - * - * This function uses O(n) additional temporary memory for merge operations - * that is automatically freed after each merge. - * - * As the head of the list might change, you <b>MUST</b> call this function - * as follows: <code>mylist = ucx_list_sort(mylist, mycmpfnc, mydata);</code>. - * - * @param list the list to sort - * @param cmpfnc the function that shall be used to compare the element data - * @param data additional data for the cmp_func() - * @return the sorted list - */ -UcxList *ucx_list_sort(UcxList *list, cmp_func cmpfnc, void *data); - -/** - * Removes an element from the list. - * - * If the first element is removed, the list pointer changes. So it is - * <i>highly recommended</i> to <i>always</i> update the pointer by calling - * <code>mylist = ucx_list_remove(mylist, myelem);</code>. - * - * @param list the list from which the element shall be removed - * @param element the element to remove - * @return returns the updated list pointer or <code>NULL</code>, if the list - * is now empty - */ -UcxList *ucx_list_remove(UcxList *list, UcxList *element); - -/** - * Removes an element from the list using a UcxAllocator. - * - * See ucx_list_remove() for details. - * - * @param allocator the allocator to use - * @param list the list from which the element shall be removed - * @param element the element to remove - * @return returns the updated list pointer or <code>NULL</code>, if the list - * @see ucx_list_remove() - */ -UcxList *ucx_list_remove_a(UcxAllocator *allocator, UcxList *list, - UcxList *element); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_LIST_H */ -
--- a/ucx/logging.c Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "logging.h" -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <time.h> - -UcxLogger *ucx_logger_new(void *stream, unsigned int level, unsigned int mask) { - UcxLogger *logger = (UcxLogger*) malloc(sizeof(UcxLogger)); - if (logger != NULL) { - logger->stream = stream; - logger->writer = (write_func)fwrite; - logger->dateformat = (char*) "%F %T %z "; - logger->level = level; - logger->mask = mask; - logger->levels = ucx_map_new(8); - - unsigned int l; - l = UCX_LOGGER_ERROR; - ucx_map_int_put(logger->levels, l, (void*) "[ERROR]"); - l = UCX_LOGGER_WARN; - ucx_map_int_put(logger->levels, l, (void*) "[WARNING]"); - l = UCX_LOGGER_INFO; - ucx_map_int_put(logger->levels, l, (void*) "[INFO]"); - l = UCX_LOGGER_TRACE; - ucx_map_int_put(logger->levels, l, (void*) "[TRACE]"); - } - - return logger; -} - -void ucx_logger_free(UcxLogger *logger) { - ucx_map_free(logger->levels); - free(logger); -} - -// estimated max. message length (documented) -#define UCX_LOGGER_MSGMAX 4096 - -void ucx_logger_logf(UcxLogger *logger, unsigned int level, const char* file, - const unsigned int line, const char *format, ...) { - if (level <= logger->level) { - char msg[UCX_LOGGER_MSGMAX]; - char *text; - size_t k = 0; - size_t n; - - if ((logger->mask & UCX_LOGGER_LEVEL) > 0) { - text = (char*) ucx_map_int_get(logger->levels, level); - n = strlen(text); - n = n > 256 ? 256 : n; - memcpy(msg+k, text, n); - k += n; - msg[k++] = ' '; - } - if ((logger->mask & UCX_LOGGER_TIMESTAMP) > 0) { - time_t now = time(NULL); - k += strftime(msg+k, 128, logger->dateformat, localtime(&now)); - } - if ((logger->mask & UCX_LOGGER_SOURCE) > 0) { - n = strlen(file); - memcpy(msg+k, file, n); - k += n; - k += sprintf(msg+k, ":%u ", line); - } - - msg[k++] = '-'; msg[k++] = ' '; - - va_list args; - va_start (args, format); - k += vsnprintf(msg+k, UCX_LOGGER_MSGMAX-k-1, format, args); - va_end (args); - - msg[k++] = '\n'; - - logger->writer(msg, 1, k, logger->stream); - } -}
--- a/ucx/logging.h Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/** - * Logging API. - * - * @file logging.h - * @author Mike Becker, Olaf Wintermann - */ -#ifndef UCX_LOGGING_H -#define UCX_LOGGING_H - -#include "ucx.h" -#include "map.h" -#include "string.h" -#include <stdio.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* leave enough space for custom log levels */ - -/** Log level for error messages. */ -#define UCX_LOGGER_ERROR 0x00 - -/** Log level for warning messages. */ -#define UCX_LOGGER_WARN 0x10 - -/** Log level for information messages. */ -#define UCX_LOGGER_INFO 0x20 - -/** Log level for debug messages. */ -#define UCX_LOGGER_DEBUG 0x30 - -/** Log level for trace messages. */ -#define UCX_LOGGER_TRACE 0x40 - -/** - * Output flag for the log level. - * If this flag is set, the log message will contain the log level. - * @see UcxLogger.mask - */ -#define UCX_LOGGER_LEVEL 0x01 - -/** - * Output flag for the timestmap. - * If this flag is set, the log message will contain the timestmap. - * @see UcxLogger.mask - */ -#define UCX_LOGGER_TIMESTAMP 0x02 - -/** - * Output flag for the source. - * If this flag is set, the log message will contain the source file and line - * number. - * @see UcxLogger.mask - */ -#define UCX_LOGGER_SOURCE 0x04 - -/** - * The UCX Logger object. - */ -typedef struct { - /** The stream this logger writes its messages to.*/ - void *stream; - - /** - * The write function that shall be used. - * For standard file or stdout loggers this might be standard fwrite - * (default). - */ - write_func writer; - - /** - * The date format for timestamp outputs including the delimiter - * (default: <code>"%F %T %z "</code>). - * @see UCX_LOGGER_TIMESTAMP - */ - char *dateformat; - - /** - * The level, this logger operates on. - * If a log command is issued, the message will only be logged, if the log - * level of the message is less or equal than the log level of the logger. - */ - unsigned int level; - - /** - * A configuration mask for automatic output. - * For each flag that is set, the logger automatically outputs some extra - * information like the timestamp or the source file and line number. - * See the documentation for the flags for details. - */ - unsigned int mask; - - /** - * A map of valid log levels for this logger. - * - * The keys represent all valid log levels and the values provide string - * representations, that are used, if the UCX_LOGGER_LEVEL flag is set. - * - * The exact data types are <code>unsigned int</code> for the key and - * <code>const char*</code> for the value. - * - * @see UCX_LOGGER_LEVEL - */ - UcxMap* levels; -} UcxLogger; - -/** - * Creates a new logger. - * @param stream the stream, which the logger shall write to - * @param level the level on which the logger shall operate - * @param mask configuration mask (cf. UcxLogger.mask) - * @return a new logger object - */ -UcxLogger *ucx_logger_new(void *stream, unsigned int level, unsigned int mask); - -/** - * Destroys the logger. - * - * The map containing the valid log levels is also automatically destroyed. - * - * @param logger the logger to destroy - */ -void ucx_logger_free(UcxLogger* logger); - -/** - * Internal log function - use macros instead. - * - * This function uses the <code>format</code> and variadic arguments for a - * printf()-style output of the log message. - * - * Dependent on the UcxLogger.mask some information is prepended. The complete - * format is: - * - * <code>[LEVEL] [TIMESTAMP] [SOURCEFILE]:[LINENO] message</code> - * - * <b>Attention:</b> the message (including automatically generated information) - * is limited to 4096 characters. The level description is limited to - * 256 characters and the timestamp string is limited to 128 characters. - * - * @param logger the logger to use - * @param level the level to log on - * @param file information about the source file - * @param line information about the source line number - * @param format format string - * @param ... arguments - * @see ucx_logger_log() - */ -void ucx_logger_logf(UcxLogger *logger, unsigned int level, const char* file, - const unsigned int line, const char* format, ...); - -/** - * Logs a message at the specified level. - * @param logger the logger to use - * @param level the level to log the message on - * @param ... format string and arguments - * @see ucx_logger_logf() - */ -#define ucx_logger_log(logger, level, ...) \ - ucx_logger_logf(logger, level, __FILE__, __LINE__, __VA_ARGS__) - -/** - * Shortcut for logging an error message. - * @param logger the logger to use - * @param ... format string and arguments - * @see ucx_logger_logf() - */ -#define ucx_logger_error(logger, ...) \ - ucx_logger_log(logger, UCX_LOGGER_ERROR, __VA_ARGS__) - -/** - * Shortcut for logging an information message. - * @param logger the logger to use - * @param ... format string and arguments - * @see ucx_logger_logf() - */ -#define ucx_logger_info(logger, ...) \ - ucx_logger_log(logger, UCX_LOGGER_INFO, __VA_ARGS__) - -/** - * Shortcut for logging a warning message. - * @param logger the logger to use - * @param ... format string and arguments - * @see ucx_logger_logf() - */ -#define ucx_logger_warn(logger, ...) \ - ucx_logger_log(logger, UCX_LOGGER_WARN, __VA_ARGS__) - -/** - * Shortcut for logging a debug message. - * @param logger the logger to use - * @param ... format string and arguments - * @see ucx_logger_logf() - */ -#define ucx_logger_debug(logger, ...) \ - ucx_logger_log(logger, UCX_LOGGER_DEBUG, __VA_ARGS__) - -/** - * Shortcut for logging a trace message. - * @param logger the logger to use - * @param ... format string and arguments - * @see ucx_logger_logf() - */ -#define ucx_logger_trace(logger, ...) \ - ucx_logger_log(logger, UCX_LOGGER_TRACE, __VA_ARGS__) - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_LOGGING_H */
--- a/ucx/map.c Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,328 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stdlib.h> -#include <string.h> - -#include "map.h" - -UcxMap *ucx_map_new(size_t size) { - return ucx_map_new_a(NULL, size); -} - -UcxMap *ucx_map_new_a(UcxAllocator *allocator, size_t size) { - if(size == 0) { - size = 16; - } - - if(!allocator) { - allocator = ucx_default_allocator(); - } - - UcxMap *map = (UcxMap*)almalloc(allocator, sizeof(UcxMap)); - if (!map) { - return NULL; - } - - map->allocator = allocator; - map->map = (UcxMapElement**)alcalloc( - allocator, size, sizeof(UcxMapElement*)); - if(map->map == NULL) { - alfree(allocator, map); - return NULL; - } - map->size = size; - map->count = 0; - - return map; -} - -static void ucx_map_free_elmlist_contents(UcxMap *map) { - for (size_t n = 0 ; n < map->size ; n++) { - UcxMapElement *elem = map->map[n]; - if (elem != NULL) { - do { - UcxMapElement *next = elem->next; - alfree(map->allocator, elem->key.data); - alfree(map->allocator, elem); - elem = next; - } while (elem != NULL); - } - } -} - -void ucx_map_free(UcxMap *map) { - ucx_map_free_elmlist_contents(map); - alfree(map->allocator, map->map); - alfree(map->allocator, map); -} - -void ucx_map_free_content(UcxMap *map, ucx_destructor destr) { - UcxMapIterator iter = ucx_map_iterator(map); - void *val; - UCX_MAP_FOREACH(key, val, iter) { - destr(val); - } -} - -void ucx_map_clear(UcxMap *map) { - if (map->count == 0) { - return; // nothing to do - } - ucx_map_free_elmlist_contents(map); - memset(map->map, 0, map->size*sizeof(UcxMapElement*)); - map->count = 0; -} - -int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to, - copy_func fnc, void *data) { - UcxMapIterator i = ucx_map_iterator(from); - void *value; - UCX_MAP_FOREACH(key, value, i) { - if (ucx_map_put(to, key, fnc ? fnc(value, data) : value)) { - return 1; - } - } - return 0; -} - -UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data) { - size_t bs = (map->count * 5) >> 1; - UcxMap *newmap = ucx_map_new(bs > map->size ? bs : map->size); - if (!newmap) { - return NULL; - } - ucx_map_copy(map, newmap, fnc, data); - return newmap; -} - -int ucx_map_rehash(UcxMap *map) { - size_t load = (map->size * 3) >> 2; - if (map->count > load) { - UcxMap oldmap; - oldmap.map = map->map; - oldmap.size = map->size; - oldmap.count = map->count; - oldmap.allocator = map->allocator; - - map->size = (map->count * 5) >> 1; - map->map = (UcxMapElement**)alcalloc( - map->allocator, map->size, sizeof(UcxMapElement*)); - if (!map->map) { - *map = oldmap; - return 1; - } - map->count = 0; - ucx_map_copy(&oldmap, map, NULL, NULL); - - /* free the UcxMapElement list of oldmap */ - ucx_map_free_elmlist_contents(&oldmap); - alfree(map->allocator, oldmap.map); - } - return 0; -} - -int ucx_map_put(UcxMap *map, UcxKey key, void *data) { - UcxAllocator *allocator = map->allocator; - - if (key.hash == 0) { - key.hash = ucx_hash((char*)key.data, key.len); - } - - size_t slot = key.hash%map->size; - UcxMapElement *restrict elm = map->map[slot]; - UcxMapElement *restrict prev = NULL; - - while (elm && elm->key.hash < key.hash) { - prev = elm; - elm = elm->next; - } - - if (!elm || elm->key.hash != key.hash) { - UcxMapElement *e = (UcxMapElement*)almalloc( - allocator, sizeof(UcxMapElement)); - if (!e) { - return -1; - } - e->key.data = NULL; - if (prev) { - prev->next = e; - } else { - map->map[slot] = e; - } - e->next = elm; - elm = e; - } - - if (!elm->key.data) { - void *kd = almalloc(allocator, key.len); - if (!kd) { - return -1; - } - memcpy(kd, key.data, key.len); - key.data = kd; - elm->key = key; - map->count++; - } - elm->data = data; - - return 0; -} - -void* ucx_map_get_and_remove(UcxMap *map, UcxKey key, _Bool remove) { - if(key.hash == 0) { - key.hash = ucx_hash((char*)key.data, key.len); - } - - size_t slot = key.hash%map->size; - UcxMapElement *restrict elm = map->map[slot]; - UcxMapElement *restrict pelm = NULL; - while (elm && elm->key.hash <= key.hash) { - if(elm->key.hash == key.hash) { - int n = (key.len > elm->key.len) ? elm->key.len : key.len; - if (memcmp(elm->key.data, key.data, n) == 0) { - void *data = elm->data; - if (remove) { - if (pelm) { - pelm->next = elm->next; - } else { - map->map[slot] = elm->next; - } - alfree(map->allocator, elm->key.data); - alfree(map->allocator, elm); - map->count--; - } - - return data; - } - } - pelm = elm; - elm = pelm->next; - } - - return NULL; -} - -void *ucx_map_get(UcxMap *map, UcxKey key) { - return ucx_map_get_and_remove(map, key, 0); -} - -void *ucx_map_remove(UcxMap *map, UcxKey key) { - return ucx_map_get_and_remove(map, key, 1); -} - -UcxKey ucx_key(void *data, size_t len) { - UcxKey key; - key.data = data; - key.len = len; - key.hash = ucx_hash((const char*) data, len); - return key; -} - - -int ucx_hash(const char *data, size_t len) { - /* murmur hash 2 */ - - int m = 0x5bd1e995; - int r = 24; - - int h = 25 ^ len; - - int i = 0; - while (len >= 4) { - int k = data[i + 0] & 0xFF; - k |= (data[i + 1] & 0xFF) << 8; - k |= (data[i + 2] & 0xFF) << 16; - k |= (data[i + 3] & 0xFF) << 24; - - k *= m; - k ^= k >> r; - k *= m; - - h *= m; - h ^= k; - - i += 4; - len -= 4; - } - - switch (len) { - case 3: h ^= (data[i + 2] & 0xFF) << 16; - /* no break */ - case 2: h ^= (data[i + 1] & 0xFF) << 8; - /* no break */ - case 1: h ^= (data[i + 0] & 0xFF); h *= m; - /* no break */ - } - - h ^= h >> 13; - h *= m; - h ^= h >> 15; - - return h; -} - -UcxMapIterator ucx_map_iterator(UcxMap *map) { - UcxMapIterator i; - i.map = map; - i.cur = NULL; - i.index = 0; - return i; -} - -int ucx_map_iter_next(UcxMapIterator *i, UcxKey *key, void **elm) { - UcxMapElement *e = i->cur; - - if (e) { - e = e->next; - } else { - e = i->map->map[0]; - } - - while (i->index < i->map->size) { - if (e) { - if (e->data) { - i->cur = e; - *elm = e->data; - *key = e->key; - return 1; - } - - e = e->next; - } else { - i->index++; - - if (i->index < i->map->size) { - e = i->map->map[i->index]; - } - } - } - - return 0; -} -
--- a/ucx/map.h Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,423 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file map.h - * - * Hash map implementation. - * - * This implementation uses murmur hash 2 and separate chaining with linked - * lists. - * - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_MAP_H -#define UCX_MAP_H - -#include "ucx.h" -#include "string.h" -#include "allocator.h" -#include <stdio.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Loop statement for UCX maps. - * - * The <code>key</code> variable is implicitly defined, but the - * <code>value</code> variable must be already declared as type information - * cannot be inferred. - * - * @param key the variable name for the key - * @param value the variable name for the value - * @param iter a UcxMapIterator - * @see ucx_map_iterator() - */ -#define UCX_MAP_FOREACH(key,value,iter) \ - for(UcxKey key;ucx_map_iter_next(&iter,&key, (void**)&value);) - -/** Type for the UCX map. @see UcxMap */ -typedef struct UcxMap UcxMap; - -/** Type for a key of a UcxMap. @see UcxKey */ -typedef struct UcxKey UcxKey; - -/** Type for an element of a UcxMap. @see UcxMapElement */ -typedef struct UcxMapElement UcxMapElement; - -/** Type for an iterator over a UcxMap. @see UcxMapIterator */ -typedef struct UcxMapIterator UcxMapIterator; - -/** Structure for the UCX map. */ -struct UcxMap { - /** An allocator that is used for the map elements. */ - UcxAllocator *allocator; - /** The array of map element lists. */ - UcxMapElement **map; - /** The size of the map is the length of the element list array. */ - size_t size; - /** The count of elements currently stored in this map. */ - size_t count; -}; - -/** Structure for a key of a UcxMap. */ -struct UcxKey { - /** The key data. */ - void *data; - /** The length of the key data. */ - size_t len; - /** The hash value of the key data. */ - int hash; -}; - -/** Structure for an element of a UcxMap. */ -struct UcxMapElement { - /** The value data. */ - void *data; - - /** A pointer to the next element in the current list. */ - UcxMapElement *next; - - /** The corresponding key. */ - UcxKey key; -}; - -/** Structure for an iterator over a UcxMap. */ -struct UcxMapIterator { - /** The map to iterate over. */ - UcxMap *map; - - /** The current map element. */ - UcxMapElement *cur; - - /** - * The current index of the element list array. - * <b>Attention: </b> this is <b>NOT</b> the element index! Do <b>NOT</b> - * manually iterate over the map by increasing this index. Use - * ucx_map_iter_next(). - * @see UcxMap.map*/ - size_t index; -}; - -/** - * Creates a new hash map with the specified size. - * @param size the size of the hash map - * @return a pointer to the new hash map - */ -UcxMap *ucx_map_new(size_t size); - -/** - * Creates a new hash map with the specified size using a UcxAllocator. - * @param allocator the allocator to use - * @param size the size of the hash map - * @return a pointer to the new hash map - */ -UcxMap *ucx_map_new_a(UcxAllocator *allocator, size_t size); - -/** - * Frees a hash map. - * - * <b>Note:</b> the contents are <b>not</b> freed, use ucx_map_free_content() - * before calling this function to achieve that. - * - * @param map the map to be freed - * @see ucx_map_free_content() - */ -void ucx_map_free(UcxMap *map); - -/** - * Frees the contents of a hash map. - * - * This is a convenience function that iterates over the map and passes all - * values to the specified destructor function (e.g. stdlib free()). - * - * You must ensure, that it is valid to pass each value in the map to the same - * destructor function. - * - * You should free or clear the map afterwards, as the contents will be invalid. - * - * @param map for which the contents shall be freed - * @param destr pointer to the destructor function - * @see ucx_map_free() - * @see ucx_map_clear() - */ -void ucx_map_free_content(UcxMap *map, ucx_destructor destr); - -/** - * Clears a hash map. - * - * <b>Note:</b> the contents are <b>not</b> freed, use ucx_map_free_content() - * before calling this function to achieve that. - * - * @param map the map to be cleared - * @see ucx_map_free_content() - */ -void ucx_map_clear(UcxMap *map); - - -/** - * Copies contents from a map to another map using a copy function. - * - * <b>Note:</b> The destination map does not need to be empty. However, if it - * contains data with keys that are also present in the source map, the contents - * are overwritten. - * - * @param from the source map - * @param to the destination map - * @param fnc the copy function or <code>NULL</code> if the pointer address - * shall be copied - * @param data additional data for the copy function - * @return 0 on success or a non-zero value on memory allocation errors - */ -int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to, - copy_func fnc, void *data); - -/** - * Clones the map and rehashes if necessary. - * - * <b>Note:</b> In contrast to ucx_map_rehash() the load factor is irrelevant. - * This function <i>always</i> ensures a new UcxMap.size of at least - * 2.5*UcxMap.count. - * - * @param map the map to clone - * @param fnc the copy function to use or <code>NULL</code> if the new and - * the old map shall share the data pointers - * @param data additional data for the copy function - * @return the cloned map - * @see ucx_map_copy() - */ -UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data); - -/** - * Increases size of the hash map, if necessary. - * - * The load value is 0.75*UcxMap.size. If the element count exceeds the load - * value, the map needs to be rehashed. Otherwise no action is performed and - * this function simply returns 0. - * - * The rehashing process ensures, that the UcxMap.size is at least - * 2.5*UcxMap.count. So there is enough room for additional elements without - * the need of another soon rehashing. - * - * You can use this function to dramatically increase access performance. - * - * @param map the map to rehash - * @return 1, if a memory allocation error occurred, 0 otherwise - */ -int ucx_map_rehash(UcxMap *map); - -/** - * Puts a key/value-pair into the map. - * - * @param map the map - * @param key the key - * @param value the value - * @return 0 on success, non-zero value on failure - */ -int ucx_map_put(UcxMap *map, UcxKey key, void *value); - -/** - * Retrieves a value by using a key. - * - * @param map the map - * @param key the key - * @return the value - */ -void* ucx_map_get(UcxMap *map, UcxKey key); - -/** - * Removes a key/value-pair from the map by using the key. - * - * @param map the map - * @param key the key - * @return the removed value - */ -void* ucx_map_remove(UcxMap *map, UcxKey key); - -/** - * Shorthand for putting data with a sstr_t key into the map. - * @param map the map - * @param key the key - * @param value the value - * @return 0 on success, non-zero value on failure - * @see ucx_map_put() - */ -#define ucx_map_sstr_put(map, key, value) \ - ucx_map_put(map, ucx_key(key.ptr, key.length), (void*)value) - -/** - * Shorthand for putting data with a C string key into the map. - * @param map the map - * @param key the key - * @param value the value - * @return 0 on success, non-zero value on failure - * @see ucx_map_put() - */ -#define ucx_map_cstr_put(map, key, value) \ - ucx_map_put(map, ucx_key((void*)key, strlen(key)), (void*)value) - -/** - * Shorthand for putting data with an integer key into the map. - * @param map the map - * @param key the key - * @param value the value - * @return 0 on success, non-zero value on failure - * @see ucx_map_put() - */ -#define ucx_map_int_put(map, key, value) \ - ucx_map_put(map, ucx_key((void*)&key, sizeof(key)), (void*)value) - -/** - * Shorthand for getting data from the map with a sstr_t key. - * @param map the map - * @param key the key - * @return the value - * @see ucx_map_get() - */ -#define ucx_map_sstr_get(map, key) \ - ucx_map_get(map, ucx_key(key.ptr, key.length)) - -/** - * Shorthand for getting data from the map with a C string key. - * @param map the map - * @param key the key - * @return the value - * @see ucx_map_get() - */ -#define ucx_map_cstr_get(map, key) \ - ucx_map_get(map, ucx_key((void*)key, strlen(key))) - -/** - * Shorthand for getting data from the map with an integer key. - * @param map the map - * @param key the key - * @return the value - * @see ucx_map_get() - */ -#define ucx_map_int_get(map, key) \ - ucx_map_get(map, ucx_key((void*)&key, sizeof(int))) - -/** - * Shorthand for removing data from the map with a sstr_t key. - * @param map the map - * @param key the key - * @return the removed value - * @see ucx_map_remove() - */ -#define ucx_map_sstr_remove(map, key) \ - ucx_map_remove(map, ucx_key(key.ptr, key.length)) - -/** - * Shorthand for removing data from the map with a C string key. - * @param map the map - * @param key the key - * @return the removed value - * @see ucx_map_remove() - */ -#define ucx_map_cstr_remove(map, key) \ - ucx_map_remove(map, ucx_key((void*)key, strlen(key))) - -/** - * Shorthand for removing data from the map with an integer key. - * @param map the map - * @param key the key - * @return the removed value - * @see ucx_map_remove() - */ -#define ucx_map_int_remove(map, key) \ - ucx_map_remove(map, ucx_key((void*)&key, sizeof(key))) - -/** - * Creates a UcxKey based on the given data. - * - * This function implicitly computes the hash. - * - * @param data the data for the key - * @param len the length of the data - * @return a UcxKey with implicitly computed hash - * @see ucx_hash() - */ -UcxKey ucx_key(void *data, size_t len); - -/** - * Computes a murmur hash-2. - * - * @param data the data to hash - * @param len the length of the data - * @return the murmur hash-2 of the data - */ -int ucx_hash(const char *data, size_t len); - -/** - * Creates an iterator for a map. - * - * <b>Note:</b> A UcxMapIterator iterates over all elements in all element - * lists successively. Therefore the order highly depends on the key hashes and - * may vary under different map sizes. So generally you may <b>NOT</b> rely on - * the iteration order. - * - * <b>Note:</b> The iterator is <b>NOT</b> initialized. You need to call - * ucx_map_iter_next() at least once before accessing any information. However, - * it is not recommended to access the fields of a UcxMapIterator directly. - * - * @param map the map to create the iterator for - * @return an iterator initialized on the first element of the - * first element list - * @see ucx_map_iter_next() - */ -UcxMapIterator ucx_map_iterator(UcxMap *map); - -/** - * Proceeds to the next element of the map (if any). - * - * Subsequent calls on the same iterator proceed to the next element and - * store the key/value-pair into the memory specified as arguments of this - * function. - * - * If no further elements are found, this function returns zero and leaves the - * last found key/value-pair in memory. - * - * @param iterator the iterator to use - * @param key a pointer to the memory where to store the key - * @param value a pointer to the memory where to store the value - * @return 1, if another element was found, 0 if all elements has been processed - * @see ucx_map_iterator() - */ -int ucx_map_iter_next(UcxMapIterator *iterator, UcxKey *key, void **value); - - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_MAP_H */ -
--- a/ucx/mempool.c Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,211 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#ifdef __cplusplus -#define __STDC_FORMAT_MACROS -#endif -#include <inttypes.h> - -#include "mempool.h" - -/** Capsule for destructible memory chunks. */ -typedef struct { - /** The destructor for the memory chunk. */ - ucx_destructor destructor; - /** - * First byte of the memory chunk. - * Note, that the address <code>&c</code> is also the address - * of the whole memory chunk. - */ - char c; -} ucx_memchunk; - -/** Capsule for data and its destructor. */ -typedef struct { - /** The destructor for the data. */ - ucx_destructor destructor; - /** A pointer to the data. */ - void *ptr; -} ucx_regdestr; - -UCX_EXTERN void ucx_mempool_shared_destr(void* ptr) { - ucx_regdestr *rd = (ucx_regdestr*)ptr; - rd->destructor(rd->ptr); -} - -UcxMempool *ucx_mempool_new(size_t n) { - UcxMempool *pool = (UcxMempool*)malloc(sizeof(UcxMempool)); - if (!pool) { - return NULL; - } - - pool->data = (void**) malloc(n * sizeof(void*)); - if (pool->data == NULL) { - free(pool); - return NULL; - } - - pool->ndata = 0; - pool->size = n; - - UcxAllocator *allocator = (UcxAllocator*)malloc(sizeof(UcxAllocator)); - if(!allocator) { - free(pool->data); - free(pool); - return NULL; - } - allocator->malloc = (ucx_allocator_malloc)ucx_mempool_malloc; - allocator->calloc = (ucx_allocator_calloc)ucx_mempool_calloc; - allocator->realloc = (ucx_allocator_realloc)ucx_mempool_realloc; - allocator->free = (ucx_allocator_free)ucx_mempool_free; - allocator->pool = pool; - pool->allocator = allocator; - - return pool; -} - -int ucx_mempool_chcap(UcxMempool *pool, size_t newcap) { - if (newcap < pool->ndata) { - return 1; - } - - void **data = (void**) realloc(pool->data, newcap*sizeof(void*)); - if (data) { - pool->data = data; - pool->size = newcap; - return 0; - } else { - return 1; - } -} - -void *ucx_mempool_malloc(UcxMempool *pool, size_t n) { - if (pool->ndata >= pool->size) { - size_t newcap = pool->size*2; - if (newcap < pool->size || ucx_mempool_chcap(pool, newcap)) { - return NULL; - } - } - - void *p = malloc(sizeof(ucx_destructor) + n); - ucx_memchunk *mem = (ucx_memchunk*)p; - if (!mem) { - return NULL; - } - - mem->destructor = NULL; - pool->data[pool->ndata] = mem; - pool->ndata++; - - return &(mem->c); -} - -void *ucx_mempool_calloc(UcxMempool *pool, size_t nelem, size_t elsize) { - void *ptr = ucx_mempool_malloc(pool, nelem*elsize); - if (!ptr) { - return NULL; - } - memset(ptr, 0, nelem * elsize); - return ptr; -} - -void *ucx_mempool_realloc(UcxMempool *pool, void *ptr, size_t n) { - char *mem = ((char*)ptr) - sizeof(ucx_destructor); - char *newm = (char*) realloc(mem, n + sizeof(ucx_destructor)); - if (!newm) { - return NULL; - } - if (mem != newm) { - for(size_t i=0 ; i < pool->ndata ; i++) { - if(pool->data[i] == mem) { - pool->data[i] = newm; - return newm + sizeof(ucx_destructor); - } - } - fprintf(stderr, "FATAL: 0x%08" PRIxPTR" not in mpool 0x%08" PRIxPTR"\n", - (intptr_t)ptr, (intptr_t)pool); - abort(); - } else { - return newm + sizeof(ucx_destructor); - } -} - -void ucx_mempool_free(UcxMempool *pool, void *ptr) { - ucx_memchunk *chunk = (ucx_memchunk*)((char*)ptr-sizeof(ucx_destructor)); - for(size_t i=0 ; i<pool->ndata ; i++) { - if(chunk == pool->data[i]) { - if(chunk->destructor != NULL) { - chunk->destructor(&(chunk->c)); - } - free(chunk); - size_t last_index = pool->ndata - 1; - if(i != last_index) { - pool->data[i] = pool->data[last_index]; - pool->data[last_index] = NULL; - } - pool->ndata--; - return; - } - } - fprintf(stderr, "FATAL: 0x%08" PRIxPTR" not in mpool 0x%08" PRIxPTR"\n", - (intptr_t)ptr, (intptr_t)pool); - abort(); -} - -void ucx_mempool_destroy(UcxMempool *pool) { - ucx_memchunk *chunk; - for(size_t i=0 ; i<pool->ndata ; i++) { - chunk = (ucx_memchunk*) pool->data[i]; - if(chunk) { - if(chunk->destructor) { - chunk->destructor(&(chunk->c)); - } - free(chunk); - } - } - free(pool->data); - free(pool->allocator); - free(pool); -} - -void ucx_mempool_set_destr(void *ptr, ucx_destructor func) { - *(ucx_destructor*)((char*)ptr-sizeof(ucx_destructor)) = func; -} - -void ucx_mempool_reg_destr(UcxMempool *pool, void *ptr, ucx_destructor destr) { - ucx_regdestr *rd = (ucx_regdestr*)ucx_mempool_malloc( - pool, - sizeof(ucx_regdestr)); - rd->destructor = destr; - rd->ptr = ptr; - ucx_mempool_set_destr(rd, ucx_mempool_shared_destr); -} -
--- a/ucx/mempool.h Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,200 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file mempool.h - * - * Memory pool implementation. - * - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_MEMPOOL_H -#define UCX_MEMPOOL_H - -#include "ucx.h" -#include <stddef.h> -#include "allocator.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * UCX mempool structure. - */ -typedef struct { - /** UcxAllocator based on this pool */ - UcxAllocator *allocator; - - /** List of pointers to pooled memory. */ - void **data; - - /** Count of pooled memory items. */ - size_t ndata; - - /** Memory pool size. */ - size_t size; -} UcxMempool; - -/** Shorthand for a new default memory pool with a capacity of 16 elements. */ -#define ucx_mempool_new_default() ucx_mempool_new(16) - - -/** - * Creates a memory pool with the specified initial size. - * - * As the created memory pool automatically grows in size by factor two when - * trying to allocate memory on a full pool, it is recommended that you use - * a power of two for the initial size. - * - * @param n initial pool size (should be a power of two, e.g. 16) - * @return a pointer to the new memory pool - * @see ucx_mempool_new_default() - */ -UcxMempool *ucx_mempool_new(size_t n); - -/** - * Resizes a memory pool. - * - * This function will fail if the new capacity is not sufficient for the - * present data. - * - * @param pool the pool to resize - * @param newcap the new capacity - * @return zero on success or non-zero on failure - */ -int ucx_mempool_chcap(UcxMempool *pool, size_t newcap); - -/** - * Allocates pooled memory. - * - * @param pool the memory pool - * @param n amount of memory to allocate - * @return a pointer to the allocated memory - * @see ucx_allocator_malloc() - */ -void *ucx_mempool_malloc(UcxMempool *pool, size_t n); -/** - * Allocates a pooled memory array. - * - * The content of the allocated memory is set to zero. - * - * @param pool the memory pool - * @param nelem amount of elements to allocate - * @param elsize amount of memory per element - * @return a pointer to the allocated memory - * @see ucx_allocator_calloc() - */ -void *ucx_mempool_calloc(UcxMempool *pool, size_t nelem, size_t elsize); - -/** - * Reallocates pooled memory. - * - * If the memory to be reallocated is not contained by the specified pool, the - * behavior is undefined. - * - * @param pool the memory pool - * @param ptr a pointer to the memory that shall be reallocated - * @param n the new size of the memory - * @return a pointer to the new location of the memory - * @see ucx_allocator_realloc() - */ -void *ucx_mempool_realloc(UcxMempool *pool, void *ptr, size_t n); - -/** - * Frees pooled memory. - * - * Before freeing the memory, the specified destructor function (if any) - * is called. - * - * If you specify memory, that is not pooled by the specified memory pool, the - * program will terminate with a call to <code>abort()</code>. - * - * @param pool the memory pool - * @param ptr a pointer to the memory that shall be freed - * @see ucx_mempool_set_destr() - */ -void ucx_mempool_free(UcxMempool *pool, void *ptr); - -/** - * Destroys a memory pool. - * - * For each element the destructor function (if any) is called and the element - * is freed. - * - * Each of the registered destructor function that has no corresponding element - * within the pool (namely those registered by ucx_mempool_reg_destr) is - * called interleaving with the element destruction, but with guarantee to the - * order in which they were registered (FIFO order). - * - * - * @param pool the mempool to destroy - */ -void ucx_mempool_destroy(UcxMempool *pool); - -/** - * Sets a destructor function for the specified memory. - * - * The destructor is automatically called when the memory is freed or the - * pool is destroyed. - * - * The only requirement for the specified memory is, that it <b>MUST</b> be - * pooled memory by a UcxMempool or an element-compatible mempool. The pointer - * to the destructor function is saved in a reserved area before the actual - * memory. - * - * @param ptr pooled memory - * @param func a pointer to the destructor function - * @see ucx_mempool_free() - * @see ucx_mempool_destroy() - */ -void ucx_mempool_set_destr(void *ptr, ucx_destructor func); - -/** - * Registers a destructor function for the specified (non-pooled) memory. - * - * This is useful, if you have memory that has not been allocated by a mempool, - * but shall be managed by a mempool. - * - * This function creates an entry in the specified mempool and the memory will - * therefore (logically) convert to pooled memory. - * - * @param pool the memory pool - * @param ptr data the destructor is registered for - * @param destr a pointer to the destructor function - */ -void ucx_mempool_reg_destr(UcxMempool *pool, void *ptr, ucx_destructor destr); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_MEMPOOL_H */ -
--- a/ucx/properties.c Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,264 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "properties.h" - -UcxProperties *ucx_properties_new() { - UcxProperties *parser = (UcxProperties*)malloc( - sizeof(UcxProperties)); - if(!parser) { - return NULL; - } - - parser->buffer = NULL; - parser->buflen = 0; - parser->pos = 0; - parser->tmp = NULL; - parser->tmplen = 0; - parser->tmpcap = 0; - parser->error = 0; - parser->delimiter = '='; - parser->comment1 = '#'; - parser->comment2 = 0; - parser->comment3 = 0; - - return parser; -} - -void ucx_properties_free(UcxProperties *parser) { - if(parser->tmp) { - free(parser->tmp); - } - free(parser); -} - -void ucx_properties_fill(UcxProperties *parser, char *buf, size_t len) { - parser->buffer = buf; - parser->buflen = len; - parser->pos = 0; -} - -static void parser_tmp_append(UcxProperties *parser, char *buf, size_t len) { - if(parser->tmpcap - parser->tmplen < len) { - size_t newcap = parser->tmpcap + len + 64; - parser->tmp = (char*)realloc(parser->tmp, newcap); - parser->tmpcap = newcap; - } - memcpy(parser->tmp + parser->tmplen, buf, len); - parser->tmplen += len; -} - -int ucx_properties_next(UcxProperties *parser, sstr_t *name, sstr_t *value) { - if(parser->tmplen > 0) { - char *buf = parser->buffer + parser->pos; - size_t len = parser->buflen - parser->pos; - sstr_t str = sstrn(buf, len); - sstr_t nl = sstrchr(str, '\n'); - if(nl.ptr) { - size_t newlen = (size_t)(nl.ptr - buf) + 1; - parser_tmp_append(parser, buf, newlen); - // the tmp buffer contains exactly one line now - - char *orig_buf = parser->buffer; - size_t orig_len = parser->buflen; - - parser->buffer = parser->tmp; - parser->buflen = parser->tmplen; - parser->pos = 0; - parser->tmp = NULL; - parser->tmpcap = 0; - parser->tmplen = 0; - // run ucx_properties_next with the tmp buffer as main buffer - int ret = ucx_properties_next(parser, name, value); - - // restore original buffer - parser->tmp = parser->buffer; - parser->buffer = orig_buf; - parser->buflen = orig_len; - parser->pos = newlen; - - /* - * if ret == 0 the tmp buffer contained just space or a comment - * we parse again with the original buffer to get a name/value - * or a new tmp buffer - */ - return ret ? ret : ucx_properties_next(parser, name, value); - } else { - parser_tmp_append(parser, buf, len); - return 0; - } - } else if(parser->tmp) { - free(parser->tmp); - parser->tmp = NULL; - } - - char comment1 = parser->comment1; - char comment2 = parser->comment2; - char comment3 = parser->comment3; - char delimiter = parser->delimiter; - - // get one line and parse it - while(parser->pos < parser->buflen) { - char *buf = parser->buffer + parser->pos; - size_t len = parser->buflen - parser->pos; - - /* - * First we check if we have at least one line. We also get indices of - * delimiter and comment chars - */ - size_t delimiter_index = 0; - size_t comment_index = 0; - int has_comment = 0; - - size_t i = 0; - char c = 0; - for(;i<len;i++) { - c = buf[i]; - if(c == comment1 || c == comment2 || c == comment3) { - if(comment_index == 0) { - comment_index = i; - has_comment = 1; - } - } else if(c == delimiter) { - if(delimiter_index == 0 && !has_comment) { - delimiter_index = i; - } - } else if(c == '\n') { - break; - } - } - - if(c != '\n') { - // we don't have enough data for a line - // store remaining bytes in temporary buffer for next round - parser->tmpcap = len + 128; - parser->tmp = (char*)malloc(parser->tmpcap); - parser->tmplen = len; - memcpy(parser->tmp, buf, len); - return 0; - } - - sstr_t line = has_comment ? sstrn(buf, comment_index) : sstrn(buf, i); - // check line - if(delimiter_index == 0) { - line = sstrtrim(line); - if(line.length != 0) { - parser->error = 1; - } - } else { - sstr_t n = sstrn(buf, delimiter_index); - sstr_t v = sstrn( - buf + delimiter_index + 1, - line.length - delimiter_index - 1); - n = sstrtrim(n); - v = sstrtrim(v); - if(n.length != 0 || v.length != 0) { - *name = n; - *value = v; - parser->pos += i + 1; - return 1; - } else { - parser->error = 1; - } - } - - parser->pos += i + 1; - } - - return 0; -} - -int ucx_properties2map(UcxProperties *parser, UcxMap *map) { - sstr_t name; - sstr_t value; - while(ucx_properties_next(parser, &name, &value)) { - value = sstrdup_a(map->allocator, value); - if(!value.ptr) { - return 1; - } - if(ucx_map_sstr_put(map, name, value.ptr)) { - alfree(map->allocator, value.ptr); - return 1; - } - } - if (parser->error) { - return parser->error; - } else { - return 0; - } -} - -// buffer size is documented - change doc, when you change bufsize! -#define UCX_PROPLOAD_BUFSIZE 1024 -int ucx_properties_load(UcxMap *map, FILE *file) { - UcxProperties *parser = ucx_properties_new(); - if(!(parser && map && file)) { - return 1; - } - - int error = 0; - size_t r; - char buf[UCX_PROPLOAD_BUFSIZE]; - while((r = fread(buf, 1, UCX_PROPLOAD_BUFSIZE, file)) != 0) { - ucx_properties_fill(parser, buf, r); - error = ucx_properties2map(parser, map); - if (error) { - break; - } - } - ucx_properties_free(parser); - return error; -} - -int ucx_properties_store(UcxMap *map, FILE *file) { - UcxMapIterator iter = ucx_map_iterator(map); - void *v; - sstr_t value; - size_t written; - - UCX_MAP_FOREACH(k, v, iter) { - value = sstr((char*)v); - - written = 0; - written += fwrite(k.data, 1, k.len, file); - written += fwrite(" = ", 1, 3, file); - written += fwrite(value.ptr, 1, value.length, file); - written += fwrite("\n", 1, 1, file); - - if (written != k.len + value.length + 4) { - return 1; - } - } - - return 0; -} -
--- a/ucx/properties.h Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,218 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/** - * @file properties.h - * - * Load / store utilities for properties files. - * - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_PROPERTIES_H -#define UCX_PROPERTIES_H - -#include "ucx.h" -#include "map.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * UcxProperties object for parsing properties data. - * Most of the fields are for internal use only. You may configure the - * properties parser, e.g. by changing the used delimiter or specifying - * up to three different characters that shall introduce comments. - */ -typedef struct { - /** - * Input buffer (don't set manually). - * Automatically set by calls to ucx_properties_fill(). - */ - char *buffer; - - /** - * Length of the input buffer (don't set manually). - * Automatically set by calls to ucx_properties_fill(). - */ - size_t buflen; - - /** - * Current buffer position (don't set manually). - * Used by ucx_properties_next(). - */ - size_t pos; - - /** - * Internal temporary buffer (don't set manually). - * Used by ucx_properties_next(). - */ - char *tmp; - - /** - * Internal temporary buffer length (don't set manually). - * Used by ucx_properties_next(). - */ - size_t tmplen; - - /** - * Internal temporary buffer capacity (don't set manually). - * Used by ucx_properties_next(). - */ - size_t tmpcap; - - /** - * Parser error code. - * This is always 0 on success and a nonzero value on syntax errors. - * The value is set by ucx_properties_next(). - */ - int error; - - /** - * The delimiter that shall be used. - * This is '=' by default. - */ - char delimiter; - - /** - * The first comment character. - * This is '#' by default. - */ - char comment1; - - /** - * The second comment character. - * This is not set by default. - */ - char comment2; - - /** - * The third comment character. - * This is not set by default. - */ - char comment3; -} UcxProperties; - - -/** - * Constructs a new UcxProperties object. - * @return a pointer to the new UcxProperties object - */ -UcxProperties *ucx_properties_new(); - -/** - * Destroys a UcxProperties object. - * @param prop the UcxProperties object to destroy - */ -void ucx_properties_free(UcxProperties *prop); - -/** - * Sets the input buffer for the properties parser. - * - * After calling this function, you may parse the data by calling - * ucx_properties_next() until it returns 0. The function ucx_properties2map() - * is a convenience function that reads as much data as possible by using this - * function. - * - * - * @param prop the UcxProperties object - * @param buf a pointer to the new buffer - * @param len the payload length of the buffer - * @see ucx_properties_next() - * @see ucx_properties2map() - */ -void ucx_properties_fill(UcxProperties *prop, char *buf, size_t len); - -/** - * Retrieves the next key/value-pair. - * - * This function returns a nonzero value as long as there are key/value-pairs - * found. If no more key/value-pairs are found, you may refill the input buffer - * with ucx_properties_fill(). - * - * <b>Attention:</b> the sstr_t.ptr pointers of the output parameters point to - * memory within the input buffer of the parser and will get invalid some time. - * If you want long term copies of the key/value-pairs, use sstrdup() after - * calling this function. - * - * @param prop the UcxProperties object - * @param name a pointer to the sstr_t that shall contain the property name - * @param value a pointer to the sstr_t that shall contain the property value - * @return Nonzero, if a key/value-pair was successfully retrieved - * @see ucx_properties_fill() - */ -int ucx_properties_next(UcxProperties *prop, sstr_t *name, sstr_t *value); - -/** - * Retrieves all available key/value-pairs and puts them into a UcxMap. - * - * This is done by successive calls to ucx_properties_next() until no more - * key/value-pairs can be retrieved. - * - * @param prop the UcxProperties object - * @param map the target map - * @return The UcxProperties.error code (i.e. 0 on success). - * @see ucx_properties_fill() - */ -int ucx_properties2map(UcxProperties *prop, UcxMap *map); - -/** - * Loads a properties file to a UcxMap. - * - * This is a convenience function that reads data from an input - * stream until the end of the stream is reached. - * - * @param map the map object to write the key/value-pairs to - * @param file the <code>FILE*</code> stream to read from - * @return 0 on success, or a non-zero value on error - * - * @see ucx_properties_fill() - * @see ucx_properties2map() - */ -int ucx_properties_load(UcxMap *map, FILE *file); - -/** - * Stores a UcxMap to a file. - * - * The key/value-pairs are written by using the following format: - * - * <code>[key] = [value]\\n</code> - * - * @param map the map to store - * @param file the <code>FILE*</code> stream to write to - * @return 0 on success, or a non-zero value on error - */ -int ucx_properties_store(UcxMap *map, FILE *file); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_PROPERTIES_H */ -
--- a/ucx/stack.c Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "stack.h" -#include <string.h> - -static size_t ucx_stack_align(size_t n) { - int align = n % sizeof(void*); - if (align) { - n += sizeof(void*) - align; - } - return n; -} - -void ucx_stack_init(UcxStack *stack, char* space, size_t size) { - stack->size = size - size % sizeof(void*); - stack->space = space; - stack->top = NULL; - - stack->allocator.pool = stack; - stack->allocator.malloc = (ucx_allocator_malloc) ucx_stack_malloc; - stack->allocator.calloc = (ucx_allocator_calloc) ucx_stack_calloc; - stack->allocator.realloc = (ucx_allocator_realloc) ucx_stack_realloc; - stack->allocator.free = (ucx_allocator_free) ucx_stack_free; -} - -void *ucx_stack_malloc(UcxStack *stack, size_t n) { - - if (ucx_stack_avail(stack) < ucx_stack_align(n)) { - return NULL; - } else { - char *prev = stack->top; - if (stack->top) { - stack->top += ucx_stack_align(ucx_stack_topsize(stack)); - } else { - stack->top = stack->space; - } - - ((struct ucx_stack_metadata*)stack->top)->prev = prev; - ((struct ucx_stack_metadata*)stack->top)->size = n; - stack->top += sizeof(struct ucx_stack_metadata); - - return stack->top; - } -} - -void *ucx_stack_calloc(UcxStack *stack, size_t nelem, size_t elsize) { - void *mem = ucx_stack_malloc(stack, nelem*elsize); - memset(mem, 0, nelem*elsize); - return mem; -} - -void *ucx_stack_realloc(UcxStack *stack, void *ptr, size_t n) { - if (ptr == stack->top) { - if (stack->size - (stack->top - stack->space) < ucx_stack_align(n)) { - return NULL; - } else { - ((struct ucx_stack_metadata*)stack->top - 1)->size = n; - return ptr; - } - } else { - if (ucx_stack_align(((struct ucx_stack_metadata*)ptr - 1)->size) < - ucx_stack_align(n)) { - void *nptr = ucx_stack_malloc(stack, n); - if (nptr) { - memcpy(nptr, ptr, n); - ucx_stack_free(stack, ptr); - - return nptr; - } else { - return NULL; - } - } else { - ((struct ucx_stack_metadata*)ptr - 1)->size = n; - return ptr; - } - } -} - -void ucx_stack_free(UcxStack *stack, void *ptr) { - if (ptr == stack->top) { - stack->top = ((struct ucx_stack_metadata*) stack->top - 1)->prev; - } else { - struct ucx_stack_metadata *next = (struct ucx_stack_metadata*)( - (char*)ptr + - ucx_stack_align(((struct ucx_stack_metadata*) ptr - 1)->size) - ); - next->prev = ((struct ucx_stack_metadata*) ptr - 1)->prev; - } -} - -void ucx_stack_popn(UcxStack *stack, void *dest, size_t n) { - if (ucx_stack_empty(stack)) { - return; - } - - size_t len = ucx_stack_topsize(stack); - if (len > n) { - len = n; - } - - memcpy(dest, stack->top, len); - - ucx_stack_free(stack, stack->top); -} - -size_t ucx_stack_avail(UcxStack *stack) { - size_t avail = ((stack->top ? (stack->size - - (stack->top - stack->space) - - ucx_stack_align(ucx_stack_topsize(stack))) - : stack->size)); - - if (avail > sizeof(struct ucx_stack_metadata)) { - return avail - sizeof(struct ucx_stack_metadata); - } else { - return 0; - } -}
--- a/ucx/stack.h Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,232 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file stack.h - * - * Default stack memory allocation implementation. - * - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_STACK_H -#define UCX_STACK_H - -#include "ucx.h" -#include "allocator.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/** - * UCX stack structure. - */ -typedef struct { - /** UcxAllocator based on this stack */ - UcxAllocator allocator; - - /** Stack size. */ - size_t size; - - /** Pointer to the bottom of the stack */ - char *space; - - /** Pointer to the top of the stack */ - char *top; -} UcxStack; - -/** - * Metadata for each UCX stack element. - */ -struct ucx_stack_metadata { - /** - * Location of the previous element (<code>NULL</code> if this is the first) - */ - char *prev; - - /** Size of this element */ - size_t size; -}; - -/** - * Initializes UcxStack structure with memory. - * - * @param stack a pointer to an uninitialized stack structure - * @param space the memory area that shall be managed - * @param size size of the memory area - * @return a new UcxStack structure - */ -void ucx_stack_init(UcxStack *stack, char* space, size_t size); - -/** - * Allocates stack memory. - * - * @param stack a pointer to the stack - * @param n amount of memory to allocate - * @return a pointer to the allocated memory - * @see ucx_allocator_malloc() - */ -void *ucx_stack_malloc(UcxStack *stack, size_t n); - -/** - * Alias for #ucx_stack_malloc(). - * @param stack a pointer to the stack - * @param n amount of memory to allocate - * @return a pointer to the allocated memory - * @see ucx_stack_malloc - */ -#define ucx_stack_push(stack, n) ucx_stack_malloc(stack, n) - -/** - * Allocates an array of stack memory - * - * The content of the allocated memory is set to zero. - * - * @param stack a pointer to the stack - * @param nelem amount of elements to allocate - * @param elsize amount of memory per element - * @return a pointer to the allocated memory - * @see ucx_allocator_calloc() - */ -void *ucx_stack_calloc(UcxStack *stack, size_t nelem, size_t elsize); - -/** - * Alias for #ucx_stack_calloc(). - * - * @param stack a pointer to the stack - * @param n amount of elements to allocate - * @param elsize amount of memory per element - * @return a pointer to the allocated memory - * @see ucx_stack_calloc - */ -#define ucx_stack_pusharr(stack,n,elsize) ucx_stack_calloc(stack,n,elssize) - -/** - * Reallocates memory on the stack. - * - * Shrinking memory is always safe. Extending memory can be very expensive. - * - * @param stack the stack - * @param ptr a pointer to the memory that shall be reallocated - * @param n the new size of the memory - * @return a pointer to the new location of the memory - * @see ucx_allocator_realloc() - */ -void *ucx_stack_realloc(UcxStack *stack, void *ptr, size_t n); - -/** - * Frees memory on the stack. - * - * Freeing stack memory behaves in a special way. - * - * If the element, that should be freed, is the top most element of the stack, - * it is removed from the stack. Otherwise it is marked as freed. Marked - * elements are removed, when they become the top most elements of the stack. - * - * @param stack a pointer to the stack - * @param ptr a pointer to the memory that shall be freed - */ -void ucx_stack_free(UcxStack *stack, void *ptr); - - -/** - * Returns the size of the top most element. - * @param stack a pointer to the stack - * @return the size of the top most element - */ -#define ucx_stack_topsize(stack) ((stack)->top ? ((struct ucx_stack_metadata*)\ - (stack)->top - 1)->size : 0) - -/** - * Removes the top most element from the stack and copies the content to <code> - * dest</code>, if specified. - * - * Use #ucx_stack_topsize()# to get the amount of memory that must be available - * at the location of <code>dest</code>. - * - * @param stack a pointer to the stack - * @param dest the location where the contents shall be written to, or <code> - * NULL</code>, if the element shall only be removed. - * @see ucx_stack_free - * @see ucx_stack_popn - */ -#define ucx_stack_pop(stack, dest) ucx_stack_popn(stack, dest, (size_t)-1) - -/** - * Removes the top most element from the stack and copies the content to <code> - * dest</code>. - * - * In contrast to #ucx_stack_pop() the <code>dest</code> pointer <code>MUST - * NOT</code> be <code>NULL</code>. - * - * @param stack a pointer to the stack - * @param dest the location where the contents shall be written to - * @param n copies at most n elements to <code>dest</code> - * @see ucx_stack_pop - */ -void ucx_stack_popn(UcxStack *stack, void *dest, size_t n); - -/** - * Returns the remaining available memory on the specified stack. - * - * @param stack a pointer to the stack - * @return the remaining available memory - */ -size_t ucx_stack_avail(UcxStack *stack); - -/** - * Checks, if the stack is empty. - * - * @param stack a pointer to the stack - * @return nonzero, if the stack is empty, zero otherwise - */ -#define ucx_stack_empty(stack) (!(stack)->top) - -/** - * Computes a recommended size for the stack memory area. Note, that - * reallocations have not been taken into account, so you might need to reserve - * twice as much memory to allow many reallocations. - * - * @param size the approximate payload - * @param elems the approximate count of element allocations - * @return a recommended size for the stack space based on the information - * provided - */ -#define ucx_stack_dim(size, elems) (size+sizeof(struct ucx_stack_metadata) * \ - (elems + 1)) - - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_STACK_H */ -
--- a/ucx/string.c Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,462 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <stdint.h> -#include <ctype.h> - -#include "string.h" -#include "allocator.h" - -sstr_t sstr(char *cstring) { - sstr_t string; - string.ptr = cstring; - string.length = strlen(cstring); - return string; -} - -sstr_t sstrn(char *cstring, size_t length) { - sstr_t string; - string.ptr = cstring; - string.length = length; - return string; -} - -size_t sstrnlen(size_t n, sstr_t s, ...) { - va_list ap; - size_t size = s.length; - va_start(ap, s); - - for (size_t i = 1 ; i < n ; i++) { - sstr_t str = va_arg(ap, sstr_t); - size += str.length; - } - va_end(ap); - - return size; -} - -static sstr_t sstrvcat_a( - UcxAllocator *a, - size_t count, - sstr_t s1, - sstr_t s2, - va_list ap) { - sstr_t str; - str.ptr = NULL; - str.length = 0; - if(count < 2) { - return str; - } - - sstr_t *strings = (sstr_t*) calloc(count, sizeof(sstr_t)); - if(!strings) { - return str; - } - - // get all args and overall length - strings[0] = s1; - strings[1] = s2; - size_t strlen = s1.length + s2.length; - for (size_t i=2;i<count;i++) { - sstr_t s = va_arg (ap, sstr_t); - strings[i] = s; - strlen += s.length; - } - - // create new string - str.ptr = (char*) almalloc(a, strlen + 1); - str.length = strlen; - if(!str.ptr) { - free(strings); - str.length = 0; - return str; - } - - // concatenate strings - size_t pos = 0; - for (size_t i=0;i<count;i++) { - sstr_t s = strings[i]; - memcpy(str.ptr + pos, s.ptr, s.length); - pos += s.length; - } - - str.ptr[str.length] = '\0'; - - free(strings); - - return str; -} - -sstr_t sstrcat(size_t count, sstr_t s1, sstr_t s2, ...) { - va_list ap; - va_start(ap, s2); - sstr_t s = sstrvcat_a(ucx_default_allocator(), count, s1, s2, ap); - va_end(ap); - return s; -} - -sstr_t sstrcat_a(UcxAllocator *a, size_t count, sstr_t s1, sstr_t s2, ...) { - va_list ap; - va_start(ap, s2); - sstr_t s = sstrvcat_a(a, count, s1, s2, ap); - va_end(ap); - return s; -} - -sstr_t sstrsubs(sstr_t s, size_t start) { - return sstrsubsl (s, start, s.length-start); -} - -sstr_t sstrsubsl(sstr_t s, size_t start, size_t length) { - sstr_t new_sstr; - if (start >= s.length) { - new_sstr.ptr = NULL; - new_sstr.length = 0; - } else { - if (length > s.length-start) { - length = s.length-start; - } - new_sstr.ptr = &s.ptr[start]; - new_sstr.length = length; - } - return new_sstr; -} - -sstr_t sstrchr(sstr_t s, int c) { - for(size_t i=0;i<s.length;i++) { - if(s.ptr[i] == c) { - return sstrsubs(s, i); - } - } - sstr_t n; - n.ptr = NULL; - n.length = 0; - return n; -} - -sstr_t sstrrchr(sstr_t s, int c) { - if (s.length > 0) { - for(size_t i=s.length;i>0;i--) { - if(s.ptr[i-1] == c) { - return sstrsubs(s, i-1); - } - } - } - sstr_t n; - n.ptr = NULL; - n.length = 0; - return n; -} - -#define ptable_r(dest, useheap, ptable, index) (dest = useheap ? \ - ((size_t*)ptable)[index] : (size_t) ((uint8_t*)ptable)[index]) - -#define ptable_w(useheap, ptable, index, src) do {\ - if (!useheap) ((uint8_t*)ptable)[index] = (uint8_t) src;\ - else ((size_t*)ptable)[index] = src;\ - } while (0); - -sstr_t sstrstr(sstr_t string, sstr_t match) { - if (match.length == 0) { - return string; - } - - /* prepare default return value in case of no match */ - sstr_t result = sstrn(NULL, 0); - - /* - * IMPORTANT: - * our prefix table contains the prefix length PLUS ONE - * this is our decision, because we want to use the full range of size_t - * the original algorithm needs a (-1) at one single place - * and we want to avoid that - */ - - /* static prefix table */ - static uint8_t s_prefix_table[256]; - - /* check pattern length and use appropriate prefix table */ - /* if the pattern exceeds static prefix table, allocate on the heap */ - register int useheap = match.length > 255; - register void* ptable = useheap ? - calloc(match.length+1, sizeof(size_t)): s_prefix_table; - - /* keep counter in registers */ - register size_t i, j; - - /* fill prefix table */ - i = 0; j = 0; - ptable_w(useheap, ptable, i, j); - while (i < match.length) { - while (j >= 1 && match.ptr[j-1] != match.ptr[i]) { - ptable_r(j, useheap, ptable, j-1); - } - i++; j++; - ptable_w(useheap, ptable, i, j); - } - - /* search */ - i = 0; j = 1; - while (i < string.length) { - while (j >= 1 && string.ptr[i] != match.ptr[j-1]) { - ptable_r(j, useheap, ptable, j-1); - } - i++; j++; - if (j-1 == match.length) { - size_t start = i - match.length; - result.ptr = string.ptr + start; - result.length = string.length - start; - break; - } - } - - /* if prefix table was allocated on the heap, free it */ - if (ptable != s_prefix_table) { - free(ptable); - } - - return result; -} - -#undef ptable_r -#undef ptable_w - -sstr_t* sstrsplit(sstr_t s, sstr_t d, ssize_t *n) { - return sstrsplit_a(ucx_default_allocator(), s, d, n); -} - -sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t s, sstr_t d, ssize_t *n) { - if (s.length == 0 || d.length == 0) { - *n = -1; - return NULL; - } - - /* special cases: delimiter is at least as large as the string */ - if (d.length >= s.length) { - /* exact match */ - if (sstrcmp(s, d) == 0) { - *n = 0; - return NULL; - } else /* no match possible */ { - *n = 1; - sstr_t *result = (sstr_t*) almalloc(allocator, sizeof(sstr_t)); - *result = sstrdup_a(allocator, s); - return result; - } - } - - ssize_t nmax = *n; - size_t arrlen = 16; - sstr_t* result = (sstr_t*) almalloc(allocator, arrlen*sizeof(sstr_t)); - - if (result) { - sstr_t curpos = s; - ssize_t j = 1; - while (1) { - sstr_t match; - /* optimize for one byte delimiters */ - if (d.length == 1) { - match = curpos; - for (size_t i = 0 ; i < curpos.length ; i++) { - if (curpos.ptr[i] == *(d.ptr)) { - match.ptr = curpos.ptr + i; - break; - } - match.length--; - } - } else { - match = sstrstr(curpos, d); - } - if (match.length > 0) { - /* is this our last try? */ - if (nmax == 0 || j < nmax) { - /* copy the current string to the array */ - sstr_t item = sstrn(curpos.ptr, match.ptr - curpos.ptr); - result[j-1] = sstrdup_a(allocator, item); - size_t processed = item.length + d.length; - curpos.ptr += processed; - curpos.length -= processed; - - /* allocate memory for the next string */ - j++; - if (j > arrlen) { - arrlen *= 2; - sstr_t* reallocated = (sstr_t*) alrealloc( - allocator, result, arrlen*sizeof(sstr_t)); - if (reallocated) { - result = reallocated; - } else { - for (ssize_t i = 0 ; i < j-1 ; i++) { - alfree(allocator, result[i].ptr); - } - alfree(allocator, result); - *n = -2; - return NULL; - } - } - } else { - /* nmax reached, copy the _full_ remaining string */ - result[j-1] = sstrdup_a(allocator, curpos); - break; - } - } else { - /* no more matches, copy last string */ - result[j-1] = sstrdup_a(allocator, curpos); - break; - } - } - *n = j; - } else { - *n = -2; - } - - return result; -} - -int sstrcmp(sstr_t s1, sstr_t s2) { - if (s1.length == s2.length) { - return memcmp(s1.ptr, s2.ptr, s1.length); - } else if (s1.length > s2.length) { - return 1; - } else { - return -1; - } -} - -int sstrcasecmp(sstr_t s1, sstr_t s2) { - if (s1.length == s2.length) { -#ifdef _WIN32 - return _strnicmp(s1.ptr, s2.ptr, s1.length); -#else - return strncasecmp(s1.ptr, s2.ptr, s1.length); -#endif - } else if (s1.length > s2.length) { - return 1; - } else { - return -1; - } -} - -sstr_t sstrdup(sstr_t s) { - return sstrdup_a(ucx_default_allocator(), s); -} - -sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t s) { - sstr_t newstring; - newstring.ptr = (char*)almalloc(allocator, s.length + 1); - if (newstring.ptr) { - newstring.length = s.length; - newstring.ptr[newstring.length] = 0; - - memcpy(newstring.ptr, s.ptr, s.length); - } else { - newstring.length = 0; - } - - return newstring; -} - -sstr_t sstrtrim(sstr_t string) { - sstr_t newstr = string; - - while (newstr.length > 0 && isspace(*newstr.ptr)) { - newstr.ptr++; - newstr.length--; - } - while (newstr.length > 0 && isspace(newstr.ptr[newstr.length-1])) { - newstr.length--; - } - - return newstr; -} - -int sstrprefix(sstr_t string, sstr_t prefix) { - if (string.length == 0) { - return prefix.length == 0; - } - if (prefix.length == 0) { - return 1; - } - - if (prefix.length > string.length) { - return 0; - } else { - return memcmp(string.ptr, prefix.ptr, prefix.length) == 0; - } -} - -int sstrsuffix(sstr_t string, sstr_t suffix) { - if (string.length == 0) { - return suffix.length == 0; - } - if (suffix.length == 0) { - return 1; - } - - if (suffix.length > string.length) { - return 0; - } else { - return memcmp(string.ptr+string.length-suffix.length, - suffix.ptr, suffix.length) == 0; - } -} - -sstr_t sstrlower(sstr_t string) { - sstr_t ret = sstrdup(string); - for (size_t i = 0; i < ret.length ; i++) { - ret.ptr[i] = tolower(ret.ptr[i]); - } - return ret; -} - -sstr_t sstrlower_a(UcxAllocator *allocator, sstr_t string) { - sstr_t ret = sstrdup_a(allocator, string); - for (size_t i = 0; i < ret.length ; i++) { - ret.ptr[i] = tolower(ret.ptr[i]); - } - return ret; -} - -sstr_t sstrupper(sstr_t string) { - sstr_t ret = sstrdup(string); - for (size_t i = 0; i < ret.length ; i++) { - ret.ptr[i] = toupper(ret.ptr[i]); - } - return ret; -} - -sstr_t sstrupper_a(UcxAllocator *allocator, sstr_t string) { - sstr_t ret = sstrdup_a(allocator, string); - for (size_t i = 0; i < ret.length ; i++) { - ret.ptr[i] = toupper(ret.ptr[i]); - } - return ret; -}
--- a/ucx/string.h Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,460 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/** - * Bounded string implementation. - * - * The UCX strings (<code>sstr_t</code>) provide an alternative to C strings. - * The main difference to C strings is, that <code>sstr_t</code> does <b>not - * need to be <code>NULL</code>-terminated</b>. Instead the length is stored - * within the structure. - * - * When using <code>sstr_t</code>, developers must be full aware of what type - * of string (<code>NULL</code>-terminated) or not) they are using, when - * accessing the <code>char* ptr</code> directly. - * - * The UCX string module provides some common string functions, known from - * standard libc, working with <code>sstr_t</code>. - * - * @file string.h - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_STRING_H -#define UCX_STRING_H - -#include "ucx.h" -#include "allocator.h" -#include <stddef.h> - -/** Shortcut for a <code>sstr_t struct</code> literal. */ -#define ST(s) { (char*)s, sizeof(s)-1 } - -/** Shortcut for the conversion of a C string to a <code>sstr_t</code>. */ -#define S(s) sstrn((char*)s, sizeof(s)-1) - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * The UCX string structure. - */ -typedef struct { - /** A reference to the string (<b>not necessarily <code>NULL</code> - * -terminated</b>) */ - char *ptr; - /** The length of the string */ - size_t length; -} sstr_t; - -/** - * Creates a new sstr_t based on a C string. - * - * The length is implicitly inferred by using a call to <code>strlen()</code>. - * - * <b>Note:</b> the sstr_t will hold a <i>reference</i> to the C string. If you - * do want a copy, use sstrdup() on the return value of this function. - * - * @param cstring the C string to wrap - * @return a new sstr_t containing the C string - * - * @see sstrn() - */ -sstr_t sstr(char *cstring); - -/** - * Creates a new sstr_t of the specified length based on a C string. - * - * <b>Note:</b> the sstr_t will hold a <i>reference</i> to the C string. If you - * do want a copy, use sstrdup() on the return value of this function. - * - * @param cstring the C string to wrap - * @param length the length of the string - * @return a new sstr_t containing the C string - * - * @see sstr() - * @see S() - */ -sstr_t sstrn(char *cstring, size_t length); - - -/** - * Returns the cumulated length of all specified strings. - * - * At least one string must be specified. - * - * <b>Attention:</b> if the count argument does not match the count of the - * specified strings, the behavior is undefined. - * - * @param count the total number of specified strings (so at least 1) - * @param string the first string - * @param ... all other strings - * @return the cumulated length of all strings - */ -size_t sstrnlen(size_t count, sstr_t string, ...); - -/** - * Concatenates two or more strings. - * - * The resulting string will be allocated by standard <code>malloc()</code>. - * So developers <b>MUST</b> pass the sstr_t.ptr to <code>free()</code>. - * - * The sstr_t.ptr of the return value will <i>always</i> be <code>NULL</code>- - * terminated. - * - * @param count the total number of strings to concatenate - * @param s1 first string - * @param s2 second string - * @param ... all remaining strings - * @return the concatenated string - */ -sstr_t sstrcat(size_t count, sstr_t s1, sstr_t s2, ...); - -/** - * Concatenates two or more strings using a UcxAllocator. - * - * See sstrcat() for details. - * - * @param a the allocator to use - * @param count the total number of strings to concatenate - * @param s1 first string - * @param s2 second string - * @param ... all remaining strings - * @return the concatenated string - */ -sstr_t sstrcat_a(UcxAllocator *a, size_t count, sstr_t s1, sstr_t s2, ...); - - -/** - * Returns a substring starting at the specified location. - * - * <b>Attention:</b> the new string references the same memory area as the - * input string and will <b>NOT</b> be <code>NULL</code>-terminated. - * Use sstrdup() to get a copy. - * - * @param string input string - * @param start start location of the substring - * @return a substring of <code>string</code> starting at <code>start</code> - * - * @see sstrsubsl() - * @see sstrchr() - */ -sstr_t sstrsubs(sstr_t string, size_t start); - -/** - * Returns a substring with a maximum length starting at the specified location. - * - * <b>Attention:</b> the new string references the same memory area as the - * input string and will <b>NOT</b> be <code>NULL</code>-terminated. - * Use sstrdup() to get a copy. - * - * @param string input string - * @param start start location of the substring - * @param length the maximum length of the substring - * @return a substring of <code>string</code> starting at <code>start</code> - * with a maximum length of <code>length</code> - * - * @see sstrsubs() - * @see sstrchr() - */ -sstr_t sstrsubsl(sstr_t string, size_t start, size_t length); - -/** - * Returns a substring starting at the location of the first occurrence of the - * specified character. - * - * If the string does not contain the character, an empty string is returned. - * - * @param string the string where to locate the character - * @param chr the character to locate - * @return a substring starting at the first location of <code>chr</code> - * - * @see sstrsubs() - */ -sstr_t sstrchr(sstr_t string, int chr); - -/** - * Returns a substring starting at the location of the last occurrence of the - * specified character. - * - * If the string does not contain the character, an empty string is returned. - * - * @param string the string where to locate the character - * @param chr the character to locate - * @return a substring starting at the last location of <code>chr</code> - * - * @see sstrsubs() - */ -sstr_t sstrrchr(sstr_t string, int chr); - -/** - * Returns a substring starting at the location of the first occurrence of the - * specified string. - * - * If the string does not contain the other string, an empty string is returned. - * - * If <code>match</code> is an empty string, the complete <code>string</code> is - * returned. - * - * @param string the string to be scanned - * @param match string containing the sequence of characters to match - * @return a substring starting at the first occurrence of - * <code>match</code>, or an empty string, if the sequence is not - * present in <code>string</code> - */ -sstr_t sstrstr(sstr_t string, sstr_t match); - -/** - * Splits a string into parts by using a delimiter string. - * - * This function will return <code>NULL</code>, if one of the following happens: - * <ul> - * <li>the string length is zero</li> - * <li>the delimeter length is zero</li> - * <li>the string equals the delimeter</li> - * <li>memory allocation fails</li> - * </ul> - * - * The integer referenced by <code>count</code> is used as input and determines - * the maximum size of the resulting array, i.e. the maximum count of splits to - * perform + 1. - * - * The integer referenced by <code>count</code> is also used as output and is - * set to - * <ul> - * <li>-2, on memory allocation errors</li> - * <li>-1, if either the string or the delimiter is an empty string</li> - * <li>0, if the string equals the delimiter</li> - * <li>1, if the string does not contain the delimiter</li> - * <li>the count of array items, otherwise</li> - * </ul> - * - * If the string starts with the delimiter, the first item of the resulting - * array will be an empty string. - * - * If the string ends with the delimiter and the maximum list size is not - * exceeded, the last array item will be an empty string. - * In case the list size would be exceeded, the last array item will be the - * remaining string after the last split, <i>including</i> the terminating - * delimiter. - * - * <b>Attention:</b> The array pointer <b>AND</b> all sstr_t.ptr of the array - * items must be manually passed to <code>free()</code>. Use sstrsplit_a() with - * an allocator to managed memory, to avoid this. - * - * @param string the string to split - * @param delim the delimiter string - * @param count IN: the maximum size of the resulting array (0 = no limit), - * OUT: the actual size of the array - * @return a sstr_t array containing the split strings or - * <code>NULL</code> on error - * - * @see sstrsplit_a() - */ -sstr_t* sstrsplit(sstr_t string, sstr_t delim, ssize_t *count); - -/** - * Performing sstrsplit() using a UcxAllocator. - * - * <i>Read the description of sstrsplit() for details.</i> - * - * The memory for the sstr_t.ptr pointers of the array items and the memory for - * the sstr_t array itself are allocated by using the UcxAllocator.malloc() - * function. - * - * <b>Note:</b> the allocator is not used for memory that is freed within the - * same call of this function (locally scoped variables). - * - * @param allocator the UcxAllocator used for allocating memory - * @param string the string to split - * @param delim the delimiter string - * @param count IN: the maximum size of the resulting array (0 = no limit), - * OUT: the actual size of the array - * @return a sstr_t array containing the split strings or - * <code>NULL</code> on error - * - * @see sstrsplit() - */ -sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t string, sstr_t delim, - ssize_t *count); - -/** - * Compares two UCX strings with standard <code>memcmp()</code>. - * - * At first it compares the sstr_t.length attribute of the two strings. The - * <code>memcmp()</code> function is called, if and only if the lengths match. - * - * @param s1 the first string - * @param s2 the second string - * @return -1, if the length of s1 is less than the length of s2 or 1, if the - * length of s1 is greater than the length of s2 or the result of - * <code>memcmp()</code> otherwise (i.e. 0 if the strings match) - */ -int sstrcmp(sstr_t s1, sstr_t s2); - -/** - * Compares two UCX strings ignoring the case. - * - * At first it compares the sstr_t.length attribute of the two strings. If and - * only if the lengths match, both strings are compared char by char ignoring - * the case. - * - * @param s1 the first string - * @param s2 the second string - * @return -1, if the length of s1 is less than the length of s2 or 1, if the - * length of s1 is greater than the length of s2 or the difference between the - * first two differing characters otherwise (i.e. 0 if the strings match and - * no characters differ) - */ -int sstrcasecmp(sstr_t s1, sstr_t s2); - -/** - * Creates a duplicate of the specified string. - * - * The new sstr_t will contain a copy allocated by standard - * <code>malloc()</code>. So developers <b>MUST</b> pass the sstr_t.ptr to - * <code>free()</code>. - * - * The sstr_t.ptr of the return value will <i>always</i> be <code>NULL</code>- - * terminated. - * - * @param string the string to duplicate - * @return a duplicate of the string - * @see sstrdup_a() - */ -sstr_t sstrdup(sstr_t string); - -/** - * Creates a duplicate of the specified string using a UcxAllocator. - * - * The new sstr_t will contain a copy allocated by the allocators - * ucx_allocator_malloc function. So it is implementation depended, whether the - * returned sstr_t.ptr pointer must be passed to the allocators - * ucx_allocator_free function manually. - * - * The sstr_t.ptr of the return value will <i>always</i> be <code>NULL</code>- - * terminated. - * - * @param allocator a valid instance of a UcxAllocator - * @param string the string to duplicate - * @return a duplicate of the string - * @see sstrdup() - */ -sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t string); - -/** - * Omits leading and trailing spaces. - * - * This function returns a new sstr_t containing a trimmed version of the - * specified string. - * - * <b>Note:</b> the new sstr_t references the same memory, thus you - * <b>MUST NOT</b> pass the sstr_t.ptr of the return value to - * <code>free()</code>. It is also highly recommended to avoid assignments like - * <code>mystr = sstrtrim(mystr);</code> as you lose the reference to the - * source string. Assignments of this type are only permitted, if the - * sstr_t.ptr of the source string does not need to be freed or if another - * reference to the source string exists. - * - * @param string the string that shall be trimmed - * @return a new sstr_t containing the trimmed string - */ -sstr_t sstrtrim(sstr_t string); - -/** - * Checks, if a string has a specific prefix. - * @param string the string to check - * @param prefix the prefix the string should have - * @return 1, if and only if the string has the specified prefix, 0 otherwise - */ -int sstrprefix(sstr_t string, sstr_t prefix); - -/** - * Checks, if a string has a specific suffix. - * @param string the string to check - * @param suffix the suffix the string should have - * @return 1, if and only if the string has the specified suffix, 0 otherwise - */ -int sstrsuffix(sstr_t string, sstr_t suffix); - -/** - * Returns a lower case version of a string. - * - * This function creates a duplicate of the input string, first. See the - * documentation of sstrdup() for the implications. - * - * @param string the input string - * @return the resulting lower case string - * @see sstrdup() - */ -sstr_t sstrlower(sstr_t string); - -/** - * Returns a lower case version of a string. - * - * This function creates a duplicate of the input string, first. See the - * documentation of sstrdup_a() for the implications. - * - * @param allocator the allocator used for duplicating the string - * @param string the input string - * @return the resulting lower case string - * @see sstrdup_a() - */ -sstr_t sstrlower_a(UcxAllocator *allocator, sstr_t string); - -/** - * Returns a upper case version of a string. - * - * This function creates a duplicate of the input string, first. See the - * documentation of sstrdup() for the implications. - * - * @param string the input string - * @return the resulting upper case string - * @see sstrdup() - */ -sstr_t sstrupper(sstr_t string); - -/** - * Returns a upper case version of a string. - * - * This function creates a duplicate of the input string, first. See the - * documentation of sstrdup_a() for the implications. - * - * @param allocator the allocator used for duplicating the string - * @param string the input string - * @return the resulting upper case string - * @see sstrdup_a() - */ -sstr_t sstrupper_a(UcxAllocator *allocator, sstr_t string); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_STRING_H */
--- a/ucx/test.c Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "test.h" - -UcxTestSuite* ucx_test_suite_new() { - UcxTestSuite* suite = (UcxTestSuite*) malloc(sizeof(UcxTestSuite)); - if (suite != NULL) { - suite->success = 0; - suite->failure = 0; - suite->tests = NULL; - } - - return suite; -} - -void ucx_test_suite_free(UcxTestSuite* suite) { - UcxTestList *l = suite->tests; - while (l != NULL) { - UcxTestList *e = l; - l = l->next; - free(e); - } - free(suite); -} - -int ucx_test_register(UcxTestSuite* suite, UcxTest test) { - if (suite->tests) { - UcxTestList *newelem = (UcxTestList*) malloc(sizeof(UcxTestList)); - if (newelem) { - newelem->test = test; - newelem->next = NULL; - - UcxTestList *last = suite->tests; - while (last->next) { - last = last->next; - } - last->next = newelem; - - return EXIT_SUCCESS; - } else { - return EXIT_FAILURE; - } - } else { - suite->tests = (UcxTestList*) malloc(sizeof(UcxTestList)); - if (suite->tests) { - suite->tests->test = test; - suite->tests->next = NULL; - - return EXIT_SUCCESS; - } else { - return EXIT_FAILURE; - } - } -} - -void ucx_test_run(UcxTestSuite* suite, FILE* output) { - suite->success = 0; - suite->failure = 0; - for (UcxTestList* elem = suite->tests ; elem ; elem = elem->next) { - elem->test(suite, output); - } - fwrite("\nAll test completed.\n", 1, 21, output); - fprintf(output, " Total: %u\n Success: %u\n Failure: %u\n", - suite->success+suite->failure, suite->success, suite->failure); -}
--- a/ucx/test.h Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,241 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file: test.h - * - * UCX Test Framework. - * - * Usage of this test framework: - * - * **** IN HEADER FILE: **** - * - * <pre> - * UCX_TEST(function_name) - * UCX_TEST_SUBROUTINE(subroutine_name, paramlist) // optional - * </pre> - * - * **** IN SOURCE FILE: **** - * <pre> - * UCX_TEST_SUBROUTINE(subroutine_name, paramlist) { - * // tests with UCX_TEST_ASSERT() - * } - * - * UCX_TEST(function_name) { - * // memory allocation and other stuff here - * #UCX_TEST_BEGIN - * // tests with UCX_TEST_ASSERT() and/or - * // calls with UCX_TEST_CALL_SUBROUTINE() here - * #UCX_TEST_END - * // cleanup of memory here - * } - * </pre> - * - * <b>Note:</b> if a test fails, a longjump is performed - * back to the #UCX_TEST_BEGIN macro! - * - * <b>Attention:</b> Do not call own functions within a test, that use - * UCX_TEST_ASSERT() macros and are not defined by using UCX_TEST_SUBROUTINE(). - * - * - * @author Mike Becker - * @author Olaf Wintermann - * - */ - -#ifndef UCX_TEST_H -#define UCX_TEST_H - -#include "ucx.h" -#include <stdio.h> -#include <string.h> -#include <setjmp.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef __FUNCTION__ - -/** - * Alias for the <code>__func__</code> preprocessor macro. - * Some compilers use <code>__func__</code> and others use __FUNCTION__. - * We use __FUNCTION__ so we define it for those compilers which use - * <code>__func__</code>. - */ -#define __FUNCTION__ __func__ -#endif - -/** Type for the UcxTestSuite. */ -typedef struct UcxTestSuite UcxTestSuite; - -/** Pointer to a test function. */ -typedef void(*UcxTest)(UcxTestSuite*,FILE*); - -/** Type for the internal list of test cases. */ -typedef struct UcxTestList UcxTestList; - -/** Structure for the internal list of test cases. */ -struct UcxTestList { - - /** Test case. */ - UcxTest test; - - /** Pointer to the next list element. */ - UcxTestList *next; -}; - -/** - * A test suite containing multiple test cases. - */ -struct UcxTestSuite { - - /** The number of successful tests after the suite has been run. */ - unsigned int success; - - /** The number of failed tests after the suite has been run. */ - unsigned int failure; - - /** - * Internal list of test cases. - * Use ucx_test_register() to add tests to this list. - */ - UcxTestList *tests; -}; - -/** - * Creates a new test suite. - * @return a new test suite - */ -UcxTestSuite* ucx_test_suite_new(); - -/** - * Destroys a test suite. - * @param suite the test suite to destroy - */ -void ucx_test_suite_free(UcxTestSuite* suite); - -/** - * Registers a test function with the specified test suite. - * - * @param suite the suite, the test function shall be added to - * @param test the test function to register - * @return <code>EXIT_SUCCESS</code> on success or - * <code>EXIT_FAILURE</code> on failure - */ -int ucx_test_register(UcxTestSuite* suite, UcxTest test); - -/** - * Runs a test suite and writes the test log to the specified stream. - * @param suite the test suite to run - * @param outstream the stream the log shall be written to - */ -void ucx_test_run(UcxTestSuite* suite, FILE* outstream); - -/** - * Macro for a #UcxTest function header. - * - * Use this macro to declare and/or define a #UcxTest function. - * - * @param name the name of the test function - */ -#define UCX_TEST(name) void name(UcxTestSuite* _suite_,FILE *_output_) - -/** - * Marks the begin of a test. - * <b>Note:</b> Any UCX_TEST_ASSERT() calls must be performed <b>after</b> - * #UCX_TEST_BEGIN. - * - * @see #UCX_TEST_END - */ -#define UCX_TEST_BEGIN fwrite("Running ", 1, 8, _output_);\ - fwrite(__FUNCTION__, 1, strlen(__FUNCTION__), _output_);\ - fwrite("... ", 1, 4, _output_);\ - jmp_buf _env_; \ - if (!setjmp(_env_)) { - -/** - * Checks a test assertion. - * If the assertion is correct, the test carries on. If the assertion is not - * correct, the specified message (terminated by a dot and a line break) is - * written to the test suites output stream. - * @param condition the condition to check - * @param message the message that shall be printed out on failure - */ -#define UCX_TEST_ASSERT(condition,message) if (!(condition)) { \ - fwrite(message".\n", 1, 2+strlen(message), _output_); \ - _suite_->failure++; \ - longjmp(_env_, 1);\ - } - -/** - * Macro for a test subroutine function header. - * - * Use this to declare and/or define a subroutine that can be called by using - * UCX_TEST_CALL_SUBROUTINE(). - * - * @param name the name of the subroutine - * @param ... the parameter list - * - * @see UCX_TEST_CALL_SUBROUTINE() - */ -#define UCX_TEST_SUBROUTINE(name,...) void name(UcxTestSuite* _suite_,\ - FILE *_output_, jmp_buf _env_, __VA_ARGS__) - -/** - * Macro for calling a test subroutine. - * - * Subroutines declared with UCX_TEST_SUBROUTINE() can be called by using this - * macro. - * - * <b>Note:</b> You may <b>only</b> call subroutines within a #UCX_TEST_BEGIN- - * #UCX_TEST_END-block. - * - * @param name the name of the subroutine - * @param ... the argument list - * - * @see UCX_TEST_SUBROUTINE() - */ -#define UCX_TEST_CALL_SUBROUTINE(name,...) \ - name(_suite_,_output_,_env_,__VA_ARGS__); - -/** - * Marks the end of a test. - * <b>Note:</b> Any UCX_TEST_ASSERT() calls must be performed <b>before</b> - * #UCX_TEST_END. - * - * @see #UCX_TEST_BEGIN - */ -#define UCX_TEST_END fwrite("success.\n", 1, 9, _output_); _suite_->success++;} - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_TEST_H */ -
--- a/ucx/ucx.c Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/** - * @mainpage UAP Common Extensions - * Library with common and useful functions, macros and data structures. - * <p> - * Latest available source:<br/> - * <a href="https://develop.uap-core.de/hg/ucx"> - * https://develop.uap-core.de/hg/ucx</a> - * </p> - * - * <h2>LICENCE</h2> - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "ucx.h"
--- a/ucx/ucx.h Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,145 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/** - * Main UCX Header providing most common definitions. - * - * @file ucx.h - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_H -#define UCX_H - -/** Major UCX version as integer constant. */ -#define UCX_VERSION_MAJOR 0 - -/** Minor UCX version as integer constant. */ -#define UCX_VERSION_MINOR 12 - -#include <stdlib.h> -#include <stdint.h> - -#ifdef _WIN32 -#if !(defined __ssize_t_defined || defined _SSIZE_T_) -#include <BaseTsd.h> -typedef SSIZE_T ssize_t; -#define __ssize_t_defined -#define _SSIZE_T_ -#endif /* __ssize_t_defined and _SSIZE_T */ -#else /* !_WIN32 */ -#include <sys/types.h> -#endif /* _WIN32 */ - -#ifdef __cplusplus -#ifndef _Bool -#define _Bool bool -#define restrict -#endif -/** Use C naming even when compiling with C++. */ -#define UCX_EXTERN extern "C" -extern "C" { -#else -/** Pointless in C. */ -#define UCX_EXTERN -#endif - - -/** - * A function pointer to a destructor function. - * @see ucx_mempool_setdestr() - * @see ucx_mempool_regdestr() - */ -typedef void(*ucx_destructor)(void*); - -/** - * Function pointer to a compare function. - * - * The compare function shall take three arguments: the two values that shall be - * compared and optional additional data. - * The function shall then return -1 if the first argument is less than the - * second argument, 1 if the first argument is greater than the second argument - * and 0 if both arguments are equal. If the third argument is - * <code>NULL</code>, it shall be ignored. - */ -typedef int(*cmp_func)(const void*,const void*,void*); - -/** - * Function pointer to a distance function. - * - * The distance function shall take three arguments: the two values for which - * the distance shall be computed and optional additional data. - * The function shall then return the signed distance as integer value. - */ -typedef intmax_t(*distance_func)(const void*,const void*,void*); - -/** - * Function pointer to a copy function. - * - * The copy function shall create a copy of the first argument and may use - * additional data provided by the second argument. If the second argument is - * <code>NULL</code>, it shall be ignored. - - * <b>Attention:</b> if pointers returned by functions of this type may be - * passed to <code>free()</code> depends on the implementation of the - * respective <code>copy_func</code>. - */ -typedef void*(*copy_func)(const void*,void*); - -/** - * Function pointer to a write function. - * - * The signature of the write function shall be compatible to the signature - * of standard <code>fwrite</code>, though it may use arbitrary data types for - * source and destination. - * - * The arguments shall contain (in ascending order): a pointer to the source, - * the length of one element, the element count and a pointer to the - * destination. - */ -typedef size_t(*write_func)(const void*, size_t, size_t, void*); - -/** - * Function pointer to a read function. - * - * The signature of the read function shall be compatible to the signature - * of standard <code>fread</code>, though it may use arbitrary data types for - * source and destination. - * - * The arguments shall contain (in ascending order): a pointer to the - * destination, the length of one element, the element count and a pointer to - * the source. - */ -typedef size_t(*read_func)(void*, size_t, size_t, void*); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_H */ -
--- a/ucx/utils.c Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,259 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "utils.h" -#include <math.h> -#include <stdio.h> -#include <limits.h> -#include <errno.h> - -/* COPY FUCNTIONS */ -void* ucx_strcpy(const void* s, void* data) { - const char *str = (const char*) s; - size_t n = 1+strlen(str); - char *cpy = (char*) malloc(n); - memcpy(cpy, str, n); - return cpy; -} - -void* ucx_memcpy(const void* m, void* n) { - size_t k = *((size_t*)n); - void *cpy = malloc(k); - memcpy(cpy, m, k); - return cpy; -} - -size_t ucx_stream_bncopy(void *src, void *dest, read_func readfnc, - write_func writefnc, char* buf, size_t bufsize, size_t n) { - if(n == 0 || bufsize == 0) { - return 0; - } - - char *lbuf; - size_t ncp = 0; - - if(buf) { - lbuf = buf; - } else { - lbuf = (char*)malloc(bufsize); - if(lbuf == NULL) { - return 0; - } - } - - size_t r; - size_t rn = bufsize > n ? n : bufsize; - while((r = readfnc(lbuf, 1, rn, src)) != 0) { - r = writefnc(lbuf, 1, r, dest); - ncp += r; - n -= r; - rn = bufsize > n ? n : bufsize; - if(r == 0 || n == 0) { - break; - } - } - - if (lbuf != buf) { - free(lbuf); - } - - return ncp; -} - -/* COMPARE FUNCTIONS */ - -int ucx_strcmp(const void *s1, const void *s2, void *data) { - return strcmp((const char*)s1, (const char*)s2); -} - -int ucx_strncmp(const void *s1, const void *s2, void *n) { - return strncmp((const char*)s1, (const char*)s2, *((size_t*) n)); -} - -int ucx_intcmp(const void *i1, const void *i2, void *data) { - int a = *((const int*) i1); - int b = *((const int*) i2); - if (a == b) { - return 0; - } else { - return a < b ? -1 : 1; - } -} - -int ucx_floatcmp(const void *f1, const void *f2, void *epsilon) { - float a = *((const float*) f1); - float b = *((const float*) f2); - float e = !epsilon ? 1e-6f : *((float*)epsilon); - if (fabsf(a - b) < e) { - return 0; - } else { - return a < b ? -1 : 1; - } -} - -int ucx_doublecmp(const void *d1, const void *d2, void *epsilon) { - double a = *((const double*) d1); - double b = *((const double*) d2); - double e = !epsilon ? 1e-14 : *((double*)epsilon); - if (fabs(a - b) < e) { - return 0; - } else { - return a < b ? -1 : 1; - } -} - -int ucx_ptrcmp(const void *ptr1, const void *ptr2, void *data) { - const intptr_t p1 = (const intptr_t) ptr1; - const intptr_t p2 = (const intptr_t) ptr2; - if (p1 == p2) { - return 0; - } else { - return p1 < p2 ? -1 : 1; - } -} - -int ucx_memcmp(const void *ptr1, const void *ptr2, void *n) { - return memcmp(ptr1, ptr2, *((size_t*)n)); -} - -/* PRINTF FUNCTIONS */ - -#ifdef va_copy -#define UCX_PRINTF_BUFSIZE 256 -#else -#pragma message("WARNING: C99 va_copy macro not supported by this platform" \ - " - limiting ucx_*printf to 2 KiB") -#define UCX_PRINTF_BUFSIZE 0x800 -#endif - -int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...) { - int ret; - va_list ap; - va_start(ap, fmt); - ret = ucx_vfprintf(stream, wfc, fmt, ap); - va_end(ap); - return ret; -} - -int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap) { - char buf[UCX_PRINTF_BUFSIZE]; -#ifdef va_copy - va_list ap2; - va_copy(ap2, ap); - int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); - if (ret < 0) { - return ret; - } else if (ret < UCX_PRINTF_BUFSIZE) { - return (int)wfc(buf, 1, ret, stream); - } else { - if (ret == INT_MAX) { - errno = ENOMEM; - return -1; - } - - int len = ret + 1; - char *newbuf = (char*)malloc(len); - if (!newbuf) { - return -1; - } - - ret = vsnprintf(newbuf, len, fmt, ap2); - if (ret > 0) { - ret = (int)wfc(newbuf, 1, ret, stream); - } - free(newbuf); - } - return ret; -#else - int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); - if (ret < 0) { - return ret; - } else if (ret < UCX_PRINTF_BUFSIZE) { - return (int)wfc(buf, 1, ret, stream); - } else { - errno = ENOMEM; - return -1; - } -#endif -} - -sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...) { - va_list ap; - sstr_t ret; - va_start(ap, fmt); - ret = ucx_vasprintf(allocator, fmt, ap); - va_end(ap); - return ret; -} - -sstr_t ucx_vasprintf(UcxAllocator *a, const char *fmt, va_list ap) { - sstr_t s; - s.ptr = NULL; - s.length = 0; - char buf[UCX_PRINTF_BUFSIZE]; -#ifdef va_copy - va_list ap2; - va_copy(ap2, ap); - int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); - if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) { - s.ptr = (char*)almalloc(a, ret + 1); - if (s.ptr) { - s.length = (size_t)ret; - memcpy(s.ptr, buf, ret); - s.ptr[s.length] = '\0'; - } - } else if (ret == INT_MAX) { - errno = ENOMEM; - } else { - int len = ret + 1; - s.ptr = (char*)almalloc(a, len); - if (s.ptr) { - ret = vsnprintf(s.ptr, len, fmt, ap2); - if (ret < 0) { - free(s.ptr); - s.ptr = NULL; - } else { - s.length = (size_t)ret; - } - } - } -#else - int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); - if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) { - s.ptr = (char*)almalloc(a, ret + 1); - if (s.ptr) { - s.length = (size_t)ret; - memcpy(s.ptr, buf, ret); - s.ptr[s.length] = '\0'; - } - } else { - errno = ENOMEM; - } -#endif - return s; -}
--- a/ucx/utils.h Tue Oct 17 15:15:54 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,281 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2017 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file utils.h - * - * Compare, copy and printf functions. - * - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_UTILS_H -#define UCX_UTILS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "ucx.h" -#include "string.h" -#include "allocator.h" -#include <inttypes.h> -#include <string.h> -#include <stdarg.h> - -/** - * Default buffer size for ucx_stream_copy() and ucx_stream_ncopy(). - */ -#define UCX_STREAM_COPY_BUFSIZE 4096 - -/** - * Copies a string. - * @param s the string to copy - * @param data omitted - * @return a pointer to a copy of s1 that can be passed to free(void*) - */ -void *ucx_strcpy(const void *s, void *data); - -/** - * Copies a memory area. - * @param m a pointer to the memory area - * @param n a pointer to the size_t containing the size of the memory area - * @return a pointer to a copy of the specified memory area that can - * be passed to free(void*) - */ -void *ucx_memcpy(const void *m, void *n); - - -/** - * Reads data from a stream and writes it to another stream. - * - * @param src the source stream - * @param dest the destination stream - * @param rfnc the read function - * @param wfnc the write function - * @param buf a pointer to the copy buffer or <code>NULL</code> if a buffer - * shall be implicitly created on the heap - * @param bufsize the size of the copy buffer - if <code>NULL</code> was - * provided for <code>buf</code>, this is the size of the buffer that shall be - * implicitly created - * @param n the maximum number of bytes that shall be copied - * @return the total number of bytes copied - */ -size_t ucx_stream_bncopy(void *src, void *dest, read_func rfnc, write_func wfnc, - char* buf, size_t bufsize, size_t n); - -/** - * Shorthand for an unbounded ucx_stream_bncopy call using a default buffer. - * - * @param src the source stream - * @param dest the destination stream - * @param rfnc the read function - * @param wfnc the write function - * @return total number of bytes copied - * - * @see #UCX_STREAM_COPY_BUFSIZE - */ -#define ucx_stream_copy(src,dest,rfnc,wfnc) ucx_stream_bncopy(\ - src, dest, (read_func)rfnc, (write_func)wfnc, \ - NULL, UCX_STREAM_COPY_BUFSIZE, (size_t)-1) - -/** - * Shorthand for ucx_stream_bncopy using a default copy buffer. - * - * @param src the source stream - * @param dest the destination stream - * @param rfnc the read function - * @param wfnc the write function - * @param n maximum number of bytes that shall be copied - * @return total number of bytes copied - */ -#define ucx_stream_ncopy(src,dest,rfnc,wfnc, n) ucx_stream_bncopy(\ - src, dest, (read_func)rfnc, (write_func)wfnc, \ - NULL, UCX_STREAM_COPY_BUFSIZE, n) - -/** - * Shorthand for an unbounded ucx_stream_bncopy call using the specified buffer. - * - * @param src the source stream - * @param dest the destination stream - * @param rfnc the read function - * @param wfnc the write function - * @param buf a pointer to the copy buffer or <code>NULL</code> if a buffer - * shall be implicitly created on the heap - * @param bufsize the size of the copy buffer - if <code>NULL</code> was - * provided for <code>buf</code>, this is the size of the buffer that shall be - * implicitly created - * @return total number of bytes copied - */ -#define ucx_stream_bcopy(src,dest,rfnc,wfnc, buf, bufsize) ucx_stream_bncopy(\ - src, dest, (read_func)rfnc, (write_func)wfnc, \ - buf, bufsize, (size_t)-1) - -/** - * Wraps the strcmp function. - * @param s1 string one - * @param s2 string two - * @param data omitted - * @return the result of strcmp(s1, s2) - */ -int ucx_strcmp(const void *s1, const void *s2, void *data); - -/** - * Wraps the strncmp function. - * @param s1 string one - * @param s2 string two - * @param n a pointer to the size_t containing the third strncmp parameter - * @return the result of strncmp(s1, s2, *n) - */ -int ucx_strncmp(const void *s1, const void *s2, void *n); - -/** - * Compares two integers of type int. - * @param i1 pointer to integer one - * @param i2 pointer to integer two - * @param data omitted - * @return -1, if *i1 is less than *i2, 0 if both are equal, - * 1 if *i1 is greater than *i2 - */ -int ucx_intcmp(const void *i1, const void *i2, void *data); - -/** - * Compares two real numbers of type float. - * @param f1 pointer to float one - * @param f2 pointer to float two - * @param data if provided: a pointer to precision (default: 1e-6f) - * @return -1, if *f1 is less than *f2, 0 if both are equal, - * 1 if *f1 is greater than *f2 - */ - -int ucx_floatcmp(const void *f1, const void *f2, void *data); - -/** - * Compares two real numbers of type double. - * @param d1 pointer to double one - * @param d2 pointer to double two - * @param data if provided: a pointer to precision (default: 1e-14) - * @return -1, if *d1 is less than *d2, 0 if both are equal, - * 1 if *d1 is greater than *d2 - */ -int ucx_doublecmp(const void *d1, const void *d2, void *data); - -/** - * Compares two pointers. - * @param ptr1 pointer one - * @param ptr2 pointer two - * @param data omitted - * @return -1 if ptr1 is less than ptr2, 0 if both are equal, - * 1 if ptr1 is greater than ptr2 - */ -int ucx_ptrcmp(const void *ptr1, const void *ptr2, void *data); - -/** - * Compares two memory areas. - * @param ptr1 pointer one - * @param ptr2 pointer two - * @param n a pointer to the size_t containing the third parameter for memcmp - * @return the result of memcmp(ptr1, ptr2, *n) - */ -int ucx_memcmp(const void *ptr1, const void *ptr2, void *n); - -/** - * A <code>printf()</code> like function which writes the output to a stream by - * using a write_func(). - * @param stream the stream the data is written to - * @param wfc the write function - * @param fmt format string - * @param ... additional arguments - * @return the total number of bytes written - */ -int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...); - -/** - * <code>va_list</code> version of ucx_fprintf(). - * @param stream the stream the data is written to - * @param wfc the write function - * @param fmt format string - * @param ap argument list - * @return the total number of bytes written - * @see ucx_fprintf() - */ -int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap); - -/** - * A <code>printf()</code> like function which allocates space for a sstr_t - * the result is written to. - * - * <b>Attention</b>: The sstr_t data is allocated with the allocators - * ucx_allocator_malloc() function. So it is implementation dependent, if - * the returned sstr_t.ptr pointer must be passed to the allocators - * ucx_allocator_free() function manually. - * - * <b>Note</b>: The sstr_t.ptr of the return value will <i>always</i> be - * <code>NULL</code>-terminated. - * - * @param allocator the UcxAllocator used for allocating the result sstr_t - * @param fmt format string - * @param ... additional arguments - * @return a sstr_t containing the formatted string - */ -sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...); - -/** - * <code>va_list</code> version of ucx_asprintf(). - * - * @param allocator the UcxAllocator used for allocating the result sstr_t - * @param fmt format string - * @param ap argument list - * @return a sstr_t containing the formatted string - * @see ucx_asprintf() - */ -sstr_t ucx_vasprintf(UcxAllocator *allocator, const char *fmt, va_list ap); - -/** Shortcut for ucx_asprintf() with default allocator. */ -#define ucx_sprintf(...) \ - ucx_asprintf(ucx_default_allocator(), __VA_ARGS__) - -/** - * A <code>printf()</code> like function which writes the output to a - * UcxBuffer. - * - * @param buffer the buffer the data is written to - * @param ... format string and additional arguments - * @return the total number of bytes written - * @see ucx_fprintf() - */ -#define ucx_bprintf(buffer, ...) ucx_fprintf((UcxBuffer*)buffer, \ - (write_func)ucx_buffer_write, __VA_ARGS__) - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_UTILS_H */ -