update ucx

Mon, 10 Jul 2023 18:39:24 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 10 Jul 2023 18:39:24 +0200
changeset 504
c094afcdfb27
parent 503
aeaf7db26fac
child 505
d41fc7f37aed

update ucx

src/server/Makefile file | annotate | diff | comparison | revisions
src/server/config/Makefile file | annotate | diff | comparison | revisions
src/server/daemon/Makefile file | annotate | diff | comparison | revisions
src/server/safs/Makefile file | annotate | diff | comparison | revisions
src/server/test/Makefile file | annotate | diff | comparison | revisions
src/server/util/Makefile file | annotate | diff | comparison | revisions
src/server/webdav/Makefile file | annotate | diff | comparison | revisions
src/tools/Makefile file | annotate | diff | comparison | revisions
src/ucx/Makefile file | annotate | diff | comparison | revisions
src/ucx/allocator.c file | annotate | diff | comparison | revisions
src/ucx/array_list.c file | annotate | diff | comparison | revisions
src/ucx/basic_mempool.c file | annotate | diff | comparison | revisions
src/ucx/cx/allocator.h file | annotate | diff | comparison | revisions
src/ucx/cx/basic_mempool.h file | annotate | diff | comparison | revisions
src/ucx/cx/collection.h file | annotate | diff | comparison | revisions
src/ucx/cx/hash_map.h file | annotate | diff | comparison | revisions
src/ucx/cx/iterator.h file | annotate | diff | comparison | revisions
src/ucx/cx/list.h file | annotate | diff | comparison | revisions
src/ucx/cx/map.h file | annotate | diff | comparison | revisions
src/ucx/cx/mempool.h file | annotate | diff | comparison | revisions
src/ucx/cx/tree.h file | annotate | diff | comparison | revisions
src/ucx/cx/utils.h file | annotate | diff | comparison | revisions
src/ucx/hash_map.c file | annotate | diff | comparison | revisions
src/ucx/linked_list.c file | annotate | diff | comparison | revisions
src/ucx/list.c file | annotate | diff | comparison | revisions
src/ucx/map.c file | annotate | diff | comparison | revisions
src/ucx/mempool.c file | annotate | diff | comparison | revisions
src/ucx/tree.c file | annotate | diff | comparison | revisions
src/ucx/utils.c file | annotate | diff | comparison | revisions
--- a/src/server/Makefile	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/server/Makefile	Mon Jul 10 18:39:24 2023 +0200
@@ -62,7 +62,8 @@
 OBJ_DIRS = daemon safs ucx util webdav config admin plugins test
 MK_OBJ_DIRS = $(OBJ_DIRS:%=$(OBJ_DIR)server/%)
 
-CFLAGS += -I../ucx/
+WS_CFLAGS = -I../ucx/
+
 LDFLAGS += -lucx
 
 preparation: $(MK_OBJ_DIRS)
--- a/src/server/config/Makefile	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/server/config/Makefile	Mon Jul 10 18:39:24 2023 +0200
@@ -27,5 +27,5 @@
 #
 
 $(CONF_OBJPRE)%.o: config/%.c
-	$(CC) -o $@ -c $(CFLAGS) $(SHLIB_CFLAGS) $<
+	$(CC) -o $@ -c $(WS_CFLAGS) $(CFLAGS) $(SHLIB_CFLAGS) $<
 
--- a/src/server/daemon/Makefile	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/server/daemon/Makefile	Mon Jul 10 18:39:24 2023 +0200
@@ -29,8 +29,6 @@
 DMN_CFLAGS = 
 
 $(DMN_OBJPRE)%.o: daemon/%.c
-	$(CC) -o $@ -c $(DMN_CFLAGS) $(CFLAGS) $<
+	$(CC) -o $@ -c $(WS_CFLAGS) $(DMN_CFLAGS) $(CFLAGS) $<
 
-$(DMN_OBJPRE)%.o: daemon/%.cpp
-	$(CXX) -o $@ -c $(DMN_CFLAGS) $(CFLAGS) $<
 	
--- a/src/server/safs/Makefile	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/server/safs/Makefile	Mon Jul 10 18:39:24 2023 +0200
@@ -29,8 +29,6 @@
 SAFS_CFLAGS = 
 
 $(SAFS_OBJPRE)%.o: safs/%.c
-	$(CC) -o $@ -c $(SAFS_CFLAGS) $(CFLAGS) $<
+	$(CC) -o $@ -c $(WS_CFLAGS) $(SAFS_CFLAGS) $(CFLAGS) $<
 
-$(SAFS_OBJPRE)%.o: /safs/%.cpp
-	$(CXX) -o $@ -c $(SAFS_CFLAGS) $(CFLAGS) $<
 	
--- a/src/server/test/Makefile	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/server/test/Makefile	Mon Jul 10 18:39:24 2023 +0200
@@ -29,8 +29,6 @@
 TEST_CFLAGS = 
 
 $(TEST_OBJPRE)%.o: test/%.c
-	$(CC) -o $@ -c $(TEST_CFLAGS) $(CFLAGS) $<
+	$(CC) -o $@ -c $(WS_CFLAGS) $(TEST_CFLAGS) $(CFLAGS) $<
 
-$(TEST_OBJPRE)%.o: test/%.cpp
-	$(CXX) -o $@ -c $(TEST_CFLAGS) $(CFLAGS) $<
 	
--- a/src/server/util/Makefile	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/server/util/Makefile	Mon Jul 10 18:39:24 2023 +0200
@@ -29,4 +29,4 @@
 UTIL_CFLAGS = 
 
 $(UTIL_OBJPRE)%.o: util/%.c
-	$(CC) -o $@ -c $(UTIL_CFLAGS) $(CFLAGS) $<
+	$(CC) -o $@ -c $(WS_CFLAGS) $(UTIL_CFLAGS) $(CFLAGS) $<
--- a/src/server/webdav/Makefile	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/server/webdav/Makefile	Mon Jul 10 18:39:24 2023 +0200
@@ -29,8 +29,8 @@
 DAV_CFLAGS = 
 
 $(DAV_OBJPRE)%.o: webdav/%.c
-	$(CC) -o $@ -c $(DAV_CFLAGS) $(CFLAGS) $<
+	$(CC) -o $@ -c $(WS_CFLAGS) $(DAV_CFLAGS) $(CFLAGS) $<
 
 $(DAV_OBJPRE)%.o: webdav/%.cpp
-	$(CXX) -o $@ -c $(DAV_CFLAGS) $(CFLAGS) $<
+	$(CXX) -o $@ -c $(WS_CFLAGS) $(DAV_CFLAGS) $(CFLAGS) $<
 	
--- a/src/tools/Makefile	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/tools/Makefile	Mon Jul 10 18:39:24 2023 +0200
@@ -30,7 +30,8 @@
 
 include $(BUILD_ROOT)/config.mk
 
-CFLAGS += -I../ucx/
+WSTOOL_CFLAGS = -I../ucx/
+
 LDFLAGS += -lucx -lwscfg
 
 # list of source files
