# HG changeset patch # User Mike Becker # Date 1736202581 -3600 # Node ID 78eeeb95088308e20355463342a88f9a0ad6973a # Parent a0e9be7ed131101583bd94e833f8323131d7a5a3 remove API for changing the store_pointer property after list creation fixes #553 diff -r a0e9be7ed131 -r 78eeeb950883 CHANGELOG --- a/CHANGELOG Sun Jan 05 18:19:42 2025 +0100 +++ b/CHANGELOG Mon Jan 06 23:29:41 2025 +0100 @@ -32,6 +32,7 @@ * removes utils.h * removes flag_removal function from iterator * removes cxMapDetach() and makes cxMapRemoveAndGet() compatible with both map variants + * removes the API for changing the store_pointer property of collections after their creation * removes CMake * removes GTest dependency * removes flags to disable SBO in tests diff -r a0e9be7ed131 -r 78eeeb950883 src/array_list.c --- a/src/array_list.c Sun Jan 05 18:19:42 2025 +0100 +++ b/src/array_list.c Mon Jan 06 23:29:41 2025 +0100 @@ -1013,22 +1013,13 @@ cx_array_list *list = cxCalloc(allocator, 1, sizeof(cx_array_list)); if (list == NULL) return NULL; - - list->base.cl = &cx_array_list_class; - list->base.collection.allocator = allocator; + cx_list_init((CxList*)list, &cx_array_list_class, + allocator, comparator, elem_size); list->capacity = initial_capacity; - if (elem_size > 0) { - list->base.collection.elem_size = elem_size; - list->base.collection.cmpfunc = comparator; - } else { - elem_size = sizeof(void *); - list->base.collection.cmpfunc = comparator == NULL ? cx_cmp_ptr : comparator; - cxListStorePointers((CxList *) list); - } - // allocate the array after the real elem_size is known - list->data = cxCalloc(allocator, initial_capacity, elem_size); + list->data = cxCalloc(allocator, initial_capacity, + list->base.collection.elem_size); if (list->data == NULL) { // LCOV_EXCL_START cxFree(allocator, list); return NULL; diff -r a0e9be7ed131 -r 78eeeb950883 src/cx/array_list.h --- a/src/cx/array_list.h Sun Jan 05 18:19:42 2025 +0100 +++ b/src/cx/array_list.h Mon Jan 06 23:29:41 2025 +0100 @@ -684,9 +684,9 @@ /** * Allocates an array list for storing elements with @p elem_size bytes each. * - * If @p elem_size is CX_STORE_POINTERS, the created list will be created as if - * cxListStorePointers() was called immediately after creation and the compare - * function will be automatically set to cx_cmp_ptr(), if none is given. + * 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. * * @param allocator the allocator for allocating the list memory * (if @c NULL, a default stdlib allocator will be used) @@ -714,9 +714,9 @@ * 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 will be created as if - * cxListStorePointers() was called immediately after creation and the compare - * function will be automatically set to cx_cmp_ptr(). + * 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. * * @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 diff -r a0e9be7ed131 -r 78eeeb950883 src/cx/hash_map.h --- a/src/cx/hash_map.h Sun Jan 05 18:19:42 2025 +0100 +++ b/src/cx/hash_map.h Mon Jan 06 23:29:41 2025 +0100 @@ -69,8 +69,8 @@ * * If @p buckets is zero, an implementation defined default will be used. * - * If @p elem_size is CX_STORE_POINTERS, the created map will be created as if - * cxMapStorePointers() was called immediately after creation. + * 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 removal. @@ -94,8 +94,8 @@ /** * Creates a new hash map with a default number of buckets. * - * If @p elem_size is CX_STORE_POINTERS, the created map will be created as if - * cxMapStorePointers() was called immediately after creation. + * 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 removal. diff -r a0e9be7ed131 -r 78eeeb950883 src/cx/linked_list.h --- a/src/cx/linked_list.h Sun Jan 05 18:19:42 2025 +0100 +++ b/src/cx/linked_list.h Mon Jan 06 23:29:41 2025 +0100 @@ -52,9 +52,9 @@ /** * Allocates a linked list for storing elements with @p elem_size bytes each. * - * If @p elem_size is CX_STORE_POINTERS, the created list will be created as if - * cxListStorePointers() was called immediately after creation and the compare - * function will be automatically set to cx_cmp_ptr(), if none is given. + * 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. * * @param allocator the allocator for allocating the list nodes * (if @c NULL, a default stdlib allocator will be used) @@ -80,9 +80,9 @@ * 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 will be created as if - * cxListStorePointers() was called immediately after creation and the compare - * function will be automatically set to cx_cmp_ptr(). + * 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. * * @param elem_size (@c size_t) the size of each element in bytes * @return (@c CxList*) the created list diff -r a0e9be7ed131 -r 78eeeb950883 src/cx/list.h --- a/src/cx/list.h Sun Jan 05 18:19:42 2025 +0100 +++ b/src/cx/list.h Mon Jan 06 23:29:41 2025 +0100 @@ -280,50 +280,64 @@ int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j); /** + * Initializes a list struct. + * + * Only use this function if you are creating your own list implementation. + * The purpose of this function is to be called in the initialization code + * of your list, to set certain members correctly. + * + * This is particularly important when you want your list to support + * #CX_STORE_POINTERS as @p elem_size. This function will wrap the list + * class accordingly and make sure that you can implement your list as if + * it was only storing objects and the wrapper will automatically enable + * the feature of storing pointers. + * + * @par Example + * + * @code + * CxList *myCustomListCreate( + * const CxAllocator *allocator, + * cx_compare_func comparator, + * size_t elem_size + * ) { + * if (allocator == NULL) { + * allocator = cxDefaultAllocator; + * } + * + * MyCustomList *list = cxCalloc(allocator, 1, sizeof(MyCustomList)); + * if (list == NULL) return NULL; + * + * // initialize + * cx_list_init((CxList*)list, &my_custom_list_class, + * allocator, comparator, elem_size); + * + * // ... some more custom stuff ... + * + * return (CxList *) list; + * } + * @endcode + * + * @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) +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 +); + +/** * Common type for all list implementations. */ typedef struct cx_list_s CxList; /** - * Advises the list to store copies of the objects (default mode of operation). - * - * Retrieving objects from this list will yield pointers to the copies stored - * within this list. - * - * @param list the list - * @see cxListStorePointers() - */ -cx_attr_nonnull -void cxListStoreObjects(CxList *list); - -/** - * Advises the list to only store pointers to the objects. - * - * Retrieving objects from this list will yield the original pointers stored. - * - * @note This function forcibly sets the element size to the size of a pointer. - * Invoking this function on a non-empty list that already stores copies of - * objects is undefined. - * - * @param list the list - * @see cxListStoreObjects() - */ -cx_attr_nonnull -void cxListStorePointers(CxList *list); - -/** - * Returns true, if this list is storing pointers instead of the actual data. - * - * @param list - * @return true, if this list is storing pointers - * @see cxListStorePointers() - */ -cx_attr_nonnull -static inline bool cxListIsStoringPointers(const CxList *list) { - return list->collection.store_pointer; -} - -/** * Returns the number of elements currently stored in the list. * * @param list the list diff -r a0e9be7ed131 -r 78eeeb950883 src/cx/map.h --- a/src/cx/map.h Sun Jan 05 18:19:42 2025 +0100 +++ b/src/cx/map.h Mon Jan 06 23:29:41 2025 +0100 @@ -160,50 +160,6 @@ 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 - * within this list. - * - * @param map the map - * @see cxMapStorePointers() - */ -cx_attr_nonnull -static inline void cxMapStoreObjects(CxMap *map) { - map->collection.store_pointer = false; -} - -/** - * Advises the map to only store pointers to the objects. - * - * Retrieving objects from this list will yield the original pointers stored. - * - * @note This function forcibly sets the element size to the size of a pointer. - * Invoking this function on a non-empty map that already stores copies of - * objects is undefined. - * - * @param map the map - * @see cxMapStoreObjects() - */ -cx_attr_nonnull -static inline void cxMapStorePointers(CxMap *map) { - map->collection.store_pointer = true; - map->collection.elem_size = sizeof(void *); -} - -/** - * Returns true, if this map is storing pointers instead of the actual data. - * - * @param map - * @return true, if this map is storing pointers - * @see cxMapStorePointers() - */ -cx_attr_nonnull -static inline bool cxMapIsStoringPointers(const CxMap *map) { - return map->collection.store_pointer; -} - -/** * Deallocates the memory of the specified map. * * Also calls the content destructor functions for each element, if specified. @@ -761,8 +717,7 @@ * @param targetbuf (@c void*) the buffer where the element shall be copied to * @retval zero success * @retval non-zero the key was not found - * - * @see cxMapStorePointers() + * * @see cxMapRemove() */ #define cxMapRemoveAndGet(map, key, targetbuf) _Generic((key), \ diff -r a0e9be7ed131 -r 78eeeb950883 src/hash_map.c --- a/src/hash_map.c Sun Jan 05 18:19:42 2025 +0100 +++ b/src/hash_map.c Mon Jan 06 23:29:41 2025 +0100 @@ -433,11 +433,10 @@ map->base.collection.allocator = allocator; if (itemsize > 0) { - map->base.collection.store_pointer = false; map->base.collection.elem_size = itemsize; } else { + map->base.collection.elem_size = sizeof(void *); map->base.collection.store_pointer = true; - map->base.collection.elem_size = sizeof(void *); } return (CxMap *) map; diff -r a0e9be7ed131 -r 78eeeb950883 src/linked_list.c --- a/src/linked_list.c Sun Jan 05 18:19:42 2025 +0100 +++ b/src/linked_list.c Mon Jan 06 23:29:41 2025 +0100 @@ -1138,17 +1138,8 @@ cx_linked_list *list = cxCalloc(allocator, 1, sizeof(cx_linked_list)); if (list == NULL) return NULL; - - list->base.cl = &cx_linked_list_class; - list->base.collection.allocator = allocator; - - if (elem_size > 0) { - list->base.collection.elem_size = elem_size; - list->base.collection.cmpfunc = comparator; - } else { - list->base.collection.cmpfunc = comparator == NULL ? cx_cmp_ptr : comparator; - cxListStorePointers((CxList *) list); - } + cx_list_init((CxList*)list, &cx_linked_list_class, + allocator, comparator, elem_size); return (CxList *) list; } diff -r a0e9be7ed131 -r 78eeeb950883 src/list.c --- a/src/list.c Sun Jan 05 18:19:42 2025 +0100 +++ b/src/list.c Mon Jan 06 23:29:41 2025 +0100 @@ -192,22 +192,6 @@ cx_pl_reverse, cx_pl_iterator, }; - -void cxListStoreObjects(CxList *list) { - list->collection.store_pointer = false; - if (list->climpl != NULL) { - list->cl = list->climpl; - list->climpl = NULL; - } -} - -void cxListStorePointers(CxList *list) { - list->collection.elem_size = sizeof(void *); - list->collection.store_pointer = true; - list->climpl = list->cl; - list->cl = &cx_pointer_list_class; -} - // // @@ -417,6 +401,29 @@ return 0; } +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 +) { + list->cl = cl; + list->collection.allocator = allocator; + list->collection.cmpfunc = comparator; + if (elem_size > 0) { + list->collection.elem_size = elem_size; + } else { + list->collection.elem_size = sizeof(void *); + if (list->collection.cmpfunc == NULL) { + list->collection.cmpfunc = cx_cmp_ptr; + } + list->collection.store_pointer = true; + list->climpl = list->cl; + list->cl = &cx_pointer_list_class; + } +} + int cxListCompare( const CxList *list, const CxList *other diff -r a0e9be7ed131 -r 78eeeb950883 tests/test_hash_map.c --- a/tests/test_hash_map.c Sun Jan 05 18:19:42 2025 +0100 +++ b/tests/test_hash_map.c Mon Jan 06 23:29:41 2025 +0100 @@ -50,11 +50,6 @@ CX_TEST_ASSERT(map->collection.simple_destructor == NULL); CX_TEST_ASSERT(map->collection.advanced_destructor == NULL); CX_TEST_ASSERT(map->collection.destructor_data == NULL); - cxMapStorePointers(map); - CX_TEST_ASSERT(map->collection.store_pointer); - CX_TEST_ASSERT(map->collection.elem_size == sizeof(void *)); - cxMapStoreObjects(map); - CX_TEST_ASSERT(!map->collection.store_pointer); cxMapFree(map); CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); diff -r a0e9be7ed131 -r 78eeeb950883 tests/test_list.c --- a/tests/test_list.c Sun Jan 05 18:19:42 2025 +0100 +++ b/tests/test_list.c Mon Jan 06 23:29:41 2025 +0100 @@ -1010,7 +1010,7 @@ CX_TEST_ASSERT(cxListSize(list) == 0); CX_TEST_ASSERT(list->collection.allocator == alloc); CX_TEST_ASSERT(list->collection.cmpfunc == cx_cmp_int); - CX_TEST_ASSERT(!cxListIsStoringPointers(list)); + CX_TEST_ASSERT(!list->collection.store_pointer); cxListFree(list); CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); } @@ -1028,24 +1028,7 @@ CX_TEST_ASSERT(cxListSize(list) == 0); CX_TEST_ASSERT(list->collection.allocator == cxDefaultAllocator); CX_TEST_ASSERT(list->collection.cmpfunc == NULL); - CX_TEST_ASSERT(!cxListIsStoringPointers(list)); - } - cxListFree(list); -} - -CX_TEST(test_list_ll_store_pointers) { - CxList *list = cxLinkedListCreateSimple(47); - CX_TEST_DO { - CX_TEST_ASSERT(!cxListIsStoringPointers(list)); - cxListStorePointers(list); - CX_TEST_ASSERT(list->collection.elem_size == sizeof(void *)); - CX_TEST_ASSERT(list->cl != NULL); - CX_TEST_ASSERT(list->climpl != NULL); - CX_TEST_ASSERT(cxListIsStoringPointers(list)); - cxListStoreObjects(list); - CX_TEST_ASSERT(list->cl != NULL); - CX_TEST_ASSERT(list->climpl == NULL); - CX_TEST_ASSERT(!cxListIsStoringPointers(list)); + CX_TEST_ASSERT(!list->collection.store_pointer); } cxListFree(list); } @@ -1061,7 +1044,7 @@ CX_TEST_ASSERT(cxListSize(list) == 0); CX_TEST_ASSERT(list->collection.allocator == cxDefaultAllocator); CX_TEST_ASSERT(list->collection.cmpfunc == cx_cmp_ptr); - CX_TEST_ASSERT(cxListIsStoringPointers(list)); + CX_TEST_ASSERT(list->collection.store_pointer); } cxListFree(list); } @@ -1080,7 +1063,7 @@ CX_TEST_ASSERT(cxListSize(list) == 0); CX_TEST_ASSERT(list->collection.allocator == alloc); CX_TEST_ASSERT(list->collection.cmpfunc == cx_cmp_int); - CX_TEST_ASSERT(!cxListIsStoringPointers(list)); + CX_TEST_ASSERT(!list->collection.store_pointer); cxListFree(list); CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc)); } @@ -1098,7 +1081,7 @@ CX_TEST_ASSERT(cxListSize(list) == 0); CX_TEST_ASSERT(list->collection.allocator == cxDefaultAllocator); CX_TEST_ASSERT(list->collection.cmpfunc == NULL); - CX_TEST_ASSERT(!cxListIsStoringPointers(list)); + CX_TEST_ASSERT(!list->collection.store_pointer); } cxListFree(list); } @@ -1114,7 +1097,7 @@ CX_TEST_ASSERT(cxListSize(list) == 0); CX_TEST_ASSERT(list->collection.allocator == cxDefaultAllocator); CX_TEST_ASSERT(list->collection.cmpfunc == cx_cmp_ptr); - CX_TEST_ASSERT(cxListIsStoringPointers(list)); + CX_TEST_ASSERT(list->collection.store_pointer); } cxListFree(list); } @@ -1862,7 +1845,7 @@ const int *testdata, size_t testdata_len) { destr_test_ctr = 0; - int off = cxListIsStoringPointers(list) ? 1 : 0; + int off = list->collection.store_pointer ? 1 : 0; cxListRemove(list, 15); CX_TEST_ASSERT(1 == destr_test_ctr); @@ -2025,7 +2008,6 @@ cx_test_register(suite, test_list_ll_create); cx_test_register(suite, test_list_ll_create_simple); - cx_test_register(suite, test_list_ll_store_pointers); cx_test_register(suite, test_list_ll_create_simple_for_pointers); cx_test_register(suite, test_list_pll_destroy_no_destr); cx_test_register(suite, test_list_pll_destroy_simple_destr);