added stack implementation + added g++ config and added some fixes for C++

Mon, 28 Jul 2014 14:36:25 +0200

author
Mike Becker <universe@uap-core.de>
date
Mon, 28 Jul 2014 14:36:25 +0200
changeset 185
a48428642b4e
parent 184
5c0990c95f74
child 186
05559c99010d

added stack implementation + added g++ config and added some fixes for C++

g++.mk file | annotate | diff | comparison | revisions
test/Makefile file | annotate | diff | comparison | revisions
test/buffer_tests.c file | annotate | diff | comparison | revisions
test/logging_tests.c file | annotate | diff | comparison | revisions
test/main.c file | annotate | diff | comparison | revisions
test/stack_tests.c file | annotate | diff | comparison | revisions
test/stack_tests.h file | annotate | diff | comparison | revisions
ucx/stack.c file | annotate | diff | comparison | revisions
ucx/stack.h file | annotate | diff | comparison | revisions
ucx/string.c file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/g++.mk	Mon Jul 28 14:36:25 2014 +0200
@@ -0,0 +1,46 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2014 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.
+#
+
+CC    = g++
+LD    = g++
+AR    = ar
+RM    = rm
+MKDIR = mkdir
+
+CFLAGS     = -O2 -fstrict-aliasing -fPIC
+CFLAGS_D   = -g -fstrict-aliasing -Wall -Wno-variadic-macros -pedantic -fPIC
+LDFLAGS    = 
+SOLDFLAGS  = -shared
+ARFLAGS    = -r
+RMFLAGS    = -f -R
+MKDIRFLAGS = -p
+
+OBJ_EXT = .o
+SO_EXT  = .so
+LIB_EXT = .a
+APP_EXT =
--- a/test/Makefile	Mon Jul 21 13:18:32 2014 +0200
+++ b/test/Makefile	Mon Jul 28 14:36:25 2014 +0200
@@ -32,6 +32,7 @@
 SRC += allocator_tests.c
 SRC += list_tests.c
 SRC += mpool_tests.c
+SRC += stack_tests.c
 SRC += map_tests.c
 SRC += prop_tests.c
 SRC += string_tests.c
--- a/test/buffer_tests.c	Mon Jul 21 13:18:32 2014 +0200
+++ b/test/buffer_tests.c	Mon Jul 28 14:36:25 2014 +0200
@@ -70,7 +70,7 @@
 }
 
 UCX_TEST(test_ucx_buffer_eof) {
-    char *test = "0123456789ABCDEF";
+    char *test = (char*)"0123456789ABCDEF";
     UcxBuffer *b = ucx_buffer_new(test, 16, UCX_BUFFER_DEFAULT);
     UCX_TEST_BEGIN
     b->pos = 9; b->size = 10;
--- a/test/logging_tests.c	Mon Jul 21 13:18:32 2014 +0200
+++ b/test/logging_tests.c	Mon Jul 28 14:36:25 2014 +0200
@@ -50,16 +50,16 @@
         "incorrect number of registered log levels");
 
     int level = UCX_LOGGER_ERROR;