@@ -45,7 +46,7 @@
 	$(CC) -o $@ $(WSTOOL_OBJ) -L$(BUILD_ROOT)/build/lib $(LDFLAGS) $(RPATH_WS_LIB_FLAG)
 
 $(BUILD_ROOT)/build/tools/%$(OBJ_EXT): %.c
-	$(CC) $(CFLAGS) -c -o $@ $<
+	$(CC) $(WSTOOL_CFLAGS) $(CFLAGS) -c -o $@ $<
 
 $(BUILD_ROOT)/build/tools:
 	mkdir -p $(BUILD_ROOT)/build/tools
--- a/src/ucx/Makefile	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/ucx/Makefile	Mon Jul 10 18:39:24 2023 +0200
@@ -32,7 +32,7 @@
 
 # list of source files
 SRC  = allocator.c
-SRC += basic_mempool.c
+SRC += mempool.c
 SRC += buffer.c
 SRC += hash_key.c
 SRC += hash_map.c
@@ -40,7 +40,6 @@
 SRC += array_list.c
 SRC += list.c
 SRC += string.c
-SRC += tree.c
 SRC += utils.c
 SRC += printf.c
 SRC += compare.c
--- a/src/ucx/allocator.c	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/ucx/allocator.c	Mon Jul 10 18:39:24 2023 +0200
@@ -75,6 +75,20 @@
 };
 CxAllocator *cxDefaultAllocator = &cx_default_allocator;
 
+
+int cx_reallocate(
+        void **mem,
+        size_t n
+) {
+    void *nmem = realloc(*mem, n);
+    if (nmem == NULL) {
+        return 1;
+    } else {
+        *mem = nmem;
+        return 0;
+    }
+}
+
 // IMPLEMENTATION OF HIGH LEVEL API
 
 void *cxMalloc(
--- a/src/ucx/array_list.c	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/ucx/array_list.c	Mon Jul 10 18:39:24 2023 +0200
@@ -103,7 +103,7 @@
 }
 
 #ifndef CX_ARRAY_SWAP_SBO_SIZE
-#define CX_ARRAY_SWAP_SBO_SIZE 512
+#define CX_ARRAY_SWAP_SBO_SIZE 128
 #endif
 
 void cx_array_swap(
@@ -169,7 +169,24 @@
 
 static void cx_arl_destructor(struct cx_list_s *list) {
     cx_array_list *arl = (cx_array_list *) list;
+
+    char *ptr = arl->data;
+
+    if (list->simple_destructor) {
+        for (size_t i = 0; i < list->size; i++) {
+            cx_invoke_simple_destructor(list, ptr);
+            ptr += list->item_size;
+        }
+    }
+    if (list->advanced_destructor) {
+        for (size_t i = 0; i < list->size; i++) {
+            cx_invoke_advanced_destructor(list, ptr);
+            ptr += list->item_size;
+        }
+    }
+
     cxFree(list->allocator, arl->data);
+    cxFree(list->allocator, list);
 }
 
 static size_t cx_arl_insert_array(
--- a/src/ucx/basic_mempool.c	Sun Jul 09 15:14:26 2023 +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 2021 Mike Becker, 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 "cx/basic_mempool.h"
-#include "cx/utils.h"
-#include <string.h>
-
-#define of_chk_(n) if (SIZE_MAX - sizeof(cx_destructor_func) < (n)) return NULL
-
-/** Internal structure for denoting pooled memory. */
-typedef struct {
-    /** The destructor. */
-    cx_destructor_func destructor;
-    /**
-     * Access to the first byte of the polled memory.
-     */
-    char c;
-} cx_basic_mempool_memory;
-
-static int cx_basic_mempool_chcap(
-        struct cx_basic_mempool_s *pool,
-        size_t newcap
-) {
-    if (newcap < pool->ndata) {
-        return 1;
-    }
-
-    size_t newcapsz;
-    if (cx_szmul(newcap, sizeof(void *), &newcapsz)) {
-        return 1;
-    }
-
-    void **data = realloc(pool->data, newcapsz);
-    if (data) {
-        pool->data = data;
-        pool->size = newcap;
-        return 0;
-    } else {
-        return 1;
-    }
-}
-
-void *cx_malloc_basic_mempool(
-        void *data,
-        size_t n
-) {
-    of_chk_(n);
-    struct cx_basic_mempool_s *pool = data;
-
-    if (pool->ndata >= pool->size) {
-        size_t newcap = pool->size * 2;
-        if (newcap < pool->size || cx_basic_mempool_chcap(pool, newcap)) {
-            return NULL;
-        }
-    }
-
-    cx_basic_mempool_memory *mem = malloc(sizeof(cx_destructor_func) + n);
-    if (mem == NULL) {
-        return NULL;
-    }
-
-    mem->destructor = NULL;
-    pool->data[pool->ndata] = mem;
-    pool->ndata++;
-
-    return &(mem->c);
-}
-
-void *cx_calloc_basic_mempool(
-        void *data,
-        size_t nelem,
-        size_t elsize
-) {
-    size_t msz;
-    if (cx_szmul(nelem, elsize, &msz)) {
-        return NULL;
-    }
-    void *ptr = cx_malloc_basic_mempool(data, msz);
-    if (ptr == NULL) {
-        return NULL;
-    }
-    memset(ptr, 0, nelem * elsize);
-    return ptr;
-}
-
-void *cx_realloc_basic_mempool(
-        void *data,
-        void *ptr,
-        size_t n
-) {
-    of_chk_(n);
-    struct cx_basic_mempool_s *pool = data;
-
-    char *mem = ((char *) ptr) - sizeof(cx_destructor_func);
-    char *newm = (char *) realloc(mem, n + sizeof(cx_destructor_func));
-    if (newm == NULL) {
-        return NULL;
-    }
-    if (mem != newm) {
-        cx_for_n(i, pool->ndata) {
-            if (pool->data[i] == mem) {
-                pool->data[i] = newm;
-                return newm + sizeof(cx_destructor_func);
-            }
-        }
-        abort();
-    } else {
-        return newm + sizeof(cx_destructor_func);
-    }
-}
-
-void cx_free_basic_mempool(
-        void *data,
-        void *ptr
-) {
-    struct cx_basic_mempool_s *pool = data;
-
-    cx_basic_mempool_memory *mem = (cx_basic_mempool_memory *)
-            ((char *) ptr - sizeof(cx_destructor_func));
-    cx_for_n(i, pool->ndata) {
-        if (mem == pool->data[i]) {
-            if (mem->destructor != NULL) {
-                mem->destructor(&(mem->c));
-            }
-            free(mem);
-            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;
-        }
-    }
-    abort();
-}
-
-void cx_basic_mempool_destroy(CxMempool *p) {
-    struct cx_basic_mempool_s *pool = (struct cx_basic_mempool_s *) p;
-    cx_basic_mempool_memory *mem;
-    cx_for_n(i, pool->ndata) {
-        mem = (cx_basic_mempool_memory *) pool->data[i];
-        if (mem) {
-            if (mem->destructor) {
-                mem->destructor(&(mem->c));
-            }
-            free(mem);
-        }
-    }
-    free(pool->data);
-    free((void *) p->allocator);
-    free(pool);
-}
-
-void cx_basic_mempool_set_destr(
-        __attribute__((__unused__)) CxMempool *pool,
-        void *ptr,
-        cx_destructor_func func
-) {
-    *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = func;
-}
-
-static cx_allocator_class cx_basic_mempool_allocator_class = {
-        cx_malloc_basic_mempool,
-        cx_realloc_basic_mempool,
-        cx_calloc_basic_mempool,
-        cx_free_basic_mempool
-};
-
-static cx_mempool_class cx_basic_mempool_class = {
-        cx_basic_mempool_destroy,
-        cx_basic_mempool_set_destr,
-};
-
-CxMempool *cxBasicMempoolCreate(size_t capacity) {
-    size_t poolsize;
-    if (cx_szmul(capacity, sizeof(void *), &poolsize)) {
-        return NULL;
-    }
-
-    struct cx_basic_mempool_s *pool =
-            malloc(sizeof(struct cx_basic_mempool_s));
-    if (pool == NULL) {
-        return NULL;
-    }
-
-
-    CxAllocator *provided_allocator = malloc(sizeof(CxAllocator));
-    if (!provided_allocator) {
-        free(pool);
-        return NULL;
-    }
-    provided_allocator->cl = &cx_basic_mempool_allocator_class;
-    provided_allocator->data = pool;
-
-    pool->base.cl = &cx_basic_mempool_class;
-    pool->base.allocator = provided_allocator;
-
-    pool->data = malloc(poolsize);
-    if (pool->data == NULL) {
-        free(provided_allocator);
-        free(pool);
-        return NULL;
-    }
-
-    pool->ndata = 0;
-    pool->size = capacity;
-
-    return (CxMempool *) pool;
-}
--- a/src/ucx/cx/allocator.h	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/ucx/cx/allocator.h	Mon Jul 10 18:39:24 2023 +0200
@@ -133,6 +133,22 @@
 ) __attribute__((__nonnull__(2)));
 
 /**
+ * Re-allocate a previously allocated block and changes the pointer in-place, if necessary.
+ *
+ * \par Error handling
+ * \c errno will be set by realloc() on failure.
+ *
+ * @param mem pointer to the pointer to allocated block
+ * @param n the new size in bytes
+ * @return zero on success, non-zero on failure
+ */
+int cx_reallocate(
+        void **mem,
+        size_t n
+)
+__attribute__((__nonnull__));
+
+/**
  * Allocate \p n bytes of memory.
  *
  * @param allocator the allocator
@@ -169,7 +185,6 @@
 /**
  * Re-allocate a previously allocated block and changes the pointer in-place, if necessary.
  * This function acts like cxRealloc() using the pointer pointed to by \p mem.
- * On success, the pointer is changed to the new location (in case the
  *
  * \note Re-allocating a block allocated by a different allocator is undefined.
  *
--- a/src/ucx/cx/basic_mempool.h	Sun Jul 09 15:14:26 2023 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2021 Mike Becker, 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 basic_mempool.h
- * \brief Implementation of a basic memory pool.
- * \author Mike Becker
- * \author Olaf Wintermann
- * \version 3.0
- * \copyright 2-Clause BSD License
- */
-
-#ifndef UCX_BASIC_MEMPOOL_H
-#define UCX_BASIC_MEMPOOL_H
-
-#include "mempool.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Basic array-based memory pool.
- */
-struct cx_basic_mempool_s {
-    /** Inherit base structure members. */
-    CxMempool base;
-
-    /** List of pointers to pooled memory. */
-    void **data;
-
-    /** Number of pooled memory items. */
-    size_t ndata;
-
-    /** Memory pool size. */
-    size_t size;
-};
-
-/**
- * Creates a basic array-based memory pool.
- *
- * @param capacity the initial capacity of the pool
- * @return the created memory pool or \c NULL if allocation failed
- */
-__attribute__((__warn_unused_result__))
-CxMempool *cxBasicMempoolCreate(size_t capacity);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // UCX_BASIC_MEMPOOL_H
--- a/src/ucx/cx/collection.h	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/ucx/cx/collection.h	Mon Jul 10 18:39:24 2023 +0200
@@ -127,6 +127,15 @@
     (c)->store_pointer ? (*((void **) (e))) : (e))
 
 
