refactor the list and map construction functions and remove the simple macros

Sun, 14 Dec 2025 17:30:17 +0100

author
Mike Becker <universe@uap-core.de>
date
Sun, 14 Dec 2025 17:30:17 +0100
changeset 1605
55b13f583356
parent 1604
68b75c091028
child 1606
f5883f6e42e7

refactor the list and map construction functions and remove the simple macros

relates to #780
relates to #622

CHANGELOG file | annotate | diff | comparison | revisions
docs/Writerside/topics/about.md file | annotate | diff | comparison | revisions
docs/Writerside/topics/array_list.h.md file | annotate | diff | comparison | revisions
docs/Writerside/topics/collection.h.md file | annotate | diff | comparison | revisions
docs/Writerside/topics/hash_map.h.md file | annotate | diff | comparison | revisions
docs/Writerside/topics/kv_list.h.md file | annotate | diff | comparison | revisions
docs/Writerside/topics/linked_list.h.md file | annotate | diff | comparison | revisions
docs/Writerside/topics/list.h.md file | annotate | diff | comparison | revisions
docs/Writerside/topics/map.h.md file | annotate | diff | comparison | revisions
docs/Writerside/topics/tree.h.md file | annotate | diff | comparison | revisions
src/array_list.c file | annotate | diff | comparison | revisions
src/cx/array_list.h file | annotate | diff | comparison | revisions
src/cx/collection.h file | annotate | diff | comparison | revisions
src/cx/hash_map.h file | annotate | diff | comparison | revisions
src/cx/kv_list.h file | annotate | diff | comparison | revisions
src/cx/linked_list.h file | annotate | diff | comparison | revisions
src/cx/list.h file | annotate | diff | comparison | revisions
src/json.c file | annotate | diff | comparison | revisions
src/kv_list.c file | annotate | diff | comparison | revisions
src/linked_list.c file | annotate | diff | comparison | revisions
src/list.c file | annotate | diff | comparison | revisions
tests/test_hash_map.c file | annotate | diff | comparison | revisions
tests/test_kv_list.c file | annotate | diff | comparison | revisions
tests/test_list.c file | annotate | diff | comparison | revisions
tests/test_properties.c file | annotate | diff | comparison | revisions
tests/test_tree.c file | annotate | diff | comparison | revisions
--- a/CHANGELOG	Sun Dec 14 16:21:09 2025 +0100
+++ b/CHANGELOG	Sun Dec 14 17:30:17 2025 +0100
@@ -10,11 +10,14 @@
  * adds cxBufferMaximumCapacity()
  * adds cxBufferAppendString()
  * adds CX_BUFFER_DO_NOT_FREE buffer flag
- * changes parameter order of cxBufferInit() and cxBufferCreate()
+ * changes the parameter order of cxBufferInit() and cxBufferCreate()
  * changes cxBufferReserve() to allow reducing the capacity
  * changes cxBufferTerminate() to automatically shrink the buffer
- * changes cxBufferTerminate() so that position and size are equal a after successful operation
+ * changes cxBufferTerminate() so that position and size are equal after a successful operation
  * changes cxBufferPutString() to accept any kind of string that cx_strcast() supports
+ * changes the names of cxDefineDestructor() and cxDefineAdvancedDestructor() to
+   cxSetDestructor() and cxSetdvancedDestructor()
+ * changes the name of cxCollectionCompareFunc() to cxSetCompareFunc()
  * changes the entire low-level array-list API by making it much simpler
  * changes the members of CxJson and CxJsonValue
  * changes the return value of cxJsonObjIter() to CxMapIterator
--- a/docs/Writerside/topics/about.md	Sun Dec 14 16:21:09 2025 +0100
+++ b/docs/Writerside/topics/about.md	Sun Dec 14 17:30:17 2025 +0100
@@ -37,11 +37,14 @@
 * adds cxBufferMaximumCapacity()
 * adds cxBufferAppendString()
 * adds CX_BUFFER_DO_NOT_FREE buffer flag
-* changes parameter order of cxBufferInit() and cxBufferCreate()
+* changes the parameter order of cxBufferInit() and cxBufferCreate()
 * changes cxBufferReserve() to allow reducing the capacity
 * changes cxBufferTerminate() to automatically shrink the buffer
 * changes cxBufferTerminate() so that position and size are equal after a successful operation
 * changes cxBufferPutString() to accept any kind of string that cx_strcast() supports
+* changes the names of cxDefineDestructor() and cxDefineAdvancedDestructor() to
+  cxSetDestructor() and cxSetdvancedDestructor()
+* changes the name of cxCollectionCompareFunc() to cxSetCompareFunc()
 * changes the entire low-level array-list API by making it much simpler
 * changes the members of CxJson and CxJsonValue
 * changes the return value of cxJsonObjIter() to CxMapIterator
--- a/docs/Writerside/topics/array_list.h.md	Sun Dec 14 16:21:09 2025 +0100
+++ b/docs/Writerside/topics/array_list.h.md	Sun Dec 14 17:30:17 2025 +0100
@@ -10,11 +10,7 @@
 #include <cx/array_list.h>
 
 CxList *cxArrayListCreate(const CxAllocator *allocator,
-        cx_compare_func comparator, size_t elem_size,
-        size_t initial_capacity);
-        
-CxList *cxArrayListCreateSimple(size_t elem_size,
-        size_t initial_capacity);
+        size_t elem_size, size_t initial_capacity);
 ```
 
 The remaining documentation on this page concentrates on dealing with plain C arrays.
--- a/docs/Writerside/topics/collection.h.md	Sun Dec 14 16:21:09 2025 +0100
+++ b/docs/Writerside/topics/collection.h.md	Sun Dec 14 17:30:17 2025 +0100
@@ -44,15 +44,23 @@
 
 In each case the argument `c` is a pointer to your collection. The macro will then access the base data with `c->collection`.
 
-Similar to the above macros, the `cxCollectionCompareFunc(c,f)` macro can be used to set the compare function.
+On the other hand, the following macros can be used to set the properties of a collection:
+
+```C
+cxSetCompareFunc(c, func)
+cxSetDestructor(c, destr) 
+cxSetAdvancedDestructor(c, destr, data)
+```
+
+More details on the destructor functions follow in the next section.
 
 ## Destructor Functions
 
 For working with destructors, the following macros are defined:
 
 ```C
-cxDefineDestructor(c, destr) 
-cxDefineAdvancedDestructor(c, destr, data)
+cxSetDestructor(c, destr) 
+cxSetAdvancedDestructor(c, destr, data)
 
 // use in your collection's implementation
 cx_invoke_destructor(c, elem)
@@ -62,9 +70,9 @@
 cx_invoke_advanced_destructor(c, elem) 
 ```
 
-With `cxDefineDestructor()` you can assign a simple [destructor function](allocator.h.md#destructor-functions)
+With `cxSetDestructor()` you can assign a simple [destructor function](allocator.h.md#destructor-functions)
 to an _instance_ of your collection.
-Similarly, you can assign an advanced destructor with custom `data` by using `cxDefineAdvancedDestructor`.
+Similarly, you can assign an advanced destructor with custom `data` by using `cxSetAdvancedDestructor`.
 
 Your collection _should_ be supporting destructors by invoking `cx_invoke_destructor()` whenever an element
 is removed from your collection _without_ being returned to the caller.
--- a/docs/Writerside/topics/hash_map.h.md	Sun Dec 14 16:21:09 2025 +0100
+++ b/docs/Writerside/topics/hash_map.h.md	Sun Dec 14 17:30:17 2025 +0100
@@ -14,20 +14,17 @@
 CxMap *cxHashMapCreate(const CxAllocator *allocator,
         size_t itemsize, size_t buckets);
 
-CxMap *cxHashMapCreateSimple(size_t itemsize);
-
 int cxMapRehash(CxMap *map);
 ```
 
 The function `cxHashMapCreate()` creates a new [map](map.h.md) where both the map structure
 and the contained buckets are allocated by the specified `allocator`.
-The [default allocator](allocator.h.md#default-allocator) is used in `cxHashMapCreateSimple()`.
 
 The map will store items of size `itemsize`.
 You can use the `CX_STORE_POINTERS` macro for `itemsize` to indicate that the map shall store
 pointers instead of actual items.
 
-If you pass zero for the number of `buckets`, or use `cxHashMapSimple()`,
+If you pass zero for the number of `buckets`,
 the map is initialized with a default of 16 buckets; otherwise the specified number of buckets is allocated.
 
 The function `cxMapRehash()` allocates a new array of buckets and re-distributes all elements,
--- a/docs/Writerside/topics/kv_list.h.md	Sun Dec 14 16:21:09 2025 +0100
+++ b/docs/Writerside/topics/kv_list.h.md	Sun Dec 14 17:30:17 2025 +0100
@@ -7,14 +7,10 @@
 #include <cx/kv_list.h>
 
 CxList *cxKvListCreate(const CxAllocator *allocator,
-        cx_compare_func comparator, size_t elem_size);
-        
-CxList *cxKvListCreateSimple(size_t elem_size);
+        size_t elem_size);
 
 CxMap *cxKvListCreateAsMap(const CxAllocator *allocator,
-        cx_compare_func comparator, size_t elem_size);
-        
-CxMap *cxKvListCreateAsMapSimple(size_t elem_size);
+        size_t elem_size);
 ```
 
 The lists are created as usual linked lists with an additional map to look up items by key.
--- a/docs/Writerside/topics/linked_list.h.md	Sun Dec 14 16:21:09 2025 +0100
+++ b/docs/Writerside/topics/linked_list.h.md	Sun Dec 14 17:30:17 2025 +0100
@@ -12,9 +12,7 @@
 typedef struct cx_linked_list_s cx_linked_list;
 
 CxList *cxLinkedListCreate(const CxAllocator *allocator,
-        cx_compare_func comparator, size_t elem_size);
-        
-CxList *cxLinkedListCreateSimple(size_t elem_size);
+        size_t elem_size);
 ```
 
 If you are using high-level linked lists to implement your own list structure,
--- a/docs/Writerside/topics/list.h.md	Sun Dec 14 16:21:09 2025 +0100
+++ b/docs/Writerside/topics/list.h.md	Sun Dec 14 17:30:17 2025 +0100
@@ -10,23 +10,16 @@
 #include <cx/linked_list.h>
 
 CxList *cxLinkedListCreate(const CxAllocator *allocator,
-        cx_compare_func comparator, size_t elem_size);
-        
-CxList *cxLinkedListCreateSimple(size_t elem_size);
+        size_t elem_size);
 
 #include <cx/array_list.h>
 
 CxList *cxArrayListCreate(const CxAllocator *allocator,
-        cx_compare_func comparator, size_t elem_size,
-        size_t initial_capacity);
-        
-CxList *cxArrayListCreateSimple(size_t elem_size,
-        size_t initial_capacity);
+        size_t elem_size, size_t initial_capacity);
 ```
 
 The function `cxLinkedListCreate()` creates a new linked list with the specified `allocator` which stores elements of size `elem_size`.
-The elements are supposed to be compared with the specified `comparator` (cf. [](#access-and-find)). 
-The function `cxLinkedListCreateSimple()` will use the [default allocator](allocator.h.md#default-allocator) and does not specify a compare function. 
+The elements are supposed to be compared with the specified `comparator` (cf. [](#access-and-find)).
 
 Array lists can be created with `cxArrayListCreate()` where the additional argument `initial_capacity` specifies for how many elements the underlying array shall be initially allocated.
 
@@ -51,10 +44,10 @@
 
 CxList *create_pattern_list(void) {
     // create a linked list to store patterns
-    CxList *list = cxLinkedListCreateSimple(sizeof(regex_t));
+    CxList *list = cxLinkedListCreate(NULL, sizeof(regex_t));
     
     // automatically free the pattern when list gets destroyed
-    cxDefineDestructor(list, regfree);
+    cxSetDestructor(list, regfree);
     
     return list;
 }
@@ -512,7 +505,6 @@
 
 CxList *my_list_create(
         const CxAllocator *allocator,
-        cx_compare_func cmpfun,
         size_t elem_size
 ) {
     if (allocator == NULL) {
@@ -522,7 +514,7 @@
     my_list *list = cxCalloc(allocator, 1, sizeof(my_list));
     if (list == NULL) return NULL;
     cx_list_init((CxList*)list, &my_list_class,
-            allocator, cmpfun, elem_size);
+            allocator, elem_size);
             
     // initialize your custom list data here
 
--- a/docs/Writerside/topics/map.h.md	Sun Dec 14 16:21:09 2025 +0100
+++ b/docs/Writerside/topics/map.h.md	Sun Dec 14 17:30:17 2025 +0100
@@ -9,19 +9,16 @@
 
 CxMap *cxHashMapCreate(const CxAllocator *allocator,
         size_t itemsize, size_t buckets);
-
-CxMap *cxHashMapCreateSimple(size_t itemsize);
 ```
 
 The function `cxHashMapCreate()` creates a new map where both the map structure
 and the contained buckets are allocated by the specified `allocator`.
