--- a/src/cx/collection.h Tue Dec 16 21:33:58 2025 +0100 +++ b/src/cx/collection.h Wed Dec 17 19:05:50 2025 +0100 @@ -58,10 +58,6 @@ */ const CxAllocator *allocator; /** - * The comparator function for the elements. - */ - cx_compare_func cmpfunc; - /** * The size of each element. */ size_t elem_size; @@ -70,6 +66,19 @@ */ size_t size; /** + * A two-argument comparator function for the elements. + */ + cx_compare_func simple_cmp; + /** + * A three-argument comparator function for the elements. + * If specified, this function has precedence over the @c simple_cmp function. + */ + cx_compare_func2 advanced_cmp; + /** + * A pointer to custom data for the @c advanced_cmp function + */ + void *cmp_data; + /** * An optional simple destructor for the collection's elements. * * @attention Read the documentation of the particular collection implementation @@ -139,6 +148,25 @@ */ #define cxCollectionStoresPointers(c) ((c)->collection.store_pointer) + +/** + * Convenience macro for adding indirection to an element if the collection is storing pointers. + * + * @param c a pointer to a struct that contains #CX_COLLECTION_BASE + * @param elem the pointer that shall be taken the address from, if the collection is storing pointers + * @return if the collection is storing pointers, takes the address of @p elem, otherwise returns @p elem + */ +#define cx_ref(c, elem) (cxCollectionStoresPointers(c) ? ((void*)&(elem)) : (elem)) + +/** + * Convenience macro for dereferencing an element if the collection is storing pointers. + * + * @param c a pointer to a struct that contains #CX_COLLECTION_BASE + * @param elem a pointer to the collection element + * @return if the collection is storing pointers, dereferences @p elem, otherwise returns @p elem + */ +#define cx_deref(c, elem) (cxCollectionStoresPointers(c) ? *((void**)(elem)) : (elem)) + /** * Indicates whether the collection can guarantee that the stored elements are currently sorted. * @@ -154,27 +182,87 @@ #define cxCollectionSorted(c) ((c)->collection.sorted || (c)->collection.size == 0) /** - * Sets the compare function for a collection. + * Sets a simple compare function for a collection. + * + * Erases a possible advanced compare function. + * If you want to set both, because you want to access the simple function + * in your advanced function, you must set the simple function first. + * + * @param c a pointer to a struct that contains #CX_COLLECTION_BASE + * @param func (@c cx_compare_func) the compare function + */ +#define cxSetCompareFunc(c, func) \ + (c)->collection.simple_cmp = (cx_compare_func)(func); \ + (c)->collection.advanced_cmp = NULL + +/** + * Sets an advanced compare function that supports custom data for a collection. + * + * @param c a pointer to a struct that contains #CX_COLLECTION_BASE + * @param func (@c cx_compare_func2) the compare function + * @param data (@c void*) the pointer to custom data that is passed to the compare function + */ +#define cxSetAdvancedCompareFunc(c, func, data) \ + (c)->collection.advanced_cmp = (cx_compare_func2) func; \ + (c)->collection.destructor_data = data + +/** + * Invokes the simple comparator function for two elements. + * + * Usually only used by collection implementations. There should be no need + * to invoke this macro manually. * * @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 + * @param left (@c void*) pointer to data + * @param right (@c void*) pointer to data + */ +#define cx_invoke_simple_compare_func(c, left, right) \ + (c)->collection.simple_cmp(left, right) + +/** + * Invokes the advanced comparator function for two elements. + * + * Usually only used by collection implementations. There should be no need + * to invoke this macro manually. + * + * @param c a pointer to a struct that contains #CX_COLLECTION_BASE + * @param left (@c void*) pointer to data + * @param right (@c void*) pointer to data */ -#define cxSetCompareFunc(c, func) (c)->collection.cmpfunc = (cx_compare_func)(func) +#define cx_invoke_advanced_compare_func(c, left, right) \ + (c)->collection.advanced_cmp(left, right, (c)->collection.cmp_data) + + +/** + * Invokes the configured comparator function for two elements. + * + * Usually only used by collection implementations. There should be no need + * to invoke this macro manually. + * + * @param c a pointer to a struct that contains #CX_COLLECTION_BASE + * @param left (@c void*) pointer to data + * @param right (@c void*) pointer to data + */ +#define cx_invoke_compare_func(c, left, right) \ + (((c)->collection.advanced_cmp) ? \ + cx_invoke_advanced_compare_func(c,left,right) : \ + cx_invoke_simple_compare_func(c,left,right)) /** * Sets a simple destructor function for this collection. * * @param c a pointer to a struct that contains #CX_COLLECTION_BASE - * @param destr the destructor function + * @param destr (@c cx_destructor_func) the destructor function */ #define cxSetDestructor(c, destr) \ (c)->collection.simple_destructor = (cx_destructor_func) destr /** - * Sets a simple destructor function for this collection. + * Sets an advanced destructor function for this collection. * * @param c a pointer to a struct that contains #CX_COLLECTION_BASE - * @param destr the destructor function + * @param destr (@c cx_destructor_func2) the destructor function + * @param data (@c void*) the additional data the advanced destructor is invoked with */ #define cxSetAdvancedDestructor(c, destr, data) \ (c)->collection.advanced_destructor = (cx_destructor_func2) destr; \