+/**
+ * Invokes all available destructor functions for a specific element.
+ *
+ * Usually only used by collection implementations. There should be no need
+ * to invoke this macro manually.
+ *
+ * @param c the collection
+ * @param e the element
+ */
 #define cx_invoke_destructor(c, e) \
     if ((c)->simple_destructor) cx_invoke_simple_destructor(c,e); \
     if ((c)->advanced_destructor) cx_invoke_advanced_destructor(c,e)
--- a/src/ucx/cx/hash_map.h	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/ucx/cx/hash_map.h	Mon Jul 10 18:39:24 2023 +0200
@@ -74,7 +74,7 @@
  * cxMapStorePointers() was called immediately after creation.
  *
  * @note Iterators provided by this hash map implementation provide the remove operation.
- * The index value of an iterator is the incremented when the iterator advanced without removal.
+ * The index value of an iterator is incremented when the iterator advanced without removal.
  * In other words, when the iterator is finished, \c index==size .
  *
  * @param allocator the allocator to use
@@ -96,7 +96,7 @@
  * cxMapStorePointers() was called immediately after creation.
  *
  * @note Iterators provided by this hash map implementation provide the remove operation.
- * The index value of an iterator is the incremented when the iterator advanced without removal.
+ * The index value of an iterator is incremented when the iterator advanced without removal.
  * In other words, when the iterator is finished, \c index==size .
  *
  * @param itemsize the size of one element
--- a/src/ucx/cx/iterator.h	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/ucx/cx/iterator.h	Mon Jul 10 18:39:24 2023 +0200
@@ -51,6 +51,8 @@
 
     /**
      * Returns a pointer to the current element.
+     *
+     * When valid returns false, the behavior of this function is undefined.
      */
     __attribute__ ((__nonnull__))
     void *(*current)(void const *);
@@ -63,12 +65,16 @@
 
     /**
      * Advances the iterator.
+     *
+     * When valid returns false, the behavior of this function is undefined.
      */
     __attribute__ ((__nonnull__))
     void (*next)(void *);
 
     /**
      * Flag current element for removal, if possible.
+     *
+     * When valid returns false, the behavior of this function is undefined.
      */
     __attribute__ ((__nonnull__))
     bool (*flag_removal)(void *);
@@ -198,13 +204,13 @@
 
 /**
  * Iterator value type.
- * An iterator points to a certain element in an (possibly unbounded) chain of elements.
+ * An iterator points to a certain element in a (possibly unbounded) chain of elements.
  * Iterators that are based on collections (which have a defined "first" element), are supposed
  * to be "position-aware", which means that they keep track of the current index within the collection.
  *
  * @note Objects that are pointed to by an iterator are always mutable through that iterator. However,
  * this iterator cannot mutate the collection itself (add or remove elements) and any mutation of the
- * collection by other means make this iterator invalid (regardless of what cxIteratorValid() returns).
+ * collection by other means makes this iterator invalid (regardless of what cxIteratorValid() returns).
  *
  * @see CxMutIterator
  */