-The [default allocator](allocator.h.md#default-allocator) is used in `cxHashMapCreateSimple()`.
 
 The map will store items of size `itemsize`.
 You can use the `CX_STORE_POINTERS` macro for `itemsize` to indicate that the map shall store
 pointers instead of actual items.
 
-If you pass zero for the number of `buckets`, or use `cxHashMapSimple()`,
+If you pass zero for the number of `buckets`,
 the map is initialized with a default of 16 buckets; otherwise the specified number of buckets is allocated.
 
 > If you want to lazy-initialize maps, you can use the global `cxEmptyMap` symbol as a placeholder instead of using a `NULL`-pointer.
@@ -41,7 +38,7 @@
 #include <cx/hash_map.h>
 
 int main() {
-    CxMap *contacts = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    CxMap *contacts = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
 
     // Build a small phone book
     cxMapPut(contacts, "John", "123-0815");
@@ -92,9 +89,9 @@
 
 int main() {
     // store strings in the map...
-    CxMap *contacts = cxHashMapCreateSimple(sizeof(cxmutstr));
+    CxMap *contacts = cxHashMapCreate(NULL, sizeof(cxmutstr), 0);
     // ...which are automatically freed when removed
-    cxDefineDestructor(contacts, cx_strfree);
+    cxSetDestructor(contacts, cx_strfree);
     
     // build a small interactive program
     const unsigned buffer_size = 256;
--- a/docs/Writerside/topics/tree.h.md	Sun Dec 14 16:21:09 2025 +0100
+++ b/docs/Writerside/topics/tree.h.md	Sun Dec 14 17:30:17 2025 +0100
@@ -428,7 +428,7 @@
 
 > Although `CxTree` supports the general concept of [destructor functions](collection.h.md#destructor-functions),
 > it is not based on `CX_COLLECTION_BASE`.
-> Therefore, the `cxDefineDestructor()` and `cxDefineAdvancedDestructor()` macros cannot be used on a `CxTree` and
+> Therefore, the `cxSetDestructor()` and `cxSetAdvancedDestructor()` macros cannot be used on a `CxTree` and
 > the fields must be set manually.
 >{style="note"}
 
--- a/src/array_list.c	Sun Dec 14 16:21:09 2025 +0100
+++ b/src/array_list.c	Sun Dec 14 17:30:17 2025 +0100
@@ -1200,7 +1200,6 @@
 
 CxList *cxArrayListCreate(
         const CxAllocator *allocator,
-        cx_compare_func comparator,
         size_t elem_size,
         size_t initial_capacity
 ) {
@@ -1211,7 +1210,7 @@
     cx_array_list *list = cxCalloc(allocator, 1, sizeof(cx_array_list));
     if (list == NULL) return NULL;
     cx_list_init((CxList*)list, &cx_array_list_class,
-        allocator, comparator, elem_size);
+        allocator, elem_size);
     list->capacity = initial_capacity;
 
     // allocate the array after the real elem_size is known
--- a/src/cx/array_list.h	Sun Dec 14 16:21:09 2025 +0100
+++ b/src/cx/array_list.h	Sun Dec 14 17:30:17 2025 +0100
@@ -766,13 +766,10 @@
  *
  * If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
  * copies of the added elements, and the compare function will be automatically set
- * to cx_cmp_ptr(), if none is given.
+ * to cx_cmp_ptr().
  *
  * @param allocator the allocator for allocating the list memory
  * (if @c NULL, the cxDefaultAllocator will be used)
- * @param comparator the comparator for the elements
- * (if @c NULL, and the list is not storing pointers, sort and find
- * functions will not work)
  * @param elem_size the size of each element in bytes
  * @param initial_capacity the initial number of elements the array can store
  * @return the created list
@@ -781,25 +778,7 @@
 cx_attr_malloc
 cx_attr_dealloc(cxListFree, 1)
 CX_EXPORT CxList *cxArrayListCreate(const CxAllocator *allocator,
-        cx_compare_func comparator, size_t elem_size, size_t initial_capacity);
-
-/**
- * Allocates an array list for storing elements with @p elem_size bytes each.
- *
- * The list will use the cxDefaultAllocator and @em NO compare function.
- * If you want to call functions that need a compare function, you have to
- * set it immediately after creation or use cxArrayListCreate().
- *
- * If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
- * copies of the added elements and the compare function will be automatically set
- * to cx_cmp_ptr().
- *
- * @param elem_size (@c size_t) the size of each element in bytes
- * @param initial_capacity (@c size_t) the initial number of elements the array can store
- * @return the created list
- */
-#define cxArrayListCreateSimple(elem_size, initial_capacity) \
-    cxArrayListCreate(NULL, NULL, elem_size, initial_capacity)
+        size_t elem_size, size_t initial_capacity);
 
 #ifdef __cplusplus
 } // extern "C"
--- a/src/cx/collection.h	Sun Dec 14 16:21:09 2025 +0100
+++ b/src/cx/collection.h	Sun Dec 14 17:30:17 2025 +0100
@@ -159,7 +159,7 @@
  * @param c a pointer to a struct that contains #CX_COLLECTION_BASE
  * @param func (@c cx_compare_func) the compare function that shall be used by @c c
  */
-#define cxCollectionCompareFunc(c, func) (c)->collection.cmpfunc = (func)
+#define cxSetCompareFunc(c, func) (c)->collection.cmpfunc = (cx_compare_func)(func)
 
 /**
  * Sets a simple destructor function for this collection.
@@ -167,7 +167,7 @@
  * @param c a pointer to a struct that contains #CX_COLLECTION_BASE
  * @param destr the destructor function
  */
-#define cxDefineDestructor(c, destr) \
+#define cxSetDestructor(c, destr) \
     (c)->collection.simple_destructor = (cx_destructor_func) destr
 
 /**
@@ -176,7 +176,7 @@
  * @param c a pointer to a struct that contains #CX_COLLECTION_BASE
  * @param destr the destructor function
  */
-#define cxDefineAdvancedDestructor(c, destr, data) \
+#define cxSetAdvancedDestructor(c, destr, data) \
     (c)->collection.advanced_destructor = (cx_destructor_func2) destr; \
     (c)->collection.destructor_data = data
 
--- a/src/cx/hash_map.h	Sun Dec 14 16:21:09 2025 +0100
+++ b/src/cx/hash_map.h	Sun Dec 14 17:30:17 2025 +0100
@@ -88,22 +88,6 @@
         size_t itemsize, size_t buckets);
 
 /**
- * Creates a new hash map with a default number of buckets.
- *
- * If @p elem_size is #CX_STORE_POINTERS, the created map stores pointers instead of
- * copies of the added elements.
- *
- * @note Iterators provided by this hash map implementation provide the remove operation.
- * The index value of an iterator is incremented when the iterator advanced without
- * removing an entry.
- * In other words, when the iterator is finished, @c index==size .
- *
- * @param itemsize (@c size_t) the size of one element
- * @return (@c CxMap*) a pointer to the new hash map
- */
-#define cxHashMapCreateSimple(itemsize) cxHashMapCreate(NULL, itemsize, 0)
-
-/**
  * Increases the number of buckets, if necessary.
  *
  * The load threshold is @c 0.75*buckets. If the element count exceeds the load
--- a/src/cx/kv_list.h	Sun Dec 14 16:21:09 2025 +0100
+++ b/src/cx/kv_list.h	Sun Dec 14 17:30:17 2025 +0100
@@ -49,7 +49,7 @@
  *
  * If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
  * copies of the added elements, and the compare function will be automatically set
- * to cx_cmp_ptr() if none is given.
+ * to cx_cmp_ptr().
  *
  * After creating the list, it can also be used as a map after converting the pointer
  * to a CxMap pointer with cxKvListAsMap().
@@ -58,9 +58,6 @@
  *
  * @param allocator the allocator for allocating the list nodes
  * (if @c NULL, the cxDefaultAllocator will be used)
- * @param comparator the comparator for the elements
- * (if @c NULL, and the list is not storing pointers, sort and find
- * functions will not work)
  * @param elem_size the size of each element in bytes
  * @return the created list
  * @see cxKvListAsMap()
@@ -68,14 +65,14 @@
  */
 cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxListFree, 1)
 CX_EXPORT CxList *cxKvListCreate(const CxAllocator *allocator,
-        cx_compare_func comparator, size_t elem_size);
+        size_t elem_size);
 
 /**
  * Allocates a linked list with a lookup-map for storing elements with @p elem_size bytes each.
  *
  * If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
  * copies of the added elements, and the compare function will be automatically set
- * to cx_cmp_ptr() if none is given.
+ * to cx_cmp_ptr().
  *
  * This function creates the list with cxKvListCreate() and immediately applies
  * cxKvListAsMap(). If you want to use the returned object as a list, you can call
@@ -83,9 +80,6 @@
  *
  * @param allocator the allocator for allocating the list nodes
  * (if @c NULL, the cxDefaultAllocator will be used)
- * @param comparator the comparator for the elements
- * (if @c NULL, and the list is not storing pointers, sort and find
- * functions will not work)
  * @param elem_size the size of each element in bytes
  * @return the created list wrapped into the CxMap interface
  * @see cxKvListAsMap()
@@ -93,52 +87,7 @@
  */
 cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxMapFree, 1)
 CX_EXPORT CxMap *cxKvListCreateAsMap(const CxAllocator *allocator,
-        cx_compare_func comparator, size_t elem_size);
-
-/**
- * Allocates a linked list with a lookup-map for storing elements with @p elem_size bytes each.
- *
- * The list will use cxDefaultAllocator and no comparator function. If you want
- * to call functions that need a comparator, you must either set one immediately
- * after list creation or use cxKvListCreate().
- *
- * If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
- * copies of the added elements, and the compare function will be automatically set
- * to cx_cmp_ptr().
- *
- * After creating the list, it can also be used as a map after converting the pointer
- * to a CxMap pointer with cxKvListAsMap().
- * When you want to use the list interface again, you can also convert the map pointer back
- * with cxKvListAsList().
- *
- * @param elem_size (@c size_t) the size of each element in bytes
- * @return (@c CxList*) the created list
- * @see cxKvListAsMap()
- * @see cxKvListAsList()
- */
-#define cxKvListCreateSimple(elem_size) cxKvListCreate(NULL, NULL, elem_size)
-
-/**
- * Allocates a linked list with a lookup-map for storing elements with @p elem_size bytes each.
- *
- * The list will use cxDefaultAllocator and no comparator function. If you want
- * to call functions that need a comparator, you must either set one immediately
- * after list creation or use cxKvListCreate().
- *
- * If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
- * copies of the added elements, and the compare function will be automatically set
- * to cx_cmp_ptr().
- *
- * This macro behaves as if the list was created with cxKvListCreateSimple() and
- * immediately followed up by cxKvListAsMap().
- * If you want to use the returned object as a list, you can call cxKvListAsList() later.
- *
- * @param elem_size (@c size_t) the size of each element in bytes
- * @return (@c CxMap*) the created list wrapped into the CxMap interface
- * @see cxKvListAsMap()
- * @see cxKvListAsList()
- */
-#define cxKvListCreateAsMapSimple(elem_size) cxKvListCreateAsMap(NULL, NULL, elem_size)
+        size_t elem_size);
 
 /**
  * Converts a map pointer belonging to a key-value-List back to the original list pointer.
@@ -152,7 +101,7 @@
 /**
  * Converts a map pointer belonging to a key-value-List back to the original list pointer.
  *
- * @param list a list created by cxKvListCreate() or cxKvListCreateSimple()
+ * @param list a list created by cxKvListCreate()
  * @return a map pointer that lets you use the list as if it was a map
  */
 cx_attr_nodiscard cx_attr_nonnull cx_attr_returns_nonnull
--- a/src/cx/linked_list.h	Sun Dec 14 16:21:09 2025 +0100
+++ b/src/cx/linked_list.h	Sun Dec 14 17:30:17 2025 +0100
@@ -87,36 +87,16 @@
  *
  * If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
  * copies of the added elements, and the compare function will be automatically set
- * to cx_cmp_ptr() if none is given.
+ * to cx_cmp_ptr().
  *
  * @param allocator the allocator for allocating the list nodes
  * (if @c NULL, the cxDefaultAllocator will be used)
