--- a/src/ucx/cx/collection.h Mon Feb 10 17:44:51 2025 +0100 +++ b/src/ucx/cx/collection.h Sun Mar 02 18:10:52 2025 +0100 @@ -26,12 +26,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ /** - * \file collection.h - * \brief Common definitions for various collection implementations. - * \author Mike Becker - * \author Olaf Wintermann - * \version 3.0 - * \copyright 2-Clause BSD License + * @file collection.h + * @brief Common definitions for various collection implementations. + * @author Mike Becker + * @author Olaf Wintermann + * @copyright 2-Clause BSD License */ #ifndef UCX_COLLECTION_H @@ -39,6 +38,7 @@ #include "allocator.h" #include "iterator.h" +#include "compare.h" #ifdef __cplusplus extern "C" { @@ -50,56 +50,125 @@ #define CX_STORE_POINTERS 0 /** - * A comparator function comparing two collection elements. + * Base attributes of a collection. */ -typedef int(*cx_compare_func)( - void const *left, - void const *right -); +struct cx_collection_s { + /** + * The allocator to use. + */ + const CxAllocator *allocator; + /** + * The comparator function for the elements. + */ + cx_compare_func cmpfunc; + /** + * The size of each element. + */ + size_t elem_size; + /** + * The number of currently stored elements. + */ + size_t size; + /** + * An optional simple destructor for the collection's elements. + * + * @attention Read the documentation of the particular collection implementation + * whether this destructor shall only destroy the contents or also free the memory. + */ + cx_destructor_func simple_destructor; + /** + * An optional advanced destructor for the collection's elements. + * + * @attention Read the documentation of the particular collection implementation + * whether this destructor shall only destroy the contents or also free the memory. + */ + cx_destructor_func2 advanced_destructor; + /** + * The pointer to additional data that is passed to the advanced destructor. + */ + void *destructor_data; + /** + * Indicates if this list is supposed to store pointers + * instead of copies of the actual objects. + */ + bool store_pointer; + /** + * Indicates if this collection is guaranteed to be sorted. + * Note that the elements can still be sorted, even when the collection is not aware of that. + */ + bool sorted; +}; /** * Use this macro to declare common members for a collection structure. + * + * @par Example Use + * @code + * struct MyCustomSet { + * CX_COLLECTION_BASE; + * MySetElements *data; + * } + * @endcode */ -#define CX_COLLECTION_MEMBERS \ - /** \ - * The allocator to use. \ - */ \ - CxAllocator const *allocator; \ - /** \ - * The comparator function for the elements. \ - */ \ - cx_compare_func cmpfunc; \ - /** \ - * The size of each element. \ - */ \ - size_t item_size; \ - /** \ - * The number of currently stored elements. \ - */ \ - size_t size; \ - /** \ - * An optional simple destructor for the collection's elements. \ - * \ - * @attention Read the documentation of the particular collection implementation \ - * whether this destructor shall only destroy the contents or also free the memory. \ - */ \ - cx_destructor_func simple_destructor; \ - /** \ - * An optional advanced destructor for the collection's elements. \ - * \ - * @attention Read the documentation of the particular collection implementation \ - * whether this destructor shall only destroy the contents or also free the memory. \ - */ \ - cx_destructor_func2 advanced_destructor; \ - /** \ - * The pointer to additional data that is passed to the advanced destructor. \ - */ \ - void *destructor_data; \ - /** \ - * Indicates if this instance of a collection is supposed to store pointers \ - * instead of copies of the actual objects. \ - */ \ - bool store_pointer; +#define CX_COLLECTION_BASE struct cx_collection_s collection + +/** + * Returns the number of elements currently stored. + * + * @param c a pointer to a struct that contains #CX_COLLECTION_BASE + * @return (@c size_t) the number of currently stored elements + */ +#define cxCollectionSize(c) ((c)->collection.size) + +/** + * Returns the size of one element. + * + * If #cxCollectionStoresPointers() returns true, this is the size of a pointer. + * + * @param c a pointer to a struct that contains #CX_COLLECTION_BASE + * @return (@c size_t) the size of one element in bytes + */ +#define cxCollectionElementSize(c) ((c)->collection.elem_size) + +/** + * Indicates whether this collection only stores pointers instead of the actual data. + * + * @param c a pointer to a struct that contains #CX_COLLECTION_BASE + * @retval true if this collection stores only pointers to data + * @retval false if this collection stores the actual element's data + */ +#define cxCollectionStoresPointers(c) ((c)->collection.store_pointer) + +/** + * Indicates whether the collection can guarantee that the stored elements are currently sorted. + * + * This may return false even when the elements are sorted. + * It is totally up to the implementation of the collection whether it keeps track of the order of its elements. + * + * @param c a pointer to a struct that contains #CX_COLLECTION_BASE + * @retval true if the elements are currently sorted wrt. the collection's compare function + * @retval false if the order of elements is unknown + */ +#define cxCollectionSorted(c) ((c)->collection.sorted) + +/** + * 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 + */ +#define cxDefineDestructor(c, destr) \ + (c)->collection.simple_destructor = (cx_destructor_func) destr + +/** + * 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 + */ +#define cxDefineAdvancedDestructor(c, destr, data) \ + (c)->collection.advanced_destructor = (cx_destructor_func2) destr; \ + (c)->collection.destructor_data = data /** * Invokes the simple destructor function for a specific element. @@ -107,11 +176,14 @@ * Usually only used by collection implementations. There should be no need * to invoke this macro manually. * - * @param c the collection - * @param e the element + * When the collection stores pointers, those pointers are directly passed + * to the destructor. Otherwise, a pointer to the element is passed. + * + * @param c a pointer to a struct that contains #CX_COLLECTION_BASE + * @param e the element (the type is @c void* or @c void** depending on context) */ #define cx_invoke_simple_destructor(c, e) \ - (c)->simple_destructor((c)->store_pointer ? (*((void **) (e))) : (e)) + (c)->collection.simple_destructor((c)->collection.store_pointer ? (*((void **) (e))) : (e)) /** * Invokes the advanced destructor function for a specific element. @@ -119,12 +191,15 @@ * Usually only used by collection implementations. There should be no need * to invoke this macro manually. * - * @param c the collection - * @param e the element + * When the collection stores pointers, those pointers are directly passed + * to the destructor. Otherwise, a pointer to the element is passed. + * + * @param c a pointer to a struct that contains #CX_COLLECTION_BASE + * @param e the element (the type is @c void* or @c void** depending on context) */ #define cx_invoke_advanced_destructor(c, e) \ - (c)->advanced_destructor((c)->destructor_data, \ - (c)->store_pointer ? (*((void **) (e))) : (e)) + (c)->collection.advanced_destructor((c)->collection.destructor_data, \ + (c)->collection.store_pointer ? (*((void **) (e))) : (e)) /** @@ -133,12 +208,15 @@ * Usually only used by collection implementations. There should be no need * to invoke this macro manually. * - * @param c the collection - * @param e the element + * When the collection stores pointers, those pointers are directly passed + * to the destructor. Otherwise, a pointer to the element is passed. + * + * @param c a pointer to a struct that contains #CX_COLLECTION_BASE + * @param e the element (the type is @c void* or @c void** depending on context) */ #define cx_invoke_destructor(c, e) \ - if ((c)->simple_destructor) cx_invoke_simple_destructor(c,e); \ - if ((c)->advanced_destructor) cx_invoke_advanced_destructor(c,e) + if ((c)->collection.simple_destructor) cx_invoke_simple_destructor(c,e); \ + if ((c)->collection.advanced_destructor) cx_invoke_advanced_destructor(c,e) #ifdef __cplusplus } // extern "C"