--- a/src/ucx/cx/list.h	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/ucx/cx/list.h	Mon Jul 10 18:39:24 2023 +0200
@@ -70,11 +70,14 @@
 struct cx_list_class_s {
     /**
      * Destructor function.
+     *
+     * Implementations SHALL invoke the content destructor functions if provided
+     * and SHALL deallocate the list memory, if an allocator is provided.
      */
     void (*destructor)(struct cx_list_s *list);
 
     /**
-     * Member function for inserting a single elements.
+     * Member function for inserting a single element.
      * Implementors SHOULD see to performant implementations for corner cases.
      */
     int (*insert_element)(
@@ -142,7 +145,7 @@
     );
 
     /**
-     * Member function for sorting the list in place.
+     * Member function for sorting the list in-place.
      */
     void (*sort)(struct cx_list_s *list);
 
@@ -581,7 +584,7 @@
 }
 
 /**
- * Sorts the list in place.
+ * Sorts the list in-place.
  *
  * \remark The underlying sort algorithm is implementation defined.
  *
@@ -632,6 +635,14 @@
 __attribute__((__nonnull__))
 void cxListDestroy(CxList *list);
 
+/**
+ * A shared instance of an empty list.
+ *
+ * Writing to that list is undefined.
+ */
+extern CxList * const cxEmptyList;
+
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
--- a/src/ucx/cx/map.h	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/ucx/cx/map.h	Mon Jul 10 18:39:24 2023 +0200
@@ -63,6 +63,24 @@
 };
 
 /**
+ * The type of iterator for a map.
+ */
+enum cx_map_iterator_type {
+    /**
+     * Iterates over key/value pairs.
+     */
+    CX_MAP_ITERATOR_PAIRS,
+    /**
+     * Iterates over keys only.
+     */
+    CX_MAP_ITERATOR_KEYS,
+    /**
+     * Iterates over values only.
+     */
+    CX_MAP_ITERATOR_VALUES
+};
+
+/**
  * The class definition for arbitrary maps.
  */
 struct cx_map_class_s {
@@ -108,40 +126,10 @@
     );
 
     /**
-     * Iterator over the key/value pairs.
-     */
-    __attribute__((__nonnull__, __warn_unused_result__))
-    CxIterator (*iterator)(CxMap const *map);
-
-    /**
-     * Iterator over the keys.
-     */
-    __attribute__((__nonnull__, __warn_unused_result__))
-    CxIterator (*iterator_keys)(CxMap const *map);
-
-    /**
-     * Iterator over the values.
+     * Creates an iterator for this map.
      */
     __attribute__((__nonnull__, __warn_unused_result__))
-    CxIterator (*iterator_values)(CxMap const *map);
-
-    /**
-     * Mutating iterator over the key/value pairs.
-     */
-    __attribute__((__nonnull__, __warn_unused_result__))
-    CxMutIterator (*mut_iterator)(CxMap *map);
-
-    /**
-     * Mutating iterator over the keys.
-     */
-    __attribute__((__nonnull__, __warn_unused_result__))
-    CxMutIterator (*mut_iterator_keys)(CxMap *map);
-
-    /**
-     * Mutating iterator over the values.
-     */
-    __attribute__((__nonnull__, __warn_unused_result__))
-    CxMutIterator (*mut_iterator_values)(CxMap *map);
+    CxIterator (*iterator)(CxMap const *map, enum cx_map_iterator_type type);
 };
 
 /**
@@ -159,6 +147,13 @@
 };
 
 /**
+ * A shared instance of an empty map.
+ *
+ * Writing to that map is undefined.
+ */
+extern CxMap *const cxEmptyMap;
+
+/**
  * Advises the map to store copies of the objects (default mode of operation).
  *
  * Retrieving objects from this map will yield pointers to the copies stored
@@ -225,8 +220,8 @@
  * @return an iterator for the currently stored values
  */
 __attribute__((__nonnull__, __warn_unused_result__))