- * @param comparator the comparator for the elements
- * (if @c NULL, and the list is not storing pointers, sort and find
- * functions will not work)
  * @param elem_size the size of each element in bytes
  * @return the created list
  */
 cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxListFree, 1)
 CX_EXPORT CxList *cxLinkedListCreate(const CxAllocator *allocator,
-        cx_compare_func comparator, size_t elem_size);
-
-/**
- * Allocates a linked list for storing elements with @p elem_size bytes each.
- *
- * The list will use cxDefaultAllocator and no comparator function. If you want
- * to call functions that need a comparator, you must either set one immediately
- * after list creation or use cxLinkedListCreate().
- *
- * If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
- * copies of the added elements, and the compare function will be automatically set
- * to cx_cmp_ptr().
- *
- * @param elem_size (@c size_t) the size of each element in bytes
- * @return (@c CxList*) the created list
- */
-#define cxLinkedListCreateSimple(elem_size) \
-        cxLinkedListCreate(NULL, NULL, elem_size)
+        size_t elem_size);
 
 /**
  * Instructs the linked list to reserve extra data in each node.
--- a/src/cx/list.h	Sun Dec 14 16:21:09 2025 +0100
+++ b/src/cx/list.h	Sun Dec 14 17:30:17 2025 +0100
@@ -302,7 +302,6 @@
  * @code
  * CxList *myCustomListCreate(
  *         const CxAllocator *allocator,
- *         cx_compare_func comparator,
  *         size_t elem_size
  * ) {
  *     if (allocator == NULL) {
@@ -314,7 +313,7 @@
  *
  *     // initialize
  *     cx_list_init((CxList*)list, &my_custom_list_class,
- *             allocator, comparator, elem_size);
+ *             allocator, elem_size);
  *
  *     // ... some more custom stuff ...
  *
@@ -325,13 +324,12 @@
  * @param list the list to initialize
  * @param cl the list class
  * @param allocator the allocator for the elements
- * @param comparator a compare function for the elements
  * @param elem_size the size of one element
  */
 cx_attr_nonnull_arg(1, 2, 3)
 CX_EXPORT void cx_list_init(struct cx_list_s *list,
     struct cx_list_class_s *cl, const struct cx_allocator_s *allocator,
-    cx_compare_func comparator, size_t elem_size);
+    size_t elem_size);
 
 /**
  * Returns the number of elements currently stored in the list.
--- a/src/json.c	Sun Dec 14 16:21:09 2025 +0100
+++ b/src/json.c	Sun Dec 14 17:30:17 2025 +0100
@@ -453,11 +453,10 @@
 }
 
 static CxJsonObject json_create_object_map(const CxAllocator *allocator) {
-    CxMap *map = cxKvListCreateAsMap(allocator, (cx_compare_func) cxJsonCompare, CX_STORE_POINTERS);
+    CxMap *map = cxKvListCreateAsMap(allocator, CX_STORE_POINTERS);
     if (map == NULL) return NULL; // LCOV_EXCL_LINE
-    // TODO: fix the specification of the compare function
-    map->collection.cmpfunc = (cx_compare_func) cxJsonCompare;
-    cxDefineDestructor(map, cxJsonValueFree);
+    cxSetCompareFunc(map, cxJsonCompare);
+    cxSetDestructor(map, cxJsonValueFree);
     return map;
 }
 
--- a/src/kv_list.c	Sun Dec 14 16:21:09 2025 +0100
+++ b/src/kv_list.c	Sun Dec 14 17:30:17 2025 +0100
@@ -552,7 +552,6 @@
 
 CxList *cxKvListCreate(
         const CxAllocator *allocator,
-        cx_compare_func comparator,
         size_t elem_size
 ) {
     if (allocator == NULL) {
@@ -560,7 +559,7 @@
     }
 
     // create a normal linked list and a normal hash map, first
-    CxList *list = cxLinkedListCreate(allocator, comparator, elem_size);
+    CxList *list = cxLinkedListCreate(allocator, elem_size);
     if (list == NULL) return NULL; // LCOV_EXCL_LINE
     cx_linked_list *ll = (cx_linked_list*)list;
     cx_linked_list_extra_data(ll, sizeof(CxHashKey));
@@ -613,10 +612,9 @@
 
 CxMap *cxKvListCreateAsMap(
         const CxAllocator *allocator,
-        cx_compare_func comparator,
         size_t elem_size
 ) {
-    CxList *list = cxKvListCreate(allocator, comparator, elem_size);
+    CxList *list = cxKvListCreate(allocator, elem_size);
     return list == NULL ? NULL : cxKvListAsMap(list);
 }
 
--- a/src/linked_list.c	Sun Dec 14 16:21:09 2025 +0100
+++ b/src/linked_list.c	Sun Dec 14 17:30:17 2025 +0100
@@ -1272,7 +1272,6 @@
 
 CxList *cxLinkedListCreate(
         const CxAllocator *allocator,
-        cx_compare_func comparator,
         size_t elem_size
 ) {
     if (allocator == NULL) {
@@ -1287,7 +1286,7 @@
     list->loc_extra = -1;
     list->extra_data_len = 0;
     cx_list_init((CxList*)list, &cx_linked_list_class,
-            allocator, comparator, elem_size);
+            allocator, elem_size);
 
     return (CxList *) list;
 }
--- a/src/list.c	Sun Dec 14 16:21:09 2025 +0100
+++ b/src/list.c	Sun Dec 14 17:30:17 2025 +0100
@@ -512,12 +512,11 @@
     struct cx_list_s *list,
     struct cx_list_class_s *cl,
     const struct cx_allocator_s *allocator,
-    cx_compare_func comparator,
     size_t elem_size
 ) {
     list->cl = cl;
     list->collection.allocator = allocator;
-    list->collection.cmpfunc = comparator;
+    list->collection.cmpfunc = NULL;
     if (elem_size > 0) {
         list->collection.elem_size = elem_size;
     } else {
--- a/tests/test_hash_map.c	Sun Dec 14 16:21:09 2025 +0100
+++ b/tests/test_hash_map.c	Sun Dec 14 17:30:17 2025 +0100
@@ -116,7 +116,7 @@
     CxAllocator *allocator = &talloc.base;
     CX_TEST_DO {
         CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 4);
-        cxDefineAdvancedDestructor(map, cxFree, allocator);
+        cxSetAdvancedDestructor(map, cxFree, allocator);
 
         char *val1 = cxMalloc(allocator, 8);
         strcpy(val1, "val 1");
@@ -290,7 +290,7 @@
 }
 
 CX_TEST(test_hash_map_integer_keys) {
-    CxMap *map = cxHashMapCreateSimple(sizeof(cxstring));
+    CxMap *map = cxHashMapCreate(NULL, sizeof(cxstring), 0);
     CX_TEST_DO {
         cxstring s1 = cx_str("hello");
         cxstring s2 = cx_str("world");
@@ -537,8 +537,8 @@
 }
 
 CX_TEST(test_hash_map_clone) {
-    CxMap *dst = cxHashMapCreateSimple(sizeof(int));
-    CxMap *src = cxHashMapCreateSimple(sizeof(int));
+    CxMap *dst = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxMap *src = cxHashMapCreate(NULL, sizeof(int), 0);
     const char *exist_keys[] = {"k1", "k2", "k3"};
     int exists[] = {1, 3, 4};
     const char *source_keys[] = {"k4", "k2", "k5"};
@@ -566,8 +566,8 @@
 }
 
 CX_TEST(test_hash_map_clone_alloc_fail) {
-    CxMap *dst = cxHashMapCreateSimple(sizeof(int));
-    CxMap *src = cxHashMapCreateSimple(sizeof(int));
+    CxMap *dst = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxMap *src = cxHashMapCreate(NULL, sizeof(int), 0);
     const char *exist_keys[] = {"k1", "k2", "k3"};
     int exists[] = {1, 3, 4};
     const char *source_keys[] = {"k4", "k2", "k5"};
@@ -602,9 +602,9 @@
     CxTestingAllocator talloc;
     cx_testing_allocator_init(&talloc);
     CxAllocator *allocator = &talloc.base;
-    CxMap *dst = cxHashMapCreateSimple(CX_STORE_POINTERS);
-    cxDefineAdvancedDestructor(dst, cxFree, allocator);
-    CxMap *src = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    CxMap *dst = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
+    cxSetAdvancedDestructor(dst, cxFree, allocator);
+    CxMap *src = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
     const char *exist_keys[] = {"k1", "k2", "k3"};
     int exists[] = {1, 3, 4};
     const char *source_keys[] = {"k4", "k2", "k5"};
@@ -638,10 +638,10 @@
 }
 
 CX_TEST(test_hash_map_difference) {
-    CxMap *dst = cxHashMapCreateSimple(sizeof(int));
+    CxMap *dst = cxHashMapCreate(NULL, sizeof(int), 0);
 
-    CxMap *s1 = cxHashMapCreateSimple(CX_STORE_POINTERS);
-    CxMap *s2 = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    CxMap *s1 = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
+    CxMap *s2 = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
     const char *s1_keys[] = {"k1", "k2", "k3"};
     int s1_values[] = {1, 3, 4};
     const char *s2_keys[] = {"k4", "k2", "k5"};
@@ -664,10 +664,10 @@
 }
 
 CX_TEST(test_hash_map_difference_alloc_fail) {
-    CxMap *dst = cxHashMapCreateSimple(sizeof(int));
+    CxMap *dst = cxHashMapCreate(NULL, sizeof(int), 0);
 
-    CxMap *s1 = cxHashMapCreateSimple(CX_STORE_POINTERS);
-    CxMap *s2 = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    CxMap *s1 = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
+    CxMap *s2 = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
     const char *s1_keys[] = {"k1", "k2", "k3"};
     int s1_values[] = {1, 3, 4};
     const char *s2_keys[] = {"k4", "k2", "k5"};
@@ -694,9 +694,10 @@
 }
 
 CX_TEST(test_hash_map_list_difference) {
-    CxMap *dst = cxHashMapCreateSimple(sizeof(int));
-    CxMap *src = cxHashMapCreateSimple(sizeof(int));
-    CxList *keys = cxArrayListCreate(NULL, cx_hash_key_cmp, sizeof(CxHashKey), 4);
+    CxMap *dst = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxMap *src = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxList *keys = cxArrayListCreate(NULL, sizeof(CxHashKey), 4);
+    cxSetCompareFunc(keys, cx_hash_key_cmp);
 
     const char *src_keys[] = {"k1", "k2", "k3"};
     int src_values[] = {1, 3, 4};
@@ -722,9 +723,10 @@
 }
 
 CX_TEST(test_hash_map_list_difference_alloc_fail) {
-    CxMap *dst = cxHashMapCreateSimple(sizeof(int));
-    CxMap *src = cxHashMapCreateSimple(sizeof(int));
-    CxList *keys = cxArrayListCreate(NULL, cx_hash_key_cmp, sizeof(CxHashKey), 4);
+    CxMap *dst = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxMap *src = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxList *keys = cxArrayListCreate(NULL, sizeof(CxHashKey), 4);
+    cxSetCompareFunc(keys, cx_hash_key_cmp);
 
     const char *src_keys[] = {"k1", "k2", "k3"};
     int src_values[] = {1, 3, 4};
@@ -754,11 +756,11 @@
 }
 
 CX_TEST(test_hash_map_difference_non_empty_target) {
-    CxMap *dst = cxHashMapCreateSimple(CX_STORE_POINTERS);
-    cxDefineAdvancedDestructor(dst, cxFree, (void*) cxDefaultAllocator);
+    CxMap *dst = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
+    cxSetAdvancedDestructor(dst, cxFree, (void*) cxDefaultAllocator);
 
-    CxMap *s1 = cxHashMapCreateSimple(sizeof(int));
-    CxMap *s2 = cxHashMapCreateSimple(sizeof(int));
+    CxMap *s1 = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxMap *s2 = cxHashMapCreate(NULL, sizeof(int), 0);
     const char *s1_keys[] = {"k1", "k2", "k3"};
     int s1_values[] = {1, 3, 4};
     const char *s2_keys[] = {"k4", "k2", "k5"};
@@ -788,10 +790,11 @@
 }
 
 CX_TEST(test_hash_map_list_difference_non_empty_target) {
-    CxMap *dst = cxHashMapCreateSimple(CX_STORE_POINTERS);
-    cxDefineAdvancedDestructor(dst, cxFree, (void*) cxDefaultAllocator);
-    CxMap *src = cxHashMapCreateSimple(sizeof(int));
-    CxList *keys = cxArrayListCreate(NULL, cx_hash_key_cmp, sizeof(CxHashKey), 4);
+    CxMap *dst = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
+    cxSetAdvancedDestructor(dst, cxFree, (void*) cxDefaultAllocator);
+    CxMap *src = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxList *keys = cxArrayListCreate(NULL, sizeof(CxHashKey), 4);
+    cxSetCompareFunc(keys, cx_hash_key_cmp);
 
     const char *src_keys[] = {"k1", "k2", "k3"};
     int src_values[] = {1, 3, 4};
@@ -827,11 +830,11 @@
     CxTestingAllocator talloc;
     cx_testing_allocator_init(&talloc);
     CxAllocator *allocator = &talloc.base;
-    CxMap *dst = cxHashMapCreateSimple(CX_STORE_POINTERS);
-    cxDefineAdvancedDestructor(dst, cxFree, allocator);
+    CxMap *dst = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
+    cxSetAdvancedDestructor(dst, cxFree, allocator);
 
-    CxMap *s1 = cxHashMapCreateSimple(CX_STORE_POINTERS);
-    CxMap *s2 = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    CxMap *s1 = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
+    CxMap *s2 = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
     const char *s1_keys[] = {"k1", "k2", "k3"};
     int s1_values[] = {1, 3, 4};
     const char *s2_keys[] = {"k4", "k2", "k5"};
@@ -858,10 +861,10 @@
 }
 
 CX_TEST(test_hash_map_intersection) {
-    CxMap *dst = cxHashMapCreateSimple(sizeof(int));
+    CxMap *dst = cxHashMapCreate(NULL, sizeof(int), 0);
 
-    CxMap *s1 = cxHashMapCreateSimple(CX_STORE_POINTERS);
-    CxMap *s2 = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    CxMap *s1 = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
+    CxMap *s2 = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
     const char *s1_keys[] = {"k1", "k2", "k3", "k4"};
     int s1_values[] = {1, 3, 4, 6};
     const char *s2_keys[] = {"k4", "k5", "k2", "k6"};
@@ -883,10 +886,10 @@
 }
 
 CX_TEST(test_hash_map_intersection_alloc_fail) {
-    CxMap *dst = cxHashMapCreateSimple(sizeof(int));
+    CxMap *dst = cxHashMapCreate(NULL, sizeof(int), 0);
 
-    CxMap *s1 = cxHashMapCreateSimple(CX_STORE_POINTERS);
-    CxMap *s2 = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    CxMap *s1 = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
+    CxMap *s2 = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
     const char *s1_keys[] = {"k1", "k2", "k3", "k4"};
     int s1_values[] = {1, 3, 4, 6};
     const char *s2_keys[] = {"k4", "k5", "k2", "k6"};
@@ -912,9 +915,10 @@
 }
 
 CX_TEST(test_hash_map_list_intersection) {
-    CxMap *dst = cxHashMapCreateSimple(sizeof(int));
-    CxMap *src = cxHashMapCreateSimple(sizeof(int));
-    CxList *keys = cxArrayListCreate(NULL, cx_hash_key_cmp, sizeof(CxHashKey), 4);
+    CxMap *dst = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxMap *src = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxList *keys = cxArrayListCreate(NULL, sizeof(CxHashKey), 4);
+    cxSetCompareFunc(keys, cx_hash_key_cmp);
 
     const char *src_keys[] = {"k1", "k2", "k3", "k4"};
     int src_values[] = {1, 3, 4, 6};
@@ -939,9 +943,10 @@
 }
 
 CX_TEST(test_hash_map_list_intersection_alloc_fail) {
-    CxMap *dst = cxHashMapCreateSimple(sizeof(int));
-    CxMap *src = cxHashMapCreateSimple(sizeof(int));
-    CxList *keys = cxArrayListCreate(NULL, cx_hash_key_cmp, sizeof(CxHashKey), 4);
+    CxMap *dst = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxMap *src = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxList *keys = cxArrayListCreate(NULL, sizeof(CxHashKey), 4);
+    cxSetCompareFunc(keys, cx_hash_key_cmp);
 
     const char *src_keys[] = {"k1", "k2", "k3", "k4"};
     int src_values[] = {1, 3, 4, 6};
@@ -970,11 +975,11 @@
 }
 
 CX_TEST(test_hash_map_intersection_non_empty_target) {
-    CxMap *dst = cxHashMapCreateSimple(CX_STORE_POINTERS);
-    cxDefineAdvancedDestructor(dst, cxFree, (void*) cxDefaultAllocator);
+    CxMap *dst = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
+    cxSetAdvancedDestructor(dst, cxFree, (void*) cxDefaultAllocator);
 
-    CxMap *s1 = cxHashMapCreateSimple(sizeof(int));
-    CxMap *s2 = cxHashMapCreateSimple(sizeof(int));
+    CxMap *s1 = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxMap *s2 = cxHashMapCreate(NULL, sizeof(int), 0);
     const char *s1_keys[] = {"k1", "k2", "k3", "k4"};
     int s1_values[] = {1, 3, 4, 6};
     const char *s2_keys[] = {"k4", "k5", "k2", "k6"};
@@ -1003,10 +1008,11 @@
 }
 
 CX_TEST(test_hash_map_list_intersection_non_empty_target) {
-    CxMap *dst = cxHashMapCreateSimple(CX_STORE_POINTERS);
-    cxDefineAdvancedDestructor(dst, cxFree, (void*) cxDefaultAllocator);
-    CxMap *src = cxHashMapCreateSimple(sizeof(int));
-    CxList *keys = cxArrayListCreate(NULL, cx_hash_key_cmp, sizeof(CxHashKey), 4);
+    CxMap *dst = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
+    cxSetAdvancedDestructor(dst, cxFree, (void*) cxDefaultAllocator);
+    CxMap *src = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxList *keys = cxArrayListCreate(NULL, sizeof(CxHashKey), 4);
+    cxSetCompareFunc(keys, cx_hash_key_cmp);
 
     const char *src_keys[] = {"k1", "k2", "k3", "k4"};
     int src_values[] = {1, 3, 4, 6};
@@ -1042,11 +1048,11 @@
     CxTestingAllocator talloc;
     cx_testing_allocator_init(&talloc);
     CxAllocator *allocator = &talloc.base;
-    CxMap *dst = cxHashMapCreateSimple(CX_STORE_POINTERS);
-    cxDefineAdvancedDestructor(dst, cxFree, allocator);
+    CxMap *dst = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
+    cxSetAdvancedDestructor(dst, cxFree, allocator);
 
-    CxMap *s1 = cxHashMapCreateSimple(CX_STORE_POINTERS);
-    CxMap *s2 = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    CxMap *s1 = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
+    CxMap *s2 = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
     const char *s1_keys[] = {"k1", "k2", "k3", "k4"};
     int s1_values[] = {1, 3, 4, 6};
     const char *s2_keys[] = {"k4", "k5", "k2", "k6"};
@@ -1070,8 +1076,8 @@
 }
 
 CX_TEST(test_hash_map_union) {
-    CxMap *s1 = cxHashMapCreateSimple(sizeof(int));
-    CxMap *s2 = cxHashMapCreateSimple(sizeof(int));
+    CxMap *s1 = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxMap *s2 = cxHashMapCreate(NULL, sizeof(int), 0);
     const char *s1_keys[] = {"k1", "k2", "k3", "k4"};
     int s1_values[] = {1, 3, 4, 6};
     const char *s2_keys[] = {"k4", "k5", "k2", "k6"};
@@ -1099,11 +1105,11 @@
     CxTestingAllocator talloc;
     cx_testing_allocator_init(&talloc);
     CxAllocator *allocator = &talloc.base;
-    CxMap *dst = cxHashMapCreateSimple(CX_STORE_POINTERS);
-    cxDefineAdvancedDestructor(dst, cxFree, allocator);
+    CxMap *dst = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
+    cxSetAdvancedDestructor(dst, cxFree, allocator);
 
-    CxMap *s1 = cxHashMapCreateSimple(sizeof(int));
-    CxMap *s2 = cxHashMapCreateSimple(sizeof(int));
+    CxMap *s1 = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxMap *s2 = cxHashMapCreate(NULL, sizeof(int), 0);
     const char *s1_keys[] = {"k1", "k2", "k3", "k4"};
     int s1_values[] = {1, 3, 4, 6};
     const char *s2_keys[] = {"k4", "k5", "k2", "k6"};
@@ -1132,8 +1138,8 @@
 }
 
 CX_TEST(test_hash_map_union_alloc_fail) {
-    CxMap *s1 = cxHashMapCreateSimple(sizeof(int));
-    CxMap *s2 = cxHashMapCreateSimple(sizeof(int));
+    CxMap *s1 = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxMap *s2 = cxHashMapCreate(NULL, sizeof(int), 0);
     const char *s1_keys[] = {"k1", "k2", "k3", "k4"};
     int s1_values[] = {1, 3, 4, 6};
     const char *s2_keys[] = {"k4", "k5", "k2", "k6"};
@@ -1163,26 +1169,26 @@
 
 CX_TEST(test_hash_map_simple_clones) {
     int v = 47; // the value does not matter in this test
-    CxMap *a = cxHashMapCreateSimple(sizeof(int));
+    CxMap *a = cxHashMapCreate(NULL, sizeof(int), 0);
     cxMapPut(a, "k1", &v);
     cxMapPut(a, "k2", &v);
     cxMapPut(a, "k3", &v);
     cxMapPut(a, "k4", &v);
 
-    CxMap *b = cxHashMapCreateSimple(sizeof(int));
+    CxMap *b = cxHashMapCreate(NULL, sizeof(int), 0);
     cxMapPut(b, "k0", &v);
     cxMapPut(b, "k2", &v);
     cxMapPut(b, "k5", &v);
 
-    CxMap *c = cxHashMapCreateSimple(sizeof(int));
+    CxMap *c = cxHashMapCreate(NULL, sizeof(int), 0);
     cxMapPut(c, "k3", &v);
     cxMapPut(c, "k4", &v);
     cxMapPut(c, "k5", &v);
 
 
     CxHashKey k;
-    CxList *kl1 = cxArrayListCreateSimple(sizeof(CxHashKey), 4);
-    cxCollectionCompareFunc(kl1, cx_hash_key_cmp);
+    CxList *kl1 = cxArrayListCreate(NULL, sizeof(CxHashKey), 4);
+    cxSetCompareFunc(kl1, cx_hash_key_cmp);
     k = CX_HASH_KEY("k0");
     cxListAdd(kl1, &k);
     k = CX_HASH_KEY("k2");
@@ -1190,8 +1196,8 @@
     k = CX_HASH_KEY("k5");
     cxListAdd(kl1, &k);
 
-    CxList *kl2 = cxArrayListCreateSimple(sizeof(CxHashKey), 4);
-    cxCollectionCompareFunc(kl2, cx_hash_key_cmp);
+    CxList *kl2 = cxArrayListCreate(NULL, sizeof(CxHashKey), 4);
+    cxSetCompareFunc(kl2, cx_hash_key_cmp);
     k = CX_HASH_KEY("k3");
     cxListAdd(kl2, &k);
     k = CX_HASH_KEY("k4");
@@ -1199,8 +1205,8 @@
     k = CX_HASH_KEY("k5");
     cxListAdd(kl2, &k);
 
-    CxMap *d1 = cxHashMapCreateSimple(sizeof(int));
-    CxMap *d2 = cxHashMapCreateSimple(sizeof(int));
+    CxMap *d1 = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxMap *d2 = cxHashMapCreate(NULL, sizeof(int), 0);
 
     CX_TEST_DO {
         CX_TEST_ASSERT(0 == cxMapCloneShallow(d1, a));
@@ -1264,8 +1270,8 @@
 }
 
 CX_TEST(test_hash_map_compare) {
-    CxMap *map1 = cxHashMapCreateSimple(sizeof(int));
-    CxMap *map2 = cxHashMapCreateSimple(CX_STORE_POINTERS);
+    CxMap *map1 = cxHashMapCreate(NULL, sizeof(int), 0);
+    CxMap *map2 = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
     // TODO: fix specification of compare function once #622 is realized
     map1->collection.cmpfunc = cx_cmp_int;
     map2->collection.cmpfunc = cx_cmp_int;
--- a/tests/test_kv_list.c	Sun Dec 14 16:21:09 2025 +0100
+++ b/tests/test_kv_list.c	Sun Dec 14 17:30:17 2025 +0100
@@ -44,7 +44,7 @@
 }
 
 CX_TEST(test_kv_list_map_as_list) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     CX_TEST_DO {
         CxMap *map = cxKvListAsMap(list);
         CX_TEST_ASSERT(map != NULL);
@@ -58,7 +58,7 @@
     CxTestingAllocator talloc;
     cx_testing_allocator_init(&talloc);
     CX_TEST_DO {
-        CxList *list = cxKvListCreate(&talloc.base, NULL, 1);
+        CxList *list = cxKvListCreate(&talloc.base, 1);
         cxListAddArray(list, "test", 4);
         CxMap *map = cxKvListAsMap(list);
         cxMapFree(map);
@@ -71,7 +71,7 @@
     CxTestingAllocator talloc;
     cx_testing_allocator_init(&talloc);
     CX_TEST_DO {
-        CxMap *map = cxKvListCreateAsMap(&talloc.base, NULL, sizeof(int));
+        CxMap *map = cxKvListCreateAsMap(&talloc.base, sizeof(int));
         int x = 5;
         cxMapPut(map, "test", &x);
         CxList *list = cxKvListAsList(map);
@@ -82,7 +82,7 @@
 }
 
 CX_TEST(test_kv_list_remove) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         CxMap *map = cxKvListAsMap(list);
@@ -121,8 +121,8 @@
 }
 
 CX_TEST(test_kv_list_find_and_remove) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
-    cxCollectionCompareFunc(list, cx_cmp_int);
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
+    cxSetCompareFunc(list, cx_cmp_int);
     int x, y;
     CX_TEST_DO {
         CxMap *map = cxKvListAsMap(list);
@@ -174,7 +174,7 @@
 }
 
 CX_TEST(test_kv_list_remove_and_get) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x, y;
     CX_TEST_DO {
         CxMap *map = cxKvListAsMap(list);
@@ -216,7 +216,7 @@
 }
 
 CX_TEST(test_kv_list_remove_array) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         CxMap *map = cxKvListAsMap(list);
@@ -247,7 +247,7 @@
 }
 
 CX_TEST(test_kv_list_remove_array_and_get) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         CxMap *map = cxKvListAsMap(list);
@@ -282,7 +282,7 @@
 }
 
 CX_TEST(test_kv_list_map_put) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         CxMap *map = cxKvListAsMap(list);
@@ -305,7 +305,7 @@
 }
 
 CX_TEST(test_kv_list_map_put_ptr) {
-    CxList *list = cxKvListCreateSimple(CX_STORE_POINTERS);
+    CxList *list = cxKvListCreate(NULL, CX_STORE_POINTERS);
     int x;
     CX_TEST_DO {
         CxMap *map = cxKvListAsMap(list);
@@ -319,7 +319,7 @@
 }
 
 CX_TEST(test_kv_list_map_put_not_hashed) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         CxMap *map = cxKvListAsMap(list);
@@ -340,14 +340,14 @@
 }
 
 CX_TEST(test_kv_list_map_put_overwrite) {
-    CxList *list = cxKvListCreateSimple(CX_STORE_POINTERS);
+    CxList *list = cxKvListCreate(NULL, CX_STORE_POINTERS);
     CxTestingAllocator talloc;
     cx_testing_allocator_init(&talloc);
     CxAllocator *al = &talloc.base;
     int *x, *y;
     CX_TEST_DO {
         CxMap *map = cxKvListAsMap(list);
-        cxDefineAdvancedDestructor(map, cxFree, al);
+        cxSetAdvancedDestructor(map, cxFree, al);
         x = cxMalloc(al, sizeof(int));
         y = cxMalloc(al, sizeof(int));
         *x = 13;
@@ -370,7 +370,7 @@
 }
 
 CX_TEST(test_kv_list_map_remove) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         CxMap *map = cxKvListAsMap(list);
@@ -397,7 +397,7 @@
 }
 
 CX_TEST(test_kv_list_map_remove_and_get) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x, y;
     CX_TEST_DO {
         CxMap *map = cxKvListAsMap(list);
@@ -409,7 +409,7 @@
         CX_TEST_ASSERT(0 == cxMapPut(map, "abc", &x));
 
         CX_TEST_ASSERT(cxMapSize(map) == 2);
-        cxDefineDestructor(map, kv_list_test_destr);
+        cxSetDestructor(map, kv_list_test_destr);
         kv_list_test_destr_val = 0;
         y = 0;
         CX_TEST_ASSERT(0 == cxMapRemoveAndGet(map, "xyz", &y));
@@ -429,7 +429,7 @@
 }
 
 CX_TEST(test_kv_list_set_key) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         x = 47;
@@ -471,7 +471,7 @@
 }
 
 CX_TEST(test_kv_list_set_key_already_exists) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         x = 47;
@@ -504,7 +504,7 @@
 }
 
 CX_TEST(test_kv_list_set_key_again) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         x = 47;
@@ -531,7 +531,7 @@
 }
 
 CX_TEST(test_kv_list_remove_key) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         CxMap *map = cxKvListAsMap(list);
@@ -573,7 +573,7 @@
 }
 
 CX_TEST(test_kv_list_get_key) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         CxMap *map = cxKvListAsMap(list);
@@ -607,7 +607,7 @@
 }
 
 CX_TEST(test_kv_list_insert_with_key) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         x = 47;
@@ -632,7 +632,7 @@
 }
 
 CX_TEST(test_kv_list_insert_ptr_with_key) {
-    CxList *list = cxKvListCreateSimple(CX_STORE_POINTERS);
+    CxList *list = cxKvListCreate(NULL, CX_STORE_POINTERS);
     int x, y, z;
     CX_TEST_DO {
         x = 15;
@@ -660,7 +660,7 @@
 }
 
 CX_TEST(test_kv_list_insert_array_and_set_keys) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     CX_TEST_DO {
         int arr[] = { 13, 21, 34, 55, 89 };
         CX_TEST_ASSERT(5 == cxListAddArray(list, arr, 5));
@@ -683,14 +683,14 @@
 }
 
 CX_TEST(test_kv_list_list_remove_destr_in_list) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         x = 0xabcd;
         CX_TEST_ASSERT(0 == cxListAdd(list, &x));
         cxKvListSetKey(list, 0, "xyz");
 
-        cxDefineDestructor(list, kv_list_test_destr);
+        cxSetDestructor(list, kv_list_test_destr);
         kv_list_test_destr_val = 0;
         CX_TEST_ASSERT(0 == cxListRemove(list, 0));
         CX_TEST_ASSERT(kv_list_test_destr_val == 0xabcd);
@@ -699,14 +699,14 @@
 }
 
 CX_TEST(test_kv_list_list_remove_destr_in_map) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         x = 0xabcd;
         CX_TEST_ASSERT(0 == cxListAdd(list, &x));
         cxKvListSetKey(list, 0, "xyz");
         CxMap *map = cxKvListAsMap(list);
-        cxDefineDestructor(map, kv_list_test_destr);
+        cxSetDestructor(map, kv_list_test_destr);
         kv_list_test_destr_val = 0;
         CX_TEST_ASSERT(0 == cxListRemove(list, 0));
         CX_TEST_ASSERT(kv_list_test_destr_val == 0xabcd);
@@ -715,13 +715,13 @@
 }
 
 CX_TEST(test_kv_list_map_remove_destr_in_list) {
-    CxMap *map = cxKvListCreateAsMapSimple(sizeof(int));
+    CxMap *map = cxKvListCreateAsMap(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         x = 0xabcd;
         CX_TEST_ASSERT(0 == cxMapPut(map, "xyz", &x));
         CxList *list = cxKvListAsList(map);
-        cxDefineDestructor(list, kv_list_test_destr);
+        cxSetDestructor(list, kv_list_test_destr);
         kv_list_test_destr_val = 0;
         CX_TEST_ASSERT(0 == cxMapRemove(map, "xyz"));
         CX_TEST_ASSERT(kv_list_test_destr_val == 0xabcd);
@@ -730,13 +730,13 @@
 }
 
 CX_TEST(test_kv_list_map_remove_destr_in_map) {
-    CxMap *map = cxKvListCreateAsMapSimple(sizeof(int));
+    CxMap *map = cxKvListCreateAsMap(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         x = 0xabcd;
         CX_TEST_ASSERT(0 == cxMapPut(map, "xyz", &x));
 
-        cxDefineDestructor(map, kv_list_test_destr);
+        cxSetDestructor(map, kv_list_test_destr);
         kv_list_test_destr_val = 0;
         CX_TEST_ASSERT(0 == cxMapRemove(map, "xyz"));
         CX_TEST_ASSERT(kv_list_test_destr_val == 0xabcd);
@@ -745,14 +745,14 @@
 }
 
 CX_TEST(test_kv_list_list_remove_destr2_in_list) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         x = 0xabcd;
         CX_TEST_ASSERT(0 == cxListAdd(list, &x));
         cxKvListSetKey(list, 0, "xyz");
 
-        cxDefineAdvancedDestructor(list, kv_list_test_destr2, (void*)0xef47);
+        cxSetAdvancedDestructor(list, kv_list_test_destr2, (void*)0xef47);
         kv_list_test_destr2_val = 0;
         kv_list_test_destr2_extra = NULL;
         CX_TEST_ASSERT(0 == cxListRemove(list, 0));
@@ -763,14 +763,14 @@
 }
 
 CX_TEST(test_kv_list_list_remove_destr2_in_map) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         x = 0xabcd;
         CX_TEST_ASSERT(0 == cxListAdd(list, &x));
         cxKvListSetKey(list, 0, "xyz");
         CxMap *map = cxKvListAsMap(list);
-        cxDefineAdvancedDestructor(map, kv_list_test_destr2, (void*)0xef47);
+        cxSetAdvancedDestructor(map, kv_list_test_destr2, (void*)0xef47);
         kv_list_test_destr2_val = 0;
         kv_list_test_destr2_extra = NULL;
         CX_TEST_ASSERT(0 == cxListRemove(list, 0));
@@ -781,13 +781,13 @@
 }
 
 CX_TEST(test_kv_list_map_remove_destr2_in_list) {
-    CxMap *map = cxKvListCreateAsMapSimple(sizeof(int));
+    CxMap *map = cxKvListCreateAsMap(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         x = 0xabcd;
         CX_TEST_ASSERT(0 == cxMapPut(map, "xyz", &x));
         CxList *list = cxKvListAsList(map);
-        cxDefineAdvancedDestructor(list, kv_list_test_destr2, (void*)0xef47);
+        cxSetAdvancedDestructor(list, kv_list_test_destr2, (void*)0xef47);
         kv_list_test_destr2_val = 0;
         kv_list_test_destr2_extra = NULL;
         CX_TEST_ASSERT(0 == cxMapRemove(map, "xyz"));
@@ -798,13 +798,13 @@
 }
 
 CX_TEST(test_kv_list_map_remove_destr2_in_map) {
-    CxMap *map = cxKvListCreateAsMapSimple(sizeof(int));
+    CxMap *map = cxKvListCreateAsMap(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         x = 0xabcd;
         CX_TEST_ASSERT(0 == cxMapPut(map, "xyz", &x));
 
-        cxDefineAdvancedDestructor(map, kv_list_test_destr2, (void*)0xef47);
+        cxSetAdvancedDestructor(map, kv_list_test_destr2, (void*)0xef47);
         kv_list_test_destr2_val = 0;
         kv_list_test_destr2_extra = NULL;
         CX_TEST_ASSERT(0 == cxMapRemove(map, "xyz"));
@@ -815,14 +815,14 @@
 }
 
 CX_TEST(test_kv_list_list_clear_destr_in_list) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         x = 0xabcd;
         CX_TEST_ASSERT(0 == cxListAdd(list, &x));
         cxKvListSetKey(list, 0, "xyz");
 
-        cxDefineDestructor(list, kv_list_test_destr);
+        cxSetDestructor(list, kv_list_test_destr);
         kv_list_test_destr_val = 0;
         cxListClear(list);
         CX_TEST_ASSERT(kv_list_test_destr_val == 0xabcd);
@@ -831,14 +831,14 @@
 }
 
 CX_TEST(test_kv_list_list_clear_destr_in_map) {
-    CxList *list = cxKvListCreateSimple(sizeof(int));
+    CxList *list = cxKvListCreate(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         x = 0xabcd;
         CX_TEST_ASSERT(0 == cxListAdd(list, &x));
         cxKvListSetKey(list, 0, "xyz");
         CxMap *map = cxKvListAsMap(list);
-        cxDefineDestructor(map, kv_list_test_destr);
+        cxSetDestructor(map, kv_list_test_destr);
         kv_list_test_destr_val = 0;
         cxListClear(list);
         CX_TEST_ASSERT(kv_list_test_destr_val == 0xabcd);
@@ -847,13 +847,13 @@
 }
 
 CX_TEST(test_kv_list_map_clear_destr_in_list) {
-    CxMap *map = cxKvListCreateAsMapSimple(sizeof(int));
+    CxMap *map = cxKvListCreateAsMap(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         x = 0xabcd;
         CX_TEST_ASSERT(0 == cxMapPut(map, "xyz", &x));
         CxList *list = cxKvListAsList(map);
-        cxDefineDestructor(list, kv_list_test_destr);
+        cxSetDestructor(list, kv_list_test_destr);
         kv_list_test_destr_val = 0;
         cxMapClear(map);
         CX_TEST_ASSERT(kv_list_test_destr_val == 0xabcd);
@@ -862,13 +862,13 @@
 }
 
 CX_TEST(test_kv_list_map_clear_destr_in_map) {
-    CxMap *map = cxKvListCreateAsMapSimple(sizeof(int));
+    CxMap *map = cxKvListCreateAsMap(NULL, sizeof(int));
     int x;
     CX_TEST_DO {
         x = 0xabcd;
         CX_TEST_ASSERT(0 == cxMapPut(map, "xyz", &x));
 
-        cxDefineDestructor(map, kv_list_test_destr);
+        cxSetDestructor(map, kv_list_test_destr);
         kv_list_test_destr_val = 0;
         cxMapClear(map);
         CX_TEST_ASSERT(kv_list_test_destr_val == 0xabcd);
@@ -877,8 +877,8 @@
 }
 
 CX_TEST(test_kv_list_destr_ptr) {
-    CxMap *map = cxKvListCreateAsMapSimple(CX_STORE_POINTERS);
-    cxDefineDestructor(map, kv_list_test_destr);
+    CxMap *map = cxKvListCreateAsMap(NULL, CX_STORE_POINTERS);
+    cxSetDestructor(map, kv_list_test_destr);
     int x;
     CX_TEST_DO {
         x = 0xabcd;
@@ -892,7 +892,7 @@
 }
 
 CX_TEST(test_kv_list_map_iterator) {
-    CxMap *map = cxKvListCreateAsMapSimple(sizeof(int));
+    CxMap *map = cxKvListCreateAsMap(NULL, sizeof(int));
     CX_TEST_DO {
         int x;
         x = 0xc0ffee; // this element shall be skipped
@@ -953,7 +953,7 @@
 }
 
 CX_TEST(test_kv_list_map_iterator_no_keys) {
-    CxMap *map = cxKvListCreateAsMapSimple(sizeof(int));
+    CxMap *map = cxKvListCreateAsMap(NULL, sizeof(int));
     CX_TEST_DO {
         CxList *list = cxKvListAsList(map);
         int x;
@@ -974,10 +974,10 @@
 }
 
 CX_TEST(test_kv_list_map_iterator_remove) {
-    CxMap *map = cxKvListCreateAsMapSimple(CX_STORE_POINTERS);
+    CxMap *map = cxKvListCreateAsMap(NULL, CX_STORE_POINTERS);
     int x, y, z;
     CX_TEST_DO {
-        cxDefineDestructor(map, kv_list_test_destr);
+        cxSetDestructor(map, kv_list_test_destr);
         x = 815;
         cxMapPut(map, "xyz", &x);
         y = 8016;
@@ -1005,9 +1005,9 @@
 }
 
 CX_TEST(test_kv_list_list_iterator_remove) {
-    CxMap *map = cxKvListCreateAsMapSimple(sizeof(int));
+    CxMap *map = cxKvListCreateAsMap(NULL, sizeof(int));
     CX_TEST_DO {
-        cxDefineAdvancedDestructor(map, kv_list_test_destr2, (void*)0xf00);
+        cxSetAdvancedDestructor(map, kv_list_test_destr2, (void*)0xf00);
         int x;
         x = 815;
         cxMapPut(map, "xyz", &x);
--- a/tests/test_list.c	Sun Dec 14 16:21:09 2025 +0100
+++ b/tests/test_list.c	Sun Dec 14 17:30:17 2025 +0100
@@ -1394,7 +1394,7 @@
         CX_TEST_ASSERT(cxListAt(cxEmptyList, 0) == NULL);
         CX_TEST_ASSERT(cxListAt(cxEmptyList, 1) == NULL);
         // a "true" empty list
-        CxList *list = cxLinkedListCreateSimple(sizeof(int));
+        CxList *list = cxLinkedListCreate(NULL, sizeof(int));
         CX_TEST_ASSERT(cxListAt(list, 0) == NULL);
         CX_TEST_ASSERT(cxListAt(list, 1) == NULL);
         cxListFree(list);
@@ -1408,7 +1408,7 @@
         CX_TEST_ASSERT(cxListFind(cxEmptyList, &x) == 0);
         CX_TEST_ASSERT(cxListFindRemove(cxEmptyList, &y) == 0);
         // a "true" empty list
-        CxList *list = cxLinkedListCreateSimple(sizeof(int));
+        CxList *list = cxLinkedListCreate(NULL, sizeof(int));
         CX_TEST_ASSERT(cxListFind(list, &x) == 0);
         CX_TEST_ASSERT(cxListFindRemove(list, &y) == 0);
         cxListFree(list);
@@ -1417,8 +1417,8 @@
 
 CX_TEST(test_empty_list_compare) {
     CxList *empty = cxEmptyList;
-    CxList *ll = cxLinkedListCreateSimple(sizeof(int));
-    CxList *al = cxArrayListCreateSimple(sizeof(int), 8);
+    CxList *ll = cxLinkedListCreate(NULL, sizeof(int));
+    CxList *al = cxArrayListCreate(NULL, sizeof(int), 8);
     int x = 5;
     CX_TEST_DO {
         CX_TEST_ASSERT(0 == cxListCompare(empty, cxEmptyList));
@@ -1451,8 +1451,9 @@
     cx_testing_allocator_init(&talloc);
     CxAllocator *alloc = &talloc.base;
     CX_TEST_DO {
-        CxList *list = cxLinkedListCreate(alloc, cx_cmp_int, sizeof(int));
+        CxList *list = cxLinkedListCreate(alloc, sizeof(int));
         CX_TEST_ASSERT(list != NULL);
+        cxSetCompareFunc(list, cx_cmp_int);
         CX_TEST_ASSERT(list->collection.elem_size == sizeof(int));
         CX_TEST_ASSERT(list->collection.simple_destructor == NULL);
         CX_TEST_ASSERT(list->collection.advanced_destructor == NULL);
@@ -1468,7 +1469,7 @@
 }
 
 CX_TEST(test_list_ll_create_simple) {
-    CxList *list = cxLinkedListCreateSimple(sizeof(int));
+    CxList *list = cxLinkedListCreate(NULL, sizeof(int));
     CX_TEST_DO {
         CX_TEST_ASSERT(list != NULL);
         CX_TEST_ASSERT(list->collection.elem_size == sizeof(int));
@@ -1484,7 +1485,7 @@
 }
 
 CX_TEST(test_list_ll_create_simple_for_pointers) {
-    CxList *list = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    CxList *list = cxLinkedListCreate(NULL, CX_STORE_POINTERS);
     CX_TEST_DO {
         CX_TEST_ASSERT(list != NULL);
         CX_TEST_ASSERT(list->collection.elem_size == sizeof(void*));
@@ -1504,8 +1505,9 @@
     cx_testing_allocator_init(&talloc);
     CxAllocator *alloc = &talloc.base;
     CX_TEST_DO {
-        CxList *list = cxArrayListCreate(alloc, cx_cmp_int, sizeof(int), 8);
+        CxList *list = cxArrayListCreate(alloc, sizeof(int), 8);
         CX_TEST_ASSERT(list != NULL);
+        cxSetCompareFunc(list, cx_cmp_int);
         CX_TEST_ASSERT(list->collection.elem_size == sizeof(int));
         CX_TEST_ASSERT(list->collection.simple_destructor == NULL);
         CX_TEST_ASSERT(list->collection.advanced_destructor == NULL);
@@ -1521,7 +1523,7 @@
 }
 
 CX_TEST(test_list_arl_create_simple) {
-    CxList *list = cxArrayListCreateSimple(sizeof(int), 8);
+    CxList *list = cxArrayListCreate(NULL, sizeof(int), 8);
     CX_TEST_DO {
         CX_TEST_ASSERT(list != NULL);
         CX_TEST_ASSERT(list->collection.elem_size == sizeof(int));
@@ -1537,7 +1539,7 @@
 }
 
 CX_TEST(test_list_arl_create_simple_for_pointers) {
-    CxList *list = cxArrayListCreateSimple(CX_STORE_POINTERS, 8);
+    CxList *list = cxArrayListCreate(NULL, CX_STORE_POINTERS, 8);
     CX_TEST_DO {
         CX_TEST_ASSERT(list != NULL);
         CX_TEST_ASSERT(list->collection.elem_size == sizeof(void*));
@@ -1562,7 +1564,8 @@
     CxAllocator *alloc = &talloc.base;
     CX_TEST_DO {
         void *item = cxMalloc(alloc, sizeof(int));
-        CxList *list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS);
+        CxList *list = cxLinkedListCreate(cxDefaultAllocator, CX_STORE_POINTERS);
+        cxSetCompareFunc(list, cx_cmp_int);
         cxListAdd(list, item);
         CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc));
         cxListFree(list);
@@ -1577,7 +1580,8 @@
 CX_TEST(test_list_pll_destroy_simple_destr) {
     CX_TEST_DO {
         int item = 0;
-        CxList *list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS);
+        CxList *list = cxLinkedListCreate(cxDefaultAllocator, CX_STORE_POINTERS);
+        cxSetCompareFunc(list, cx_cmp_int);
         list->collection.simple_destructor = test_fake_simple_int_destr;
         cxListAdd(list, &item);
         cxListFree(list);
@@ -1591,7 +1595,8 @@
     CxAllocator *alloc = &talloc.base;
     CX_TEST_DO {
         void *item = cxMalloc(alloc, sizeof(int));
-        CxList *list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS);
+        CxList *list = cxLinkedListCreate(cxDefaultAllocator, CX_STORE_POINTERS);
+        cxSetCompareFunc(list, cx_cmp_int);
         list->collection.destructor_data = alloc;
         list->collection.advanced_destructor = (cx_destructor_func2) cxFree;
         cxListAdd(list, item);
@@ -1608,7 +1613,8 @@
     CxAllocator *alloc = &talloc.base;
     CX_TEST_DO {
         void *item = cxMalloc(alloc, sizeof(int));
-        CxList *list = cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS, 4);
+        CxList *list = cxArrayListCreate(cxDefaultAllocator, CX_STORE_POINTERS, 4);
+        cxSetCompareFunc(list, cx_cmp_int);
         cxListAdd(list, item);
         CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc));
         cxListFree(list);
@@ -1623,7 +1629,8 @@
 CX_TEST(test_list_parl_destroy_simple_destr) {
     CX_TEST_DO {
         int item = 0;
-        CxList *list = cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS, 4);
+        CxList *list = cxArrayListCreate(cxDefaultAllocator, CX_STORE_POINTERS, 4);
+        cxSetCompareFunc(list, cx_cmp_int);
         list->collection.simple_destructor = test_fake_simple_int_destr;
         cxListAdd(list, &item);
         cxListFree(list);
@@ -1637,7 +1644,8 @@
     CxAllocator *alloc = &talloc.base;
     CX_TEST_DO {
         void *item = cxMalloc(alloc, sizeof(int));
-        CxList *list = cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS, 4);
+        CxList *list = cxArrayListCreate(cxDefaultAllocator, CX_STORE_POINTERS, 4);
+        cxSetCompareFunc(list, cx_cmp_int);
         list->collection.destructor_data = alloc;
         list->collection.advanced_destructor = (cx_destructor_func2) cxFree;
         cxListAdd(list, item);
@@ -1661,37 +1669,43 @@
 #define roll_out_test_invokers(name) \
 CX_TEST(test_list_ll_##name) { \
     set_up_combo \
-        CxList *list = cxLinkedListCreate(alloc, cx_cmp_int, sizeof(int)); \
+        CxList *list = cxLinkedListCreate(alloc, sizeof(int)); \
+        cxSetCompareFunc(list, cx_cmp_int); \
         CX_TEST_CALL_SUBROUTINE(test_list_verify_##name, list, false); \
     tear_down_combo \
 } \
 CX_TEST(test_list_arl_##name) { \
     set_up_combo \
-        CxList *list = cxArrayListCreate(alloc, cx_cmp_int, sizeof(int), 8); \
+        CxList *list = cxArrayListCreate(alloc, sizeof(int), 8); \
+        cxSetCompareFunc(list, cx_cmp_int); \
         CX_TEST_CALL_SUBROUTINE(test_list_verify_##name, list, false); \
     tear_down_combo \
 } \
 CX_TEST(test_list_kvl_##name) { \
     set_up_combo \
-        CxList *list = cxKvListCreate(alloc, cx_cmp_int, sizeof(int)); \
+        CxList *list = cxKvListCreate(alloc, sizeof(int)); \
+        cxSetCompareFunc(list, cx_cmp_int); \
         CX_TEST_CALL_SUBROUTINE(test_list_verify_##name, list, false); \
     tear_down_combo \
 } \
 CX_TEST(test_list_pll_##name) { \
     set_up_combo \
-        CxList *list = cxLinkedListCreate(alloc, cx_cmp_int, CX_STORE_POINTERS); \
+        CxList *list = cxLinkedListCreate(alloc, CX_STORE_POINTERS); \
+        cxSetCompareFunc(list, cx_cmp_int); \
         CX_TEST_CALL_SUBROUTINE(test_list_verify_##name, list, true); \
     tear_down_combo \
 } \
 CX_TEST(test_list_parl_##name) { \
     set_up_combo \
-        CxList *list = cxArrayListCreate(alloc, cx_cmp_int, CX_STORE_POINTERS, 8); \
+        CxList *list = cxArrayListCreate(alloc, CX_STORE_POINTERS, 8); \
+        cxSetCompareFunc(list, cx_cmp_int); \
         CX_TEST_CALL_SUBROUTINE(test_list_verify_##name, list, true); \
     tear_down_combo \
 } \
 CX_TEST(test_list_pkvl_##name) { \
     set_up_combo \
-        CxList *list = cxKvListCreate(alloc, cx_cmp_int, CX_STORE_POINTERS); \
+        CxList *list = cxKvListCreate(alloc, CX_STORE_POINTERS); \
+        cxSetCompareFunc(list, cx_cmp_int); \
         CX_TEST_CALL_SUBROUTINE(test_list_verify_##name, list, true); \
     tear_down_combo \
 }
@@ -1725,28 +1739,32 @@
 roll_out_test_invokers(name) \
 CX_TEST(test_list_llm_##name) { \
     set_up_combo \
-        CxList *list = cxLinkedListCreate(alloc, cx_cmp_int, sizeof(int)); \
+        CxList *list = cxLinkedListCreate(alloc, sizeof(int)); \
+        cxSetCompareFunc(list, cx_cmp_int); \
         do_set_default_class_funcs(list); \
         CX_TEST_CALL_SUBROUTINE(test_list_verify_##name, list, false); \
     tear_down_combo \
 } \
 CX_TEST(test_list_arlm_##name) { \
     set_up_combo \
-        CxList *list = cxArrayListCreate(alloc, cx_cmp_int, sizeof(int), 8); \
+        CxList *list = cxArrayListCreate(alloc, sizeof(int), 8); \
+        cxSetCompareFunc(list, cx_cmp_int); \
         do_set_default_class_funcs(list); \
         CX_TEST_CALL_SUBROUTINE(test_list_verify_##name, list, false); \
     tear_down_combo \
 } \
 CX_TEST(test_list_pllm_##name) { \
     set_up_combo \
-        CxList *list = cxLinkedListCreate(alloc, cx_cmp_int, CX_STORE_POINTERS); \
+        CxList *list = cxLinkedListCreate(alloc, CX_STORE_POINTERS); \
+        cxSetCompareFunc(list, cx_cmp_int); \
         do_set_default_class_funcs(list); \
         CX_TEST_CALL_SUBROUTINE(test_list_verify_##name, list, true); \
     tear_down_combo \
 } \
 CX_TEST(test_list_parlm_##name) { \
     set_up_combo \
-        CxList *list = cxArrayListCreate(alloc, cx_cmp_int, CX_STORE_POINTERS, 8); \
+        CxList *list = cxArrayListCreate(alloc, CX_STORE_POINTERS, 8); \
+        cxSetCompareFunc(list, cx_cmp_int); \
         do_set_default_class_funcs(list); \
         CX_TEST_CALL_SUBROUTINE(test_list_verify_##name, list, true); \
     tear_down_combo \
@@ -2221,7 +2239,7 @@
 roll_out_test_combos(remove_array, {
     const size_t testdata_len = 32;
     int *testdata = int_test_data_added_to_list(list, isptrlist, testdata_len);
-    cxDefineDestructor(list, test_remove_array_destr);
+    cxSetDestructor(list, test_remove_array_destr);
     test_remove_array_destr_ctr = 0;
 
     // first, remove and get - no destructor must be called
@@ -2443,7 +2461,8 @@
     CxAllocator *alloc = &talloc.base;
     CX_TEST_DO {
         size_t item_size = 2*cx_array_swap_sbo_size;
-        CxList *list = cxArrayListCreate(alloc, cx_cmp_int, item_size, 8);
+        CxList *list = cxArrayListCreate(alloc, item_size, 8);
+        cxSetCompareFunc(list, cx_cmp_int);
 
         char *obj = malloc(item_size);
         for (char c = 'a' ; c <= 'z' ; c++) {
@@ -2643,6 +2662,7 @@
     const size_t len = 47; \
     int *testdata = int_test_data_added_to_list(list, isptrlist, len); \
     CxList *other = otherctr; \
+    cxSetCompareFunc(other, cx_cmp_int); \
     for (size_t i = 0; i < len; i++) cxListAdd(other, &testdata[i]); \
     CX_TEST_CALL_SUBROUTINE(test_list_verify_compare, list, other); \
     cxListFree(other); \
@@ -2650,25 +2670,26 @@
 })
 
 roll_out_compare_tests(
-        ll, cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int))
+        ll, cxLinkedListCreate(cxDefaultAllocator, sizeof(int))
 )
 
 roll_out_compare_tests(
-        pll, cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS)
+        pll, cxLinkedListCreate(cxDefaultAllocator, CX_STORE_POINTERS)
 )
 
 roll_out_compare_tests(
-        arl, cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int), 50)
+        arl, cxArrayListCreate(cxDefaultAllocator, sizeof(int), 50)
 )
 
 roll_out_compare_tests(
-        parl, cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS, 50)
+        parl, cxArrayListCreate(cxDefaultAllocator, CX_STORE_POINTERS, 50)
 )
 
 roll_out_test_combos_with_defaulted_funcs(compare_unoptimized, {
     const size_t len = 33;
     int *testdata = int_test_data_added_to_list(list, isptrlist, len);
-    CxList *other = cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int), 50);
+    CxList *other = cxArrayListCreate(cxDefaultAllocator, sizeof(int), 50);
+    cxSetCompareFunc(other, cx_cmp_int);
     do_set_default_class_funcs(other);
     for (size_t i = 0; i < len; i++) cxListAdd(other, &testdata[i]);
     CX_TEST_CALL_SUBROUTINE(test_list_verify_compare, list, other);
@@ -2738,7 +2759,7 @@
 roll_out_test_combos(simple_destr, {
     const size_t len = 60;
     int *testdata = int_test_data_added_to_list(list, isptrlist, len);
-    cxDefineDestructor(list, simple_destr_test_fun);
+    cxSetDestructor(list, simple_destr_test_fun);
     CX_TEST_CALL_SUBROUTINE(test_list_verify_destructor, list, testdata, len);
     free(testdata);
 })
@@ -2746,7 +2767,7 @@
 roll_out_test_combos(advanced_destr, {
     const size_t len = 75;
     int *testdata = int_test_data_added_to_list(list, isptrlist, len);
-    cxDefineAdvancedDestructor(list, advanced_destr_test_fun, NULL);
+    cxSetAdvancedDestructor(list, advanced_destr_test_fun, NULL);
     CX_TEST_CALL_SUBROUTINE(test_list_verify_destructor, list, testdata, len);
     free(testdata);
 })
@@ -2806,7 +2827,7 @@
 
     // register a destructor for the target list if it is storing pointers
     if (target_isptrlist) {
-        cxDefineAdvancedDestructor(target, cxFree, testing_alloc);
+        cxSetAdvancedDestructor(target, cxFree, testing_alloc);
     }
 
     // fill the source list
@@ -2853,7 +2874,7 @@
 
     // register a destructor for the target list if it is storing pointers
     if (target_isptrlist) {
-        cxDefineAdvancedDestructor(target, cxFree, testing_alloc);
+        cxSetAdvancedDestructor(target, cxFree, testing_alloc);
     }
 
     // fill the source list
@@ -2896,42 +2917,50 @@
 }
 
 roll_out_test_combos(clone_into_arl, {
-    CxList *target = cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int), 8);
+    CxList *target = cxArrayListCreate(cxDefaultAllocator, sizeof(int), 8);
+    cxSetCompareFunc(target, cx_cmp_int);
     CX_TEST_CALL_SUBROUTINE(verify_clone, target, list, false);
 })
 
 roll_out_test_combos(clone_into_ll, {
-    CxList *target = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int));
+    CxList *target = cxLinkedListCreate(cxDefaultAllocator, sizeof(int));
+    cxSetCompareFunc(target, cx_cmp_int);
     CX_TEST_CALL_SUBROUTINE(verify_clone, target, list, false);
 })
 
 roll_out_test_combos(clone_into_parl, {
-    CxList *target = cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS, 8);
+    CxList *target = cxArrayListCreate(cxDefaultAllocator, CX_STORE_POINTERS, 8);
+    cxSetCompareFunc(target, cx_cmp_int);
     CX_TEST_CALL_SUBROUTINE(verify_clone, target, list, true);
 })
 
 roll_out_test_combos(clone_into_pll, {
-    CxList *target = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS);
+    CxList *target = cxLinkedListCreate(cxDefaultAllocator, CX_STORE_POINTERS);
+    cxSetCompareFunc(target, cx_cmp_int);
     CX_TEST_CALL_SUBROUTINE(verify_clone, target, list, true);
 })
 
 roll_out_test_combos(clone_alloc_fail_into_arl, {
-    CxList *target = cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int), 8);
+    CxList *target = cxArrayListCreate(cxDefaultAllocator, sizeof(int), 8);
+    cxSetCompareFunc(target, cx_cmp_int);
     CX_TEST_CALL_SUBROUTINE(verify_clone_alloc_fail, target, list, false);
 })
 
 roll_out_test_combos(clone_alloc_fail_into_ll, {
-    CxList *target = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int));
+    CxList *target = cxLinkedListCreate(cxDefaultAllocator,  sizeof(int));
+    cxSetCompareFunc(target, cx_cmp_int);
     CX_TEST_CALL_SUBROUTINE(verify_clone_alloc_fail, target, list, false);
 })
 
 roll_out_test_combos(clone_alloc_fail_into_parl, {
-    CxList *target = cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS, 8);
+    CxList *target = cxArrayListCreate(cxDefaultAllocator,  CX_STORE_POINTERS, 8);
+    cxSetCompareFunc(target, cx_cmp_int);
     CX_TEST_CALL_SUBROUTINE(verify_clone_alloc_fail, target, list, true);
 })
 
 roll_out_test_combos(clone_alloc_fail_into_pll, {
-    CxList *target = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS);
+    CxList *target = cxLinkedListCreate(cxDefaultAllocator, CX_STORE_POINTERS);
+    cxSetCompareFunc(target, cx_cmp_int);
     CX_TEST_CALL_SUBROUTINE(verify_clone_alloc_fail, target, list, true);
 })
 
@@ -2939,10 +2968,13 @@
     CxTestingAllocator talloc;
     cx_testing_allocator_init(&talloc);
 
-    CxList *dst = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS);
-    cxDefineAdvancedDestructor(dst, cxFree, &talloc);
-    CxList *minuend = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int));
-    CxList *subtrahend = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int));
+    CxList *dst = cxLinkedListCreate(cxDefaultAllocator, CX_STORE_POINTERS);
+    cxSetAdvancedDestructor(dst, cxFree, &talloc);
+    CxList *minuend = cxLinkedListCreate(cxDefaultAllocator, sizeof(int));
+    CxList *subtrahend = cxLinkedListCreate(cxDefaultAllocator, sizeof(int));
+    cxSetCompareFunc(dst, cx_cmp_int);
+    cxSetCompareFunc(minuend, cx_cmp_int);
+    cxSetCompareFunc(subtrahend, cx_cmp_int);
 
     int dst_data[] = {47, 178, 176, 83};
     int minuend_data[] = {
@@ -2985,7 +3017,8 @@
         test_clone_func_max_clones = 30;
         expected_len = 34;
     }
-    CxList *expected = cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int), expected_len);
+    CxList *expected = cxArrayListCreate(cxDefaultAllocator, sizeof(int), expected_len);
+    cxSetCompareFunc(expected, cx_cmp_int);
     cxListAddArray(expected, sorted ? expected_sorted : expected_unsorted, expected_len);
 
     int result = cxListDifference(dst, minuend, subtrahend, test_clone_func, &talloc.base, NULL);
@@ -3034,10 +3067,13 @@
     CxTestingAllocator talloc;
     cx_testing_allocator_init(&talloc);
 
-    CxList *dst = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS);
-    cxDefineAdvancedDestructor(dst, cxFree, &talloc);
-    CxList *src = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int));
-    CxList *other = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int));
+    CxList *dst = cxLinkedListCreate(cxDefaultAllocator, CX_STORE_POINTERS);
+    cxSetAdvancedDestructor(dst, cxFree, &talloc);
+    CxList *src = cxLinkedListCreate(cxDefaultAllocator, sizeof(int));
+    CxList *other = cxLinkedListCreate(cxDefaultAllocator, sizeof(int));
+    cxSetCompareFunc(dst, cx_cmp_int);
+    cxSetCompareFunc(src, cx_cmp_int);
+    cxSetCompareFunc(other, cx_cmp_int);
 
     int dst_data[] = {47, 178, 176, 83};
     int src_data[] = {
@@ -3078,7 +3114,8 @@
         test_clone_func_max_clones = 10;
         expected_len = 14;
     }
-    CxList *expected = cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int), expected_len);
+    CxList *expected = cxArrayListCreate(cxDefaultAllocator, sizeof(int), expected_len);
+    cxSetCompareFunc(expected, cx_cmp_int);
     cxListAddArray(expected, sorted ? expected_sorted : expected_unsorted, expected_len);
 
     int result = cxListIntersection(dst, src, other, test_clone_func, &talloc.base, NULL);
@@ -3127,10 +3164,13 @@
     CxTestingAllocator talloc;
     cx_testing_allocator_init(&talloc);
 
-    CxList *dst = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS);
-    cxDefineAdvancedDestructor(dst, cxFree, &talloc);
-    CxList *src = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int));
-    CxList *other = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int));
+    CxList *dst = cxLinkedListCreate(cxDefaultAllocator, CX_STORE_POINTERS);
+    cxSetCompareFunc(dst, cx_cmp_int);
+    cxSetAdvancedDestructor(dst, cxFree, &talloc);
+    CxList *src = cxLinkedListCreate(cxDefaultAllocator, sizeof(int));
+    CxList *other = cxLinkedListCreate(cxDefaultAllocator, sizeof(int));
+    cxSetCompareFunc(src, cx_cmp_int);
+    cxSetCompareFunc(other, cx_cmp_int);
 
     int dst_data[] = {47, 178, 176, 83};
     int src_data[] = {
@@ -3183,7 +3223,8 @@
         test_clone_func_max_clones = 66;
         expected_len = 70;
     }
-    CxList *expected = cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int), expected_len);
+    CxList *expected = cxArrayListCreate(cxDefaultAllocator, sizeof(int), expected_len);
+    cxSetCompareFunc(expected, cx_cmp_int);
     cxListAddArray(expected, sorted ? expected_sorted : expected_unsorted, expected_len);
 
     int result = cxListUnion(dst, src, other, test_clone_func, &talloc.base, NULL);
@@ -3235,23 +3276,23 @@
     int c[] = {2, 4, 6, 8, 10, 12};
     int d[] = {4, 8, 12};
 
-    CxList *la = cxArrayListCreateSimple(sizeof(int), 8);
-    cxCollectionCompareFunc(la, cx_cmp_int);
+    CxList *la = cxArrayListCreate(NULL, sizeof(int), 8);
+    cxSetCompareFunc(la, cx_cmp_int);
     cxListInsertSortedArray(la, a, cx_nmemb(a));
-    CxList *lb = cxArrayListCreateSimple(sizeof(int), 8);
-    cxCollectionCompareFunc(lb, cx_cmp_int);
+    CxList *lb = cxArrayListCreate(NULL, sizeof(int), 8);
+    cxSetCompareFunc(lb, cx_cmp_int);
     cxListInsertSortedArray(lb, b, cx_nmemb(b));
-    CxList *lc = cxArrayListCreateSimple(sizeof(int), 8);
-    cxCollectionCompareFunc(lc, cx_cmp_int);
+    CxList *lc = cxArrayListCreate(NULL, sizeof(int), 8);
+    cxSetCompareFunc(lc, cx_cmp_int);
     cxListInsertSortedArray(lc, c, cx_nmemb(c));
-    CxList *ld = cxArrayListCreateSimple(sizeof(int), 8);
-    cxCollectionCompareFunc(ld, cx_cmp_int);
+    CxList *ld = cxArrayListCreate(NULL, sizeof(int), 8);
+    cxSetCompareFunc(ld, cx_cmp_int);
     cxListInsertSortedArray(ld, d, cx_nmemb(d));
 
-    CxList *d1 = cxArrayListCreateSimple(sizeof(int), 8);
-    cxCollectionCompareFunc(d1, cx_cmp_int);
-    CxList *d2 = cxArrayListCreateSimple(sizeof(int), 8);
-    cxCollectionCompareFunc(d2, cx_cmp_int);
+    CxList *d1 = cxArrayListCreate(NULL, sizeof(int), 8);
+    cxSetCompareFunc(d1, cx_cmp_int);
+    CxList *d2 = cxArrayListCreate(NULL, sizeof(int), 8);
+    cxSetCompareFunc(d2, cx_cmp_int);
 
     CX_TEST_DO {
         // clone a into d1
@@ -3262,7 +3303,7 @@
         // union of a (in d1) and b
         CX_TEST_ASSERT(0 == cxListUnionShallow(d2, d1, lb));
         CX_TEST_ASSERT(cxCollectionSorted(d2));
-        CxList *expected_union = cxArrayListCreateSimple(sizeof(int), 8);
+        CxList *expected_union = cxArrayListCreate(NULL, sizeof(int), 8);
         {
             int expected[] = {1, 2, 3, 5, 7, 8, 9, 10, 11};
             cxListAddArray(expected_union, expected, cx_nmemb(expected));
@@ -3274,7 +3315,7 @@
         cxListClear(d1);
         CX_TEST_ASSERT(0 == cxListIntersectionShallow(d1, d2, lc));
         CX_TEST_ASSERT(cxCollectionSorted(d1));
-        CxList *expected_intersection = cxArrayListCreateSimple(sizeof(int), 8);
+        CxList *expected_intersection = cxArrayListCreate(NULL, sizeof(int), 8);
         {
             int expected[] = {2, 8, 10};
             cxListAddArray(expected_intersection, expected, cx_nmemb(expected));
@@ -3286,7 +3327,7 @@
         cxListClear(d2);
         CX_TEST_ASSERT(0 == cxListDifferenceShallow(d2, d1, ld));
         CX_TEST_ASSERT(cxCollectionSorted(d2));
-        CxList *expected_difference = cxArrayListCreateSimple(sizeof(int), 8);
+        CxList *expected_difference = cxArrayListCreate(NULL, sizeof(int), 8);
         {
             int expected[] = {2, 10};
             cxListAddArray(expected_difference, expected, cx_nmemb(expected));
@@ -3304,7 +3345,8 @@
 }
 
 CX_TEST(test_list_pointer_list_supports_null) {
-    CxList *list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, CX_STORE_POINTERS);
+    CxList *list = cxLinkedListCreate(cxDefaultAllocator, CX_STORE_POINTERS);
+    cxSetCompareFunc(list, cx_cmp_int);
     int x = 47;
     int y = 11;
     int z = 1337;
@@ -3332,9 +3374,12 @@
 }
 
 CX_TEST(test_list_use_insert_unique_to_remove_duplicates) {
-    CxList *linked_list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int));
-    CxList *array_list = cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int), 8);
-    CxList *defaulted_list = cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int), 8);
+    CxList *linked_list = cxLinkedListCreate(cxDefaultAllocator, sizeof(int));
+    CxList *array_list = cxArrayListCreate(cxDefaultAllocator, sizeof(int), 8);
+    CxList *defaulted_list = cxArrayListCreate(cxDefaultAllocator, sizeof(int), 8);
+    cxSetCompareFunc(linked_list, cx_cmp_int);
+    cxSetCompareFunc(array_list, cx_cmp_int);
+    cxSetCompareFunc(defaulted_list, cx_cmp_int);
     do_set_default_class_funcs(defaulted_list);
     int test_array[23] = {
         120, -13, 100, -90, 13, -56, 74, 20, 28, 80, 18, -56, 130, 12, 15, 0, 39, 100, 0, 29, 28, 85, 20
@@ -3362,9 +3407,12 @@
 }
 
 CX_TEST(test_list_use_insert_unique_with_duplicates_in_source) {
-    CxList *linked_list = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int));
-    CxList *array_list = cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int), 8);
-    CxList *defaulted_list = cxArrayListCreate(cxDefaultAllocator, cx_cmp_int, sizeof(int), 8);
+    CxList *linked_list = cxLinkedListCreate(cxDefaultAllocator, sizeof(int));
+    CxList *array_list = cxArrayListCreate(cxDefaultAllocator, sizeof(int), 8);
+    CxList *defaulted_list = cxArrayListCreate(cxDefaultAllocator, sizeof(int), 8);
+    cxSetCompareFunc(linked_list, cx_cmp_int);
+    cxSetCompareFunc(array_list, cx_cmp_int);
+    cxSetCompareFunc(defaulted_list, cx_cmp_int);
     do_set_default_class_funcs(defaulted_list);
     int pre_filled[10] = {-13, 5, 18, 30, 40, 45, 50, 80, 85, 110};
     cxListInsertSortedArray(linked_list, pre_filled, 10);
--- a/tests/test_properties.c	Sun Dec 14 16:21:09 2025 +0100
+++ b/tests/test_properties.c	Sun Dec 14 17:30:17 2025 +0100
@@ -521,8 +521,8 @@
         // preparation of test file complete
 
         // we want to load the properties into a map of char* pointers
-        CxMap *map = cxHashMapCreateSimple(CX_STORE_POINTERS);
-        cxDefineAdvancedDestructor(map, cxFree, &talloc);
+        CxMap *map = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
+        cxSetAdvancedDestructor(map, cxFree, &talloc);
         CxPropertiesStatus status = cxPropertiesLoadDefault(&talloc.base, fname, map);
 
         CX_TEST_ASSERT(status == CX_PROPERTIES_NO_ERROR);
@@ -570,7 +570,7 @@
         fclose(f);
         f = NULL;
 
-        CxMap *map = cxHashMapCreateSimple(CX_STORE_POINTERS);
+        CxMap *map = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
         // store something that we don't want to be deleted
         cxMapPut(map, "test", "value");
         CxPropertiesStatus status = cxPropertiesLoadDefault(&talloc.base, fname, map);
@@ -601,7 +601,7 @@
         fclose(f);
         f = NULL;
 
-        CxMap *map = cxHashMapCreateSimple(CX_STORE_POINTERS);
+        CxMap *map = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
         CxPropertiesStatus status = cxPropertiesLoadDefault(&talloc.base, fname, map);
         CX_TEST_ASSERT(status == CX_PROPERTIES_NO_DATA);
         CX_TEST_ASSERT(cxMapSize(map) == 0);
@@ -627,8 +627,8 @@
         fclose(f);
         f = NULL;
 
-        CxMap *map = cxHashMapCreateSimple(CX_STORE_POINTERS);
-        cxDefineAdvancedDestructor(map, cxFree, &talloc);
+        CxMap *map = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
+        cxSetAdvancedDestructor(map, cxFree, &talloc);
         CxPropertiesStatus status = cxPropertiesLoadDefault(&talloc.base, fname, map);
         CX_TEST_ASSERT(status == CX_PROPERTIES_INVALID_EMPTY_KEY);
         // all keys that could be successfully parsed are added
@@ -647,7 +647,7 @@
 
 CX_TEST(test_properties_load_file_not_exists) {
     CX_TEST_DO {
-        CxMap *map = cxHashMapCreateSimple(CX_STORE_POINTERS);
+        CxMap *map = cxHashMapCreate(NULL, CX_STORE_POINTERS, 0);
         CxPropertiesStatus status = cxPropertiesLoadDefault(NULL, "does-definitely-not-exist", map);
         CX_TEST_ASSERT(status == CX_PROPERTIES_FILE_ERROR);
         cxMapFree(map);
@@ -666,8 +666,8 @@
         fclose(f);
         f = NULL;
 
-        CxMap *map = cxHashMapCreateSimple(sizeof(cxmutstr));
-        cxDefineAdvancedDestructor(map, cx_strfree_a, &talloc);
+        CxMap *map = cxHashMapCreate(NULL, sizeof(cxmutstr), 0);
+        cxSetAdvancedDestructor(map, cx_strfree_a, &talloc);
         CxPropertiesStatus status = cxPropertiesLoadDefault(&talloc.base, fname, map);
         CX_TEST_ASSERT(status == CX_PROPERTIES_NO_ERROR);
         CX_TEST_ASSERT(cxMapSize(map) == 2);
@@ -697,8 +697,8 @@
         fclose(f);
         f = NULL;
 
-        CxMap *map = cxHashMapCreateSimple(sizeof(CxBuffer));
-        cxDefineAdvancedDestructor(map, cxFree, &talloc);
+        CxMap *map = cxHashMapCreate(NULL, sizeof(CxBuffer), 0);
+        cxSetAdvancedDestructor(map, cxFree, &talloc);
         CxPropertiesStatus status = cxPropertiesLoadDefault(&talloc.base, fname, map);
         CX_TEST_ASSERT(status == CX_PROPERTIES_MAP_ERROR);
         CX_TEST_ASSERT(cxMapSize(map) == 0);
--- a/tests/test_tree.c	Sun Dec 14 16:21:09 2025 +0100
+++ b/tests/test_tree.c	Sun Dec 14 17:30:17 2025 +0100
@@ -2188,7 +2188,7 @@
         // for the subtree, we use a little trick and wrap it in a new tree
         CxTree *foo_tree = cxTreeCreateWrapped(alloc, foo, tree_node_file_layout);
         foo_tree->collection.allocator = alloc;
-        cxDefineAdvancedDestructor(foo_tree, cxFree, alloc);
+        cxSetAdvancedDestructor(foo_tree, cxFree, alloc);
         cxTreeFree(foo_tree);
         CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
     }
@@ -2306,7 +2306,7 @@
         cxTreeFree(tree);
         CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc));
         CxTree *w = cxTreeCreateWrapped(alloc, root, tree_node_file_layout);
-        cxDefineAdvancedDestructor(w, cxFree, alloc);
+        cxSetAdvancedDestructor(w, cxFree, alloc);
         cxTreeDestroySubtree(w, w->root);
         CX_TEST_ASSERT(!cx_testing_allocator_verify(&talloc));
         cxTreeFree(w);
@@ -2326,7 +2326,7 @@
     cx_tree_link(&child1, &child3, tree_node_layout);
     CX_TEST_DO {
         CxTree *tree = cxTreeCreateWrapped(cxDefaultAllocator, &root, tree_node_layout);
-        cxDefineDestructor(tree,test_tree_high_simple_destructor_func);
+        cxSetDestructor(tree,test_tree_high_simple_destructor_func);
         cxTreeDestroyNode(tree, &child1, NULL);
         cxTreeFree(tree);
         CX_TEST_ASSERT(root.data == 1);

mercurial