adds documentation for destructor functions and collections docs/3.1 tip

Sat, 08 Feb 2025 20:38:05 +0100

author
Mike Becker <universe@uap-core.de>
date
Sat, 08 Feb 2025 20:38:05 +0100
branch
docs/3.1
changeset 1171
155bc3b0dcb3
parent 1170
49cc0bbea6a9

adds documentation for destructor functions and collections

also invented some new macros for the collection.h

relates to #451

docs/Writerside/topics/allocator.h.md file | annotate | diff | comparison | revisions
docs/Writerside/topics/collection.h.md file | annotate | diff | comparison | revisions
src/cx/collection.h file | annotate | diff | comparison | revisions
--- a/docs/Writerside/topics/allocator.h.md	Sat Feb 08 14:24:22 2025 +0100
+++ b/docs/Writerside/topics/allocator.h.md	Sat Feb 08 20:38:05 2025 +0100
@@ -107,6 +107,37 @@
 }
 ```
 
+When you are implementing 
+
+## Destructor Functions
+
+The `allocator.h` header also declares two function pointers for destructor functions.
+
+```C
+typedef void (*cx_destructor_func)(void *memory);
+typedef void (*cx_destructor_func2)(void *data, void *memory);
+```
+
+The first one is called _simple_ destructor (e.g. in the context of [collections](collection.h.md)),
+and the second one is called _advanced_ destructor.
+The only difference is that you can pass additional custom `data` to an advanced destructor function.
+
+Destructor functions play a vital role in deep de-allocations.
+Another scenarios, besides destroying elements in a collection, are the de-allocation of objects
+stored in a [memory pool](mempool.h.md) or de-allocations of deeply nested [JSON](json.h.md) objects.
+
+> Destructor functions are not to be confused with `free()`-like functions.
+> The fundamental differences are that 
+> * it is not safe to pass `NULL` to a destructor function
+> * a destructor may only de-allocate the contents inside an object but not the object itself, depending on context
+>
+{style="note"}
+
+> For example, when you are using a [list](list.h.md) that stores elements directly, a destructor function
+> assigned to that collection may only destroy the element's contents but must not deallocate the element's memory.
+> On the other hand, when the list is storing just pointers to the elements, you _may_ want the destructor
+> function to also de-allocate the element's memory when the element is removed from that list.
+
 <seealso>
 <category ref="apidoc">
 <a href="https://ucx.sourceforge.io/api/allocator_8h.html">allocator.h</a>
--- a/docs/Writerside/topics/collection.h.md	Sat Feb 08 14:24:22 2025 +0100
+++ b/docs/Writerside/topics/collection.h.md	Sat Feb 08 20:38:05 2025 +0100
@@ -1,24 +1,77 @@
 # Collections
 
-<warning>
-Outdated - Rewrite!
-</warning>
-
-Collections in UCX 3 have several common features.
+UCX defines common attributes for collections.
 If you want to implement an own collection data type that uses the same features, you can use the
 `CX_COLLECTION_BASE` macro at the beginning of your struct to roll out all members a usual UCX collection has.
+
+This macro will embed a structure in your collection that can be accessed with the member name `collection`.
+
 ```c
 struct my_fancy_collection_s {
-    CX_COLLECTION_BASE;
+    CX_COLLECTION_BASE; // adds a member named 'collection'
     struct my_collection_data_s *data;
 };
 ```
-Based on this structure, this header provides some convenience macros for invoking the destructor functions
-that are part of the basic collection members.
-The idea of having destructor functions within a collection is that you can destroy the collection _and_ the
-contents with one single function call.
-When you are implementing a collection, you are responsible for invoking the destructors at the right places, e.g.
-when removing (and deleting) elements in the collection, clearing the collection, or - the most prominent case -
-destroying the collection.
+
+> You can always look at the UCX list and map implementations if you need some inspiration.
+
+## Base Attributes of a Collection
+
+The following attributes are declared by the `CX_COLLECTION_BASE` macro:
+
+| Attribute             | Description                                                                                                    |
+|-----------------------|----------------------------------------------------------------------------------------------------------------|
+| `allocator`           | The [allocator](allocator.h.md) that shall be used for the collection data.                                    |
+| `cmpfunc`             | A function to [compare](compare.h.md) two elements.                                                            |
+| `elem_size`           | The size of one element in bytes.                                                                              |
+| `size`                | The size, meaning the number of elements, currently stored.                                                    |
+| `simple_destructor`   | An optional simple [destructor function](allocator.h.md#destructor-functions).                                 |
+| `advanced_destructor` | An optional advanced destructor function.                                                                      |
+| `destructor_data`     | A pointer to the custom data that shall be passed to the advanced destructor.                                  |
+| `store_pointer`       | A `bool` indicating whether this collection stores pointers instead of the element's data.                     |
+| `sorted`              | A `bool` indicating whether the elements are currently guaranteed sorted with respect to the compare function. |
+
+The attributes can be accessed directly via the `collection` member of your struct, or with the following convenience macros.
+
+```C
+cxCollectionSize(c)
+cxCollectionElementSize(c)
+cxCollectionStoresPointers(c)
+cxCollectionSorted(c)
+```
+
+In each case the argument `c` is a pointer to your collection. The macro will then access the base data with `c->collection`.
+
+For working with destructors, the following macros are defined:
 
-You can always look at the UCX list and map implementations if you need some inspiration.
+```C
+cxDefineDestructor(c, destr) 
+cxDefineAdvancedDestructor(c, destr, data)
+
+// use in your collection's implementation
+cx_invoke_destructor(c, elem)
+  
+// the following two should not be used
+cx_invoke_simple_destructor(c, elem) 
+cx_invoke_advanced_destructor(c, elem) 
+```
+
+With `cxDefineDestructor()` 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`.
+
+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.
+This macro will invoke a simple destructor, if one is assigned, first, and then the advanced destructor (again, if assigned).
+
+> Destructor functions are always invoked with a pointer to the element in your collection.
+> If your collection is storing pointers (i.e. `cxCollectionStorePointers()` returns `true`)
+> the `cx_invoke_destructor()` will make sure that the pointer to the element is dereferenced first,
+> so that the destructor functions are _always_ invoked with pointer to the actual element.
+{style="note"}
+
+<seealso>
+<category ref="apidoc">
+<a href="https://ucx.sourceforge.io/api/collection_8h.html">collection.h</a>
+</category>
+</seealso>
--- a/src/cx/collection.h	Sat Feb 08 14:24:22 2025 +0100
+++ b/src/cx/collection.h	Sat Feb 08 20:38:05 2025 +0100
@@ -113,6 +113,45 @@
 #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

mercurial