-static inline CxIterator cxMapIteratorValues(CxMap *map) {
-    return map->cl->iterator_values(map);
+static inline CxIterator cxMapIteratorValues(CxMap const *map) {
+    return map->cl->iterator(map, CX_MAP_ITERATOR_VALUES);
 }
 
 /**
@@ -241,8 +236,8 @@
  * @return an iterator for the currently stored keys
  */
 __attribute__((__nonnull__, __warn_unused_result__))
-static inline CxIterator cxMapIteratorKeys(CxMap *map) {
-    return map->cl->iterator_keys(map);
+static inline CxIterator cxMapIteratorKeys(CxMap const *map) {
+    return map->cl->iterator(map, CX_MAP_ITERATOR_KEYS);
 }
 
 /**
@@ -259,8 +254,8 @@
  * @see cxMapIteratorValues()
  */
 __attribute__((__nonnull__, __warn_unused_result__))
-static inline CxIterator cxMapIterator(CxMap *map) {
-    return map->cl->iterator(map);
+static inline CxIterator cxMapIterator(CxMap const *map) {
+    return map->cl->iterator(map, CX_MAP_ITERATOR_PAIRS);
 }
 
 
@@ -274,9 +269,7 @@
  * @return an iterator for the currently stored values
  */
 __attribute__((__nonnull__, __warn_unused_result__))
-static inline CxMutIterator cxMapMutIteratorValues(CxMap *map) {
-    return map->cl->mut_iterator_values(map);
-}
+CxMutIterator cxMapMutIteratorValues(CxMap *map);
 
 /**
  * Creates a mutating iterator over the keys of a map.
@@ -290,9 +283,7 @@
  * @return an iterator for the currently stored keys
  */
 __attribute__((__nonnull__, __warn_unused_result__))
-static inline CxMutIterator cxMapMutIteratorKeys(CxMap *map) {
-    return map->cl->mut_iterator_keys(map);
-}
+CxMutIterator cxMapMutIteratorKeys(CxMap *map);
 
 /**
  * Creates a mutating iterator for a map.
@@ -308,9 +299,7 @@
  * @see cxMapMutIteratorValues()
  */
 __attribute__((__nonnull__, __warn_unused_result__))
-static inline CxMutIterator cxMapMutIterator(CxMap *map) {
-    return map->cl->mut_iterator(map);
-}
+CxMutIterator cxMapMutIterator(CxMap *map);
 
 #ifdef __cplusplus
 } // end the extern "C" block here, because we want to start overloading
--- a/src/ucx/cx/mempool.h	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/ucx/cx/mempool.h	Mon Jul 10 18:39:24 2023 +0200
@@ -44,24 +44,31 @@
 extern "C" {
 #endif
 
-/**
- * Memory pool class type.
- */
-typedef struct cx_mempool_class_s cx_mempool_class;
+/** Internal structure for pooled memory. */
+struct cx_mempool_memory_s;
 
 /**
  * The basic structure of a memory pool.
  * Should be the first member of an actual memory pool implementation.
  */
 struct cx_mempool_s {
+    /** The provided allocator. */
+    CxAllocator const *allocator;
+
     /**
-     * The pool class definition.
+     * A destructor that shall be automatically registered for newly allocated memory.
+     * This destructor MUST NOT free the memory.
      */
-    cx_mempool_class *cl;
-    /**
-     * The provided allocator.
-     */
-    CxAllocator const *allocator;
+    cx_destructor_func auto_destr;
+
+    /** Array of pooled memory. */
+    struct cx_mempool_memory_s **data;
+
+    /** Number of pooled memory items. */
+    size_t size;
+
+    /** Memory pool capacity. */
+    size_t capacity;
 };
 
 /**
@@ -70,50 +77,70 @@
 typedef struct cx_mempool_s CxMempool;
 
 /**
- * The class definition for a memory pool.
+ * Creates an array-based memory pool with a shared destructor function.
+ *
+ * This destructor MUST NOT free the memory.
+ *
+ * @param capacity the initial capacity of the pool
+ * @param destr the destructor function to use for allocated memory
+ * @return the created memory pool or \c NULL if allocation failed
  */
-struct cx_mempool_class_s {
-    /** Member function for destroying the pool. */
-    __attribute__((__nonnull__))
-    void (*destroy)(CxMempool *pool);
-
-    /** Member function for setting a destructor. */
-    __attribute__((__nonnull__))
-    void (*set_destructor)(
-            CxMempool *pool,
-            void *memory,
-            cx_destructor_func fnc
-    );
-};
-
+__attribute__((__warn_unused_result__))
+CxMempool *cxMempoolCreate(size_t capacity, cx_destructor_func destr);
 
 /**
- * Destroys a memory pool including their contents.
+ * Creates a basic array-based memory pool.
+ *
+ * @param capacity the initial capacity of the pool
+ * @return the created memory pool or \c NULL if allocation failed
+ */
+__attribute__((__warn_unused_result__))
+static inline CxMempool *cxBasicMempoolCreate(size_t capacity) {
+    return cxMempoolCreate(capacity, NULL);
+}
+
+/**
+ * Destroys a memory pool and frees the managed memory.
  *
  * @param pool the memory pool to destroy
  */
 __attribute__((__nonnull__))
-static inline void cxMempoolDestroy(CxMempool *pool) {
-    pool->cl->destroy(pool);
-}
+void cxMempoolDestroy(CxMempool *pool);
 
 /**
- * Sets a destructor function for an allocated memory object.
+ * Sets the destructor function for a specific allocated memory object.
  *
- * If the memory is not managed by the pool, the behavior is undefined.
+ * If the memory is not managed by a UCX memory pool, the behavior is undefined.
+ * The destructor MUST NOT free the memory.
  *
- * @param pool the pool
- * @param memory the objected allocated in the pool
+ * @param memory the object allocated in the pool
  * @param fnc the destructor function
  */
 __attribute__((__nonnull__))
-static inline void cxMempoolSetDestructor(
-        CxMempool *pool,
+void cxMempoolSetDestructor(
         void *memory,
         cx_destructor_func fnc
-) {
-    pool->cl->set_destructor(pool, memory, fnc);
-}
+);
+
+/**
+ * Registers foreign memory with this pool.
+ *
+ * The destructor, in contrast to memory allocated by the pool, MUST free the memory.
+ *
+ * A small portion of memory will be allocated to register the information in the pool.
+ * If that allocation fails, this function will return non-zero.
+ *
+ * @param pool the pool
+ * @param memory the object allocated in the pool
+ * @param destr the destructor function
+ * @return zero on success, non-zero on failure
+ */
+__attribute__((__nonnull__))
+int cxMempoolRegister(
+        CxMempool *pool,
+        void *memory,
+        cx_destructor_func destr
+);
 
 #ifdef __cplusplus
 } // extern "C"
--- a/src/ucx/cx/tree.h	Sun Jul 09 15:14:26 2023 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,136 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2021 Mike Becker, 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 tree.h
- * \brief Interface for tree implementations.
- * \author Olaf Wintermann
- * \author Mike Becker
- * \version 3.0
- * \copyright 2-Clause BSD License
- */
-
-#ifndef UCX_TREE_H
-#define UCX_TREE_H
-
-#include "common.h"
-#include "allocator.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Adds a sibling to the current tree node.
- *
- * In case your struct does not have a \p prev or a \p parent pointer,
- * specify a negative location. The location of the \p next pointer is
- * mandatory.
- *
- * \attention Do not use this function to add siblings in a tree where the
- * nodes store a pointer to the last sibling because that would not be modified by this function.
- *
- * \remark If yo do not provide a location to the parent pointer, a call to this function is
- * effectively the same as a call to cx_linked_list_add().
- *
- * @param node a pointer to the node
- * @param loc_prev the location of a \c prev pointer within your node struct
- * @param loc_next the location of a \c next pointer within your node struct
- * @param loc_parent the location of a \c parent pointer within your node struct
- * @param new_node the new node that shall be added as a sibling
- */
-void cx_tree_add_sibling(void *node,
-                         ptrdiff_t loc_prev, ptrdiff_t loc_next,
-                         ptrdiff_t loc_parent,
-                         void *new_node)
-__attribute__((__nonnull__));
-
-/**
- * Adds a node to the list of children.
- *
- * \par Example with a full structure
- * A full tree node structure may look like this:
- * \code
- * typedef struct MyTreeNode MyTreeNode;
- * struct MyTreeNode {
- *   MyTreeNode* parent;
- *   MyTreeNode* first_child;
- *   MyTreeNode* last_child;
- *   MyTreeNode* prev_sibling;
- *   MyTreeNode* next_sibling;
- *   // ...contents...
- * }
- * \endcode
- * Adding a new child to a node with the above structure can be performed with the following call:
- * \code
- * MyTreeNode *node, *child; // given
- * cx_tree_add_child(&node->first_child, &node->last_child,
- *                   offsetof(MyTreeNode, prev_sibling), offsetof(MyTreeNode, next_sibling),
- *                   child, offsetof(MyTreeNode, parent), node);
- * \endcode
- *
- * \par Example with a reduced structure
- * The minimal reasonable structure with parent pointer looks like this:
- * \code
- * typedef struct MyTreeNode MyTreeNode;
- * struct MyTreeNode {
- *   MyTreeNode* parent;
- *   MyTreeNode* children;
- *   MyTreeNode* next_sibling;
- *   // ...contents...
- * }
- * \endcode
- * This simplifies the function call to:
- * \code
- * MyTreeNode *node, *child; // given
- * cx_tree_add_child(&node->children, NULL, -1, offsetof(MyTreeNode, next_sibling),
- *                   child, offsetof(MyTreeNode, parent), node);
- * \endcode
- *
- * \remark If your tree structure does not possess a parent pointer, a call to this function is
- * effectively the same as a call to cx_linked_list_add().
- *
- * @param children_begin a pointer to the begin node pointer (if your list has one)
- * @param children_end a pointer to the end node pointer (if your list has one)
- * @param loc_prev the location of a \c prev pointer within your node struct
- * @param loc_next the location of a \c next pointer within your node struct
- * @param new_node a pointer to the node that shall be appended
- * @param loc_parent the location of a \c parent pointer within your node struct
- * @param parent the parent node
- */
-void cx_tree_add_child(void **children_begin, void **children_end,
-                       ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node,
-                       ptrdiff_t loc_parent, void *parent)
-__attribute__((__nonnull__ (5)));
-
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // UCX_TREE_H
-
--- a/src/ucx/cx/utils.h	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/ucx/cx/utils.h	Mon Jul 10 18:39:24 2023 +0200
@@ -183,7 +183,6 @@
  * @param dest the destination stream
  * @param rfnc the read function
  * @param wfnc the write function
- * @param n the maximum number of bytes that shall be copied.
  * @return total number of bytes copied
  */
 #define cx_stream_copy(src, dest, rfnc, wfnc) \
--- a/src/ucx/hash_map.c	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/ucx/hash_map.c	Mon Jul 10 18:39:24 2023 +0200
@@ -26,10 +26,12 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <string.h>
 #include "cx/hash_map.h"
 #include "cx/utils.h"
 
+#include <string.h>
+#include <assert.h>
+
 struct cx_hash_map_element_s {
     /** A pointer to the next element in the current bucket. */
     struct cx_hash_map_element_s *next;
@@ -334,13 +336,30 @@
     }
 }
 
-static CxIterator cx_hash_map_iterator(CxMap const *map) {
+static CxIterator cx_hash_map_iterator(
+        CxMap const *map,
+        enum cx_map_iterator_type type
+) {
     CxIterator iter;
 
     iter.src_handle = map;
     iter.base.valid = cx_hash_map_iter_valid;
     iter.base.next = cx_hash_map_iter_next;
-    iter.base.current = cx_hash_map_iter_current_entry;
+
+    switch (type) {
+        case CX_MAP_ITERATOR_PAIRS:
+            iter.base.current = cx_hash_map_iter_current_entry;
+            break;
+        case CX_MAP_ITERATOR_KEYS:
+            iter.base.current = cx_hash_map_iter_current_key;
+            break;
+        case CX_MAP_ITERATOR_VALUES:
+            iter.base.current = cx_hash_map_iter_current_value;
+            break;
+        default:
+            assert(false);
+    }
+
     iter.base.flag_removal = cx_hash_map_iter_flag_rm;
     iter.base.remove = false;
     iter.base.mutating = false;
@@ -370,40 +389,6 @@
     return iter;
 }
 
-static CxIterator cx_hash_map_iterator_keys(CxMap const *map) {
-    CxIterator iter = cx_hash_map_iterator(map);
-    iter.base.current = cx_hash_map_iter_current_key;
-    return iter;
-}
-
-static CxIterator cx_hash_map_iterator_values(CxMap const *map) {
-    CxIterator iter = cx_hash_map_iterator(map);
-    iter.base.current = cx_hash_map_iter_current_value;
-    return iter;
-}
-
-static CxMutIterator cx_hash_map_mut_iterator(CxMap *map) {
-    CxIterator it = cx_hash_map_iterator(map);
-    it.base.mutating = true;
-
-    // we know the iterators share the same memory layout
-    CxMutIterator iter;
-    memcpy(&iter, &it, sizeof(CxMutIterator));
-    return iter;
-}
-
-static CxMutIterator cx_hash_map_mut_iterator_keys(CxMap *map) {
-    CxMutIterator iter = cx_hash_map_mut_iterator(map);
-    iter.base.current = cx_hash_map_iter_current_key;
-    return iter;
-}
-
-static CxMutIterator cx_hash_map_mut_iterator_values(CxMap *map) {
-    CxMutIterator iter = cx_hash_map_mut_iterator(map);
-    iter.base.current = cx_hash_map_iter_current_value;
-    return iter;
-}
-
 static cx_map_class cx_hash_map_class = {
         cx_hash_map_destructor,
         cx_hash_map_clear,
@@ -411,11 +396,6 @@
         cx_hash_map_get,
         cx_hash_map_remove,
         cx_hash_map_iterator,
-        cx_hash_map_iterator_keys,
-        cx_hash_map_iterator_values,
-        cx_hash_map_mut_iterator,
-        cx_hash_map_mut_iterator_keys,
-        cx_hash_map_mut_iterator_values,
 };
 
 CxMap *cxHashMapCreate(
--- a/src/ucx/linked_list.c	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/ucx/linked_list.c	Mon Jul 10 18:39:24 2023 +0200
@@ -283,7 +283,7 @@
 #define CX_LINKED_LIST_SORT_SBO_SIZE 1024
 #endif
 
-static void *cx_linked_list_sort_merge(
+static void cx_linked_list_sort_merge(
         ptrdiff_t loc_prev,
         ptrdiff_t loc_next,
         ptrdiff_t loc_data,
@@ -291,7 +291,9 @@
         void *ls,
         void *le,
         void *re,
-        cx_compare_func cmp_func
+        cx_compare_func cmp_func,
+        void **begin,
+        void **end
 ) {
     void *sbo[CX_LINKED_LIST_SORT_SBO_SIZE];
     void **sorted = length >= CX_LINKED_LIST_SORT_SBO_SIZE ?
@@ -330,11 +332,11 @@
     }
     ll_next(sorted[length - 1]) = NULL;
 
-    void *ret = sorted[0];
+    *begin = sorted[0];
+    *end = sorted[length-1];
     if (sorted != sbo) {
         free(sorted);
     }
-    return ret;
 }
 
 void cx_linked_list_sort( // NOLINT(misc-no-recursion) - purposely recursive function
@@ -380,8 +382,10 @@
         re = ll_next(rc);
 
         // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them
-        void *sorted = cx_linked_list_sort_merge(loc_prev, loc_next, loc_data,
-                                                 ln + rn, ls, le, re, cmp_func);
+        void *sorted_begin, *sorted_end;
+        cx_linked_list_sort_merge(loc_prev, loc_next, loc_data,
+                                  ln + rn, ls, le, re, cmp_func,
+                                  &sorted_begin, &sorted_end);
 
         // Something left? Sort it!
         size_t remainder_length = cx_linked_list_size(re, loc_next);
@@ -390,14 +394,13 @@
             cx_linked_list_sort(&remainder, NULL, loc_prev, loc_next, loc_data, cmp_func);
 
             // merge sorted list with (also sorted) remainder
-            *begin = cx_linked_list_sort_merge(loc_prev, loc_next, loc_data,
-                                               ln + rn + remainder_length,
-                                               sorted, remainder, NULL, cmp_func);
-        } else {
-            // no remainder - we've got our sorted list
-            *begin = sorted;
+            cx_linked_list_sort_merge(loc_prev, loc_next, loc_data,
+                                      ln + rn + remainder_length,
+                                      sorted_begin, remainder, NULL, cmp_func,
+                                      &sorted_begin, &sorted_end);
         }
-        if (end) *end = cx_linked_list_last(sorted, loc_next);
+        *begin = sorted_begin;
+        if (end) *end = sorted_end;
     }
 }
 
@@ -604,7 +607,7 @@
 }
 
 #ifndef CX_LINKED_LIST_SWAP_SBO_SIZE