-    UCX_TEST_ASSERT(strcmp(ucx_map_int_get(logger->levels, level),
+    UCX_TEST_ASSERT(strcmp((char*)ucx_map_int_get(logger->levels, level),
         "[ERROR]") == 0, "invalid error level");
     level = UCX_LOGGER_WARN;
-    UCX_TEST_ASSERT(strcmp(ucx_map_int_get(logger->levels, level),
+    UCX_TEST_ASSERT(strcmp((char*)ucx_map_int_get(logger->levels, level),
         "[WARNING]") == 0, "invalid warning level");
     level = UCX_LOGGER_INFO;
-    UCX_TEST_ASSERT(strcmp(ucx_map_int_get(logger->levels, level),
+    UCX_TEST_ASSERT(strcmp((char*)ucx_map_int_get(logger->levels, level),
         "[INFO]") == 0, "invalid info level");
     level = UCX_LOGGER_TRACE;
-    UCX_TEST_ASSERT(strcmp(ucx_map_int_get(logger->levels, level),
+    UCX_TEST_ASSERT(strcmp((char*)ucx_map_int_get(logger->levels, level),
         "[TRACE]") == 0, "invalid trace level");
 
     UCX_TEST_END
@@ -75,7 +75,7 @@
 
     UcxLogger *logger = ucx_logger_new(stream,
             UCX_LOGGER_INFO, UCX_LOGGER_SOURCE | UCX_LOGGER_LEVEL);
-    logger->dateformat = "%F:";
+    logger->dateformat = (char*) "%F:";
     
     UCX_TEST_BEGIN
     const uint line1 = __LINE__; ucx_logger_info(logger, "allright");
@@ -92,7 +92,7 @@
     size_t r = fread(buffer, 1, 100, stream);
     
     const size_t expected_length = 87;
-    char expected[expected_length+1];
+    char expected[88];
     snprintf(expected, expected_length+1,
         "[INFO] logging_tests.c:%u - allright\n"
         "[ERROR] %slogging_tests.c:%u - error 42!\n", line1, timestr, line2);
--- a/test/main.c	Mon Jul 21 13:18:32 2014 +0200
+++ b/test/main.c	Mon Jul 28 14:36:25 2014 +0200
@@ -38,6 +38,7 @@
 #include "list_tests.h"
 #include "string_tests.h"
 #include "mpool_tests.h"
+#include "stack_tests.h"
 #include "map_tests.h"
 #include "prop_tests.h"
 #include "buffer_tests.h"
@@ -156,6 +157,14 @@
         ucx_test_register(suite, test_ucx_mempool_set_destr);
         ucx_test_register(suite, test_ucx_mempool_reg_destr);
         ucx_test_register(suite, test_ucx_mempool_realloc);
+        
+        /* UcxStack Tests */
+        ucx_test_register(suite, test_ucx_stack_init);
+        ucx_test_register(suite, test_ucx_stack_malloc);
+        ucx_test_register(suite, test_ucx_stack_calloc);
+        ucx_test_register(suite, test_ucx_stack_free);
+        ucx_test_register(suite, test_ucx_stack_realloc);
+        ucx_test_register(suite, test_ucx_stack_pop);
 
         /* UcxMap Tests */
         ucx_test_register(suite, test_ucx_map_new);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/stack_tests.c	Mon Jul 28 14:36:25 2014 +0200
@@ -0,0 +1,209 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 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_tests.h"
+
+#define test_ucx_stack_before \
+    char space[100]; \
+    UcxStack stack; \
+    ucx_stack_init(&stack, space, 100) \
+
+UCX_TEST(test_ucx_stack_init) {
+    
+    test_ucx_stack_before;
+    
+    UCX_TEST_BEGIN
+    
+    UCX_TEST_ASSERT(
+        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 &&
+        stack.allocator.pool == &stack,
+        "allocator not properly set");
+    
+    UCX_TEST_ASSERT(!stack.top && stack.space == space
+        && stack.size == 100 - 100 % sizeof(void*),
+        "struct fields not properly set");
+    
+    UCX_TEST_END
+}
+
+UCX_TEST(test_ucx_stack_malloc) {
+
+    test_ucx_stack_before;
+    
+    const size_t metasize = sizeof(struct ucx_stack_metadata);
+    
+    
+    char* first = (char*) ucx_stack_malloc(&stack, 30);
+    char* second = (char*) ucx_stack_malloc(&stack, 30);
+    char* full = (char*) ucx_stack_malloc(&stack, 30);
+    
+    memcpy(first,  "012345678901234567890123456789", 30);
+    memcpy(second, "abcdefghijklmnopqrstuvwxyzABCD", 30);
+    
+    UCX_TEST_BEGIN
+    
+    UCX_TEST_ASSERT(!memcmp(space + metasize,
+        "012345678901234567890123456789", 30), "first element corrupted");
+    UCX_TEST_ASSERT(!memcmp(space + 32+2*metasize,
+        "abcdefghijklmnopqrstuvwxyzABCD", 30), "first element corrupted");
+    
+    UCX_TEST_ASSERT(!full, "stack can be overflowed");
+    UCX_TEST_ASSERT(stack.top == space + 32 + 2*metasize, "wrong top pointer");
+
+    if (3*metasize < 32) {
+        UCX_TEST_ASSERT(ucx_stack_avail(&stack) == 32-3*metasize,
+            "wrong remaining available memory");
+    } else {
+        UCX_TEST_ASSERT(ucx_stack_avail(&stack) == 0,
+            "wrong remaining available memory");
+    }
+
+    UCX_TEST_END
+}
+
+UCX_TEST(test_ucx_stack_calloc) {
+    
+    test_ucx_stack_before;
+
+    char zeros[100];
+    memset(zeros, 0, 100);
+    memset(space, 32, 100);
+    ucx_stack_calloc(&stack, 4, sizeof(int));
+    
+    UCX_TEST_BEGIN
+    
+    UCX_TEST_ASSERT(!memcmp(space+sizeof(struct ucx_stack_metadata),
+        zeros, 4*sizeof(int)), "memory not nulled");
+    UCX_TEST_ASSERT(!memcmp(space+sizeof(struct ucx_stack_metadata)
+        +4*sizeof(int), "          ", 10), "too much memory nulled");
+        
+    UCX_TEST_END
+}
+
+UCX_TEST(test_ucx_stack_free) {
+    
+    test_ucx_stack_before;
+    
+    void *fst = ucx_stack_malloc(&stack, 10);
+    void *snd = ucx_stack_malloc(&stack, 10);
+    void *thrd = ucx_stack_malloc(&stack, 10);
+    
+    UCX_TEST_BEGIN
+    
+    UCX_TEST_ASSERT(stack.top == thrd, "wrong stack");
+    UCX_TEST_ASSERT(((struct ucx_stack_metadata*) thrd - 1)->prev == snd,
+        "wrong thrd prev pointer before free");
+    
+    ucx_stack_free(&stack, snd);
+    
+    UCX_TEST_ASSERT(((struct ucx_stack_metadata*) thrd - 1)->prev == fst,
+        "wrong thrd prev pointer after freeing snd");
+    UCX_TEST_ASSERT(stack.top == thrd, "wrong top after freeing snd");
+    
+    ucx_stack_free(&stack, thrd);
+
+    UCX_TEST_ASSERT(stack.top == fst, "wrong top after freeing thrd");
+    
+    UCX_TEST_END
+}
+
+UCX_TEST(test_ucx_stack_realloc) {
+    
+    test_ucx_stack_before;
+    
+    void *fst = ucx_stack_malloc(&stack, 10);
+    void *snd = ucx_stack_malloc(&stack, 10);
+    
+    UCX_TEST_BEGIN
+    
+    void *nfst = ucx_stack_realloc(&stack, fst, 16);
+    UCX_TEST_ASSERT(nfst == fst, "unnecessary move on reallocation");
+    UCX_TEST_ASSERT(((struct ucx_stack_metadata*)fst - 1)->size == 16,
+        "wrong size after reallocation");
+    
+    void *nsnd = ucx_stack_realloc(&stack, snd, 30);
+    UCX_TEST_ASSERT(nsnd == snd, "unnecessary move on top reallocation");
+    UCX_TEST_ASSERT(ucx_stack_topsize(&stack) == 30,
+        "wrong size after top reallocation");
+    
+    nsnd = ucx_stack_realloc(&stack, snd, 5);
+    UCX_TEST_ASSERT(nsnd == snd, "unnecessary move on top shrink");
+    UCX_TEST_ASSERT(ucx_stack_topsize(&stack) == 5,
+        "wrong size after top shrink");
+    UCX_TEST_ASSERT(ucx_stack_avail(&stack) ==
+        72-3*sizeof(struct ucx_stack_metadata), "wrong size after top shrink");
+    
+    nfst = ucx_stack_realloc(&stack, fst, 24);
+    UCX_TEST_ASSERT(nfst != fst, "missing move on huge reallocation");
+    UCX_TEST_ASSERT(stack.top == nfst, "wrong top after huge reallocation");
+    UCX_TEST_ASSERT(ucx_stack_topsize(&stack) == 24,
+        "wrong size after huge reallocation");
+    UCX_TEST_ASSERT(!((struct ucx_stack_metadata*)snd - 1)->prev,
+        "element not freed after huge reallocation");
+    
+    UCX_TEST_END
+}
+
+UCX_TEST(test_ucx_stack_pop) {
+    
+    test_ucx_stack_before;
+    memset(space, 32, 100);
+    
+    void *fst = ucx_stack_malloc(&stack, 10);
+    void *snd = ucx_stack_malloc(&stack, 10);
+    ucx_stack_malloc(&stack, 10);
+    
+    char buf[16];
+    
+    UCX_TEST_BEGIN
+    
+    memset(buf, '0', 16);
+    ucx_stack_pop(&stack, buf);
+    UCX_TEST_ASSERT(memcmp(buf, "          000000", 16) == 0,
+        "popped wrong content");
+    UCX_TEST_ASSERT(stack.top == snd, "wrong top after pop");
+    
+    memset(buf, '0', 16);
+    ucx_stack_popn(&stack, buf, 5);
+    UCX_TEST_ASSERT(memcmp(buf, "     00000000000", 16) == 0,
+        "n-popped wrong content");
+    UCX_TEST_ASSERT(stack.top == fst, "wrong top after pop");
+    
+    ucx_stack_pop(&stack, buf);
+    UCX_TEST_ASSERT(!stack.top, "top not NULL after last pop");
+    
+    memset(buf, '0', 16);
+    ucx_stack_pop(&stack, buf);
+    UCX_TEST_ASSERT(memcmp(buf, "0000000000000000", 16) == 0,
+        "content not unchanged after empty pop");
+    
+    UCX_TEST_END
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/stack_tests.h	Mon Jul 28 14:36:25 2014 +0200
@@ -0,0 +1,51 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 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.
+ */
+
+#ifndef STACK_TESTS_H
+#define	STACK_TESTS_H
+
+#include "ucx/test.h"
+#include "ucx/stack.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+UCX_TEST(test_ucx_stack_init);
+UCX_TEST(test_ucx_stack_malloc);
+UCX_TEST(test_ucx_stack_calloc);
+UCX_TEST(test_ucx_stack_free);
+UCX_TEST(test_ucx_stack_realloc);
+UCX_TEST(test_ucx_stack_pop);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* STACK_TESTS_H */
+
--- a/ucx/stack.c	Mon Jul 21 13:18:32 2014 +0200
+++ b/ucx/stack.c	Mon Jul 28 14:36:25 2014 +0200
@@ -29,35 +29,43 @@
 #include "stack.h"
 #include <string.h>
 
-UcxStack ucx_stack_new(char* space, size_t size) {
-    UcxStack stack;
-    stack.size = size;
-    stack.space = stack.top = space;
+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;
     
-    UcxAllocator alloc;
-    alloc.pool = &stack;
-    alloc.malloc = (ucx_allocator_malloc) ucx_stack_malloc;
-    alloc.calloc = (ucx_allocator_calloc) ucx_stack_calloc;
-    alloc.realloc = (ucx_allocator_realloc) ucx_stack_realloc;
-    alloc.free = (ucx_allocator_free) ucx_stack_free;
-    
-    stack.allocator = alloc;
-    
-    return stack;
+    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) {
-    n += n % sizeof(void*);
 
-    if (stack->top + n + sizeof(size_t) > stack->space + stack->size) {
+    if (ucx_stack_avail(stack) < ucx_stack_align(n)) {
         return NULL;
     } else {
-        void *ptr = stack->top;
+        char *prev = stack->top;
+        if (stack->top) {
+            stack->top += ucx_stack_align(ucx_stack_topsize(stack));
+        } else {
+            stack->top = stack->space;
+        }
         
-        *((size_t*) (stack->top + n)) = n;
-        stack->top += n + sizeof(size_t);
+        ((struct ucx_stack_metadata*)stack->top)->prev = prev;
+        ((struct ucx_stack_metadata*)stack->top)->size = n;
+        stack->top += sizeof(struct ucx_stack_metadata);
         
-        return ptr;
+        return stack->top;
     }
 }
 
@@ -68,41 +76,68 @@
 }
 
 void *ucx_stack_realloc(UcxStack *stack, void *ptr, size_t n) {
-    if (ptr == stack->top - sizeof(size_t) - *((size_t*) stack->top - 1)) {
-
-        stack->top = (char*)ptr + n;
-        *((size_t*)stack->top) = n;
-        stack->top += sizeof(size_t);
-        
-        return ptr;
+    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 {
-        size_t* sptr = (size_t*) (((char*) ptr)-sizeof(size_t));
-        if (*sptr < n) {
+        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, *sptr);
+                memcpy(nptr, ptr, n);
                 ucx_stack_free(stack, ptr);
+                
                 return nptr;
             } else {
                 return NULL;
             }
         } else {
-            *sptr = n;
+            ((struct ucx_stack_metadata*)ptr - 1)->size = n;
             return ptr;
         }
     }
 }
 
 void ucx_stack_free(UcxStack *stack, void *ptr) {
-    if (ptr == stack->top+sizeof(size_t)) {
-        
+    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_pop(UcxStack *stack, void *dest) {
+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);
 }
 
-void ucx_stack_popn(UcxStack *stack, void *dest, size_t n) {
+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	Mon Jul 21 13:18:32 2014 +0200
+++ b/ucx/stack.h	Mon Jul 28 14:36:25 2014 +0200
@@ -39,7 +39,7 @@
 #define	UCX_STACK_H
 
 #include "ucx.h"
-#include <stddef.h>
+#include <stdint.h>
 #include "allocator.h"
 
 #ifdef	__cplusplus
@@ -65,13 +65,27 @@
 } UcxStack;
 
 /**
- * Wraps memory in a new UcxStack structure.
+ * 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
  */
-UcxStack ucx_stack_new(char* space, size_t size);
+void ucx_stack_init(UcxStack *stack, char* space, size_t size);
 
 /**
  * Allocates stack memory.
@@ -149,7 +163,8 @@
  * @param stack a pointer to the stack
  * @return the size of the top most element
  */
-#define ucx_stack_topsize(stack) (*(((size_t*)stack->top - 1))
+#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>
@@ -164,7 +179,7 @@
  * @see ucx_stack_free
  * @see ucx_stack_popn
  */
-void ucx_stack_pop(UcxStack *stack, void *dest);
+#define ucx_stack_pop(stack, dest) ucx_stack_popn(stack, dest, SIZE_MAX)
 
 /**
  * Removes the top most element from the stack and copies the content to <code>
@@ -186,8 +201,28 @@
  * @param stack a pointer to the stack
  * @return the remaining available memory
  */
-#define ucx_stack_avail(stack) ((stack->size)  - (s.top - s.space)\
-                                - sizeof(size_t))
+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
--- a/ucx/string.c	Mon Jul 21 13:18:32 2014 +0200
+++ b/ucx/string.c	Mon Jul 28 14:36:25 2014 +0200
@@ -74,7 +74,7 @@
         return str;
     }
     
-    sstr_t *strings = calloc(count, sizeof(sstr_t));
+    sstr_t *strings = (sstr_t*) calloc(count, sizeof(sstr_t));
     if(!strings) {
         return str;
     }
@@ -90,7 +90,7 @@
     }
     
     // create new string
-    str.ptr = almalloc(a, strlen + 1);
+    str.ptr = (char*) almalloc(a, strlen + 1);
     str.length = strlen;
     if(!str.ptr) {
         free(strings);

mercurial