-#define CX_LINKED_LIST_SWAP_SBO_SIZE 16
+#define CX_LINKED_LIST_SWAP_SBO_SIZE 128
 #endif
 
 static int cx_ll_swap(
@@ -873,11 +876,13 @@
 
     cx_linked_list_node *node = ll->begin;
     while (node) {
+        cx_invoke_destructor(list, node->payload);
         void *next = node->next;
         cxFree(list->allocator, node);
         node = next;
     }
-    // do not free the list pointer, this is just a destructor!
+
+    cxFree(list->allocator, list);
 }
 
 static cx_list_class cx_linked_list_class = {
--- a/src/ucx/list.c	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/ucx/list.c	Mon Jul 10 18:39:24 2023 +0200
@@ -195,34 +195,102 @@
 
 // </editor-fold>
 
+// <editor-fold desc="empty list implementation">
+
+static void cx_emptyl_noop(__attribute__((__unused__)) CxList *list) {
+    // this is a noop, but MUST be implemented
+}
+
+static void *cx_emptyl_at(
+        __attribute__((__unused__)) struct cx_list_s const *list,
+        __attribute__((__unused__)) size_t index
+) {
+    return NULL;
+}
+
+static ssize_t cx_emptyl_find(
+        __attribute__((__unused__)) struct cx_list_s const *list,
+        __attribute__((__unused__)) void const *elem
+) {
+    return -1;
+}
+
+static int cx_emptyl_compare(
+        __attribute__((__unused__)) struct cx_list_s const *list,
+        struct cx_list_s const *other
+) {
+    if (other->size == 0) return 0;
+    return -1;
+}
+
+static bool cx_emptyl_iter_valid(__attribute__((__unused__)) void const *iter) {
+    return false;
+}
+
+static CxIterator cx_emptyl_iterator(
+        struct cx_list_s const *list,
+        size_t index,
+        __attribute__((__unused__)) bool backwards
+) {
+    CxIterator iter = {0};
+    iter.src_handle = list;
+    iter.index = index;
+    iter.base.valid = cx_emptyl_iter_valid;
+    return iter;
+}
+
+static cx_list_class cx_empty_list_class = {
+        cx_emptyl_noop,
+        NULL,
+        NULL,
+        NULL,
+        NULL,
+        cx_emptyl_noop,
+        NULL,
+        cx_emptyl_at,
+        cx_emptyl_find,
+        cx_emptyl_noop,
+        cx_emptyl_compare,
+        cx_emptyl_noop,
+        cx_emptyl_iterator,
+};
+
+CxList cx_empty_list = {
+        NULL,
+        NULL,
+        0,
+        0,
+        NULL,
+        NULL,
+        NULL,
+        false,
+        &cx_empty_list_class,
+        NULL
+};
+
+CxList *const cxEmptyList = &cx_empty_list;
+
+// </editor-fold>
+
 void cxListDestroy(CxList *list) {
-    if (list->simple_destructor) {
-        CxIterator iter = cxListIterator(list);
-        cx_foreach(void*, elem, iter) {
-            // already correctly resolved pointer - immediately invoke dtor
-            list->simple_destructor(elem);
-        }
-    }
-    if (list->advanced_destructor) {
-        CxIterator iter = cxListIterator(list);
-        cx_foreach(void*, elem, iter) {
-            // already correctly resolved pointer - immediately invoke dtor
-            list->advanced_destructor(list->destructor_data, elem);
-        }
-    }
-
     list->cl->destructor(list);
-    cxFree(list->allocator, list);
 }
 
 int cxListCompare(
         CxList const *list,
         CxList const *other
 ) {
-    if ((list->store_pointer ^ other->store_pointer) ||
-        ((list->climpl == NULL) ^ (other->climpl != NULL)) ||
+    if (
+        // if one is storing pointers but the other is not
+        (list->store_pointer ^ other->store_pointer) ||
+
+        // if one class is wrapped but the other is not
+        ((list->climpl == NULL) ^ (other->climpl == NULL)) ||
+
+        // if the resolved compare functions are not the same
         ((list->climpl != NULL ? list->climpl->compare : list->cl->compare) !=
-         (other->climpl != NULL ? other->climpl->compare : other->cl->compare))) {
+         (other->climpl != NULL ? other->climpl->compare : other->cl->compare))
+    ) {
         // lists are definitely different - cannot use internal compare function
         if (list->size == other->size) {
             CxIterator left = cxListIterator(list);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/map.c	Mon Jul 10 18:39:24 2023 +0200
@@ -0,0 +1,112 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2023 Mike Becker, 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 "cx/map.h"
+#include <string.h>
+
+// <editor-fold desc="empty map implementation">
+
+static void cx_empty_map_noop(__attribute__((__unused__)) CxMap *map) {
+    // this is a noop, but MUST be implemented
+}
+
+static void *cx_empty_map_get(
+        __attribute__((__unused__)) CxMap const *map,
+        __attribute__((__unused__)) CxHashKey key
+) {
+    return NULL;
+}
+
+static bool cx_empty_map_iter_valid(__attribute__((__unused__)) void const *iter) {
+    return false;
+}
+
+static CxIterator cx_empty_map_iterator(
+        struct cx_map_s const *map,
+        __attribute__((__unused__)) enum cx_map_iterator_type type
+) {
+    CxIterator iter = {0};
+    iter.src_handle = map;
+    iter.base.valid = cx_empty_map_iter_valid;
+    return iter;
+}
+
+static struct cx_map_class_s cx_empty_map_class = {
+        cx_empty_map_noop,
+        cx_empty_map_noop,
+        NULL,
+        cx_empty_map_get,
+        NULL,
+        cx_empty_map_iterator
+};
+
+CxMap cx_empty_map = {
+        NULL,
+        NULL,
+        0,
+        0,
+        NULL,
+        NULL,
+        NULL,
+        false,
+        &cx_empty_map_class
+};
+
+CxMap *const cxEmptyMap = &cx_empty_map;
+
+// </editor-fold>
+
+CxMutIterator cxMapMutIteratorValues(CxMap *map) {
+    CxIterator it = map->cl->iterator(map, CX_MAP_ITERATOR_VALUES);
+    it.base.mutating = true;
+
+    // we know the iterators share the same memory layout
+    CxMutIterator iter;
+    memcpy(&iter, &it, sizeof(CxMutIterator));
+    return iter;
+}
+
+CxMutIterator cxMapMutIteratorKeys(CxMap *map) {
+    CxIterator it = map->cl->iterator(map, CX_MAP_ITERATOR_KEYS);
+    it.base.mutating = true;
+
+    // we know the iterators share the same memory layout
+    CxMutIterator iter;
+    memcpy(&iter, &it, sizeof(CxMutIterator));
+    return iter;
+}
+
+CxMutIterator cxMapMutIterator(CxMap *map) {
+    CxIterator it = map->cl->iterator(map, CX_MAP_ITERATOR_PAIRS);
+    it.base.mutating = true;
+
+    // we know the iterators share the same memory layout
+    CxMutIterator iter;
+    memcpy(&iter, &it, sizeof(CxMutIterator));
+    return iter;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/mempool.c	Mon Jul 10 18:39:24 2023 +0200
@@ -0,0 +1,232 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2021 Mike Becker, 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 "cx/mempool.h"
+#include "cx/utils.h"
+#include <string.h>
+
+struct cx_mempool_memory_s {
+    /** The destructor. */
+    cx_destructor_func destructor;
+    /** The actual memory. */
+    char c[];
+};
+
+static void *cx_mempool_malloc(
+        void *p,
+        size_t n
+) {
+    struct cx_mempool_s *pool = p;
+
+    if (pool->size >= pool->capacity) {
+        size_t newcap = pool->capacity - (pool->capacity % 16) + 16;
+        struct cx_mempool_memory_s **newdata = realloc(pool->data, newcap*sizeof(struct cx_mempool_memory_s*));
+        if (newdata == NULL) {
+            return NULL;
+        }
+        pool->data = newdata;
+        pool->capacity = newcap;
+    }
+
+    struct cx_mempool_memory_s *mem = malloc(sizeof(cx_destructor_func) + n);
+    if (mem == NULL) {
+        return NULL;
+    }
+
+    mem->destructor = pool->auto_destr;
+    pool->data[pool->size] = mem;
+    pool->size++;
+
+    return mem->c;
+}
+
+static void *cx_mempool_calloc(
+        void *p,
+        size_t nelem,
+        size_t elsize
+) {
+    size_t msz;
+    if (cx_szmul(nelem, elsize, &msz)) {
+        return NULL;
+    }
+    void *ptr = cx_mempool_malloc(p, msz);
+    if (ptr == NULL) {
+        return NULL;
+    }
+    memset(ptr, 0, nelem * elsize);
+    return ptr;
+}
+
+static void *cx_mempool_realloc(
+        void *p,
+        void *ptr,
+        size_t n
+) {
+    struct cx_mempool_s *pool = p;
+
+    struct cx_mempool_memory_s *mem, *newm;
+    mem = (struct cx_mempool_memory_s*)(((char *) ptr) - sizeof(cx_destructor_func));
+    newm = realloc(mem, n + sizeof(cx_destructor_func));
+
+    if (newm == NULL) {
+        return NULL;
+    }
+    if (mem != newm) {
+        cx_for_n(i, pool->size) {
+            if (pool->data[i] == mem) {
+                pool->data[i] = newm;
+                return ((char*)newm) + sizeof(cx_destructor_func);
+            }
+        }
+        abort();
+    } else {
+        return ptr;
+    }
+}
+
+static void cx_mempool_free(
+        void *p,
+        void *ptr
+) {
+    struct cx_mempool_s *pool = p;
+
+    struct cx_mempool_memory_s *mem = (struct cx_mempool_memory_s *)
+            ((char *) ptr - sizeof(cx_destructor_func));
+
+    cx_for_n(i, pool->size) {
+        if (mem == pool->data[i]) {
+            if (mem->destructor) {
+                mem->destructor(mem->c);
+            }
+            free(mem);
+            size_t last_index = pool->size - 1;
+            if (i != last_index) {
+                pool->data[i] = pool->data[last_index];
+                pool->data[last_index] = NULL;
+            }
+            pool->size--;
+            return;
+        }
+    }
+    abort();
+}
+
+void cxMempoolDestroy(CxMempool *pool) {
+    struct cx_mempool_memory_s *mem;
+    cx_for_n(i, pool->size) {
+        mem = pool->data[i];
+        if (mem->destructor) {
+            mem->destructor(mem->c);
+        }
+        free(mem);
+    }
+    free(pool->data);
+    free((void*) pool->allocator);
+    free(pool);
+}
+
+void cxMempoolSetDestructor(
+        void *ptr,
+        cx_destructor_func func
+) {
+    *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = func;
+}
+
+struct cx_mempool_foreign_mem_s {
+    cx_destructor_func destr;
+    void* mem;
+};
+
+static void cx_mempool_destr_foreign_mem(void* ptr) {
+    struct cx_mempool_foreign_mem_s *fm = ptr;
+    fm->destr(fm->mem);
+}
+
+int cxMempoolRegister(
+        CxMempool *pool,
+        void *memory,
+        cx_destructor_func destr
+) {
+    struct cx_mempool_foreign_mem_s *fm = cx_mempool_malloc(
+            pool,
+            sizeof(struct cx_mempool_foreign_mem_s)
+    );
+    if (fm == NULL) return 1;
+
+    fm->mem = memory;
+    fm->destr = destr;
+    *(cx_destructor_func *) ((char *) fm - sizeof(cx_destructor_func)) = cx_mempool_destr_foreign_mem;
+
+    return 0;
+}
+
+static cx_allocator_class cx_mempool_allocator_class = {
+        cx_mempool_malloc,
+        cx_mempool_realloc,
+        cx_mempool_calloc,
+        cx_mempool_free
+};
+
+CxMempool *cxMempoolCreate(
+        size_t capacity,
+        cx_destructor_func destr
+) {
+    size_t poolsize;
+    if (cx_szmul(capacity, sizeof(struct cx_mempool_memory_s*), &poolsize)) {
+        return NULL;
+    }
+
+    struct cx_mempool_s *pool =
+            malloc(sizeof(struct cx_mempool_s));
+    if (pool == NULL) {
+        return NULL;
+    }
+
+    CxAllocator *provided_allocator = malloc(sizeof(CxAllocator));
+    if (provided_allocator == NULL) {
+        free(pool);
+        return NULL;
+    }
+    provided_allocator->cl = &cx_mempool_allocator_class;
+    provided_allocator->data = pool;
+
+    pool->allocator = provided_allocator;
+
+    pool->data = malloc(poolsize);
+    if (pool->data == NULL) {
+        free(provided_allocator);
+        free(pool);
+        return NULL;
+    }
+
+    pool->size = 0;
+    pool->capacity = capacity;
+    pool->auto_destr = destr;
+
+    return (CxMempool *) pool;
+}
--- a/src/ucx/tree.c	Sun Jul 09 15:14:26 2023 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2021 Mike Becker, 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 "cx/tree.h"
-#include "cx/linked_list.h"
-
-#define CX_TR_PTR(cur, off) *((void**)(((char*)(cur))+(off)))
-
-void cx_tree_add_sibling(void *node, ptrdiff_t loc_prev, ptrdiff_t loc_next, ptrdiff_t loc_parent, void *new_node) {
-    cx_linked_list_add(&node, NULL, loc_prev, loc_next, new_node);
-
-    // optional parent link
-    if (loc_parent >= 0) {
-        CX_TR_PTR(new_node, loc_parent) = CX_TR_PTR(node, loc_parent);
-    }
-}
-
-void cx_tree_add_child(void **children_begin, void **children_end,
-                       ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node,
-                       ptrdiff_t loc_parent, void *parent) {
-    cx_linked_list_add(children_begin, children_end, loc_prev, loc_next, new_node);
-
-    // optional parent link
-    if (loc_parent >= 0) {
-        CX_TR_PTR(new_node, loc_parent) = parent;
-    }
-}
--- a/src/ucx/utils.c	Sun Jul 09 15:14:26 2023 +0200
+++ b/src/ucx/utils.c	Mon Jul 10 18:39:24 2023 +0200
@@ -28,8 +28,13 @@
 
 #include "cx/utils.h"
 
+#ifndef CX_STREAM_BCOPY_BUF_SIZE
 #define CX_STREAM_BCOPY_BUF_SIZE 8192
+#endif
+
+#ifndef CX_STREAM_COPY_BUF_SIZE
 #define CX_STREAM_COPY_BUF_SIZE 1024
+#endif
 
 size_t cx_stream_bncopy(
         void *src,

mercurial