Update doc (WIP)

This commit is contained in:
Patrick Pelissier committed 2025-05-07 21:02:24 +02:00
1 parent 3ddf9438da
commit 431e3a1228
1 file changed
+138
+138
View File
@@ -9583,6 +9583,144 @@ The following macro is defined and enabled to iterate over a container (See exam
_________________
## Memory context Customization
It is possible to give a custom memory context parameter to the memory methods `REALLOC`, `FREE`, `NEW`and `DEL`.
For this, you need to define `M_USE_CONTEXT` to the type of the custom memory context parameter.
The definition of this global parameter modifies the generation of **all** functions
so that the functions that may allocate or free something will add a new argument,
the memory context parameter `m_context` of type `M_USE_CONTEXT`,
as their first arguement.
It will also modifies the `OPLIST` definition so that they request the parameter named `m_context`
for such methods.
The memory context can be an [arena allocator](https://www.rfleury.com/p/untangling-lifetimes-the-arena-allocator)
> [!Note]
> The memory context parameter is not stored in the container
> because it is not efficient in memory usage and is redundant when you
> create container of other containers (example `array` of `string_t)`
> The user shall ensure of the coherence of the memory context for a given container
> so that it is the same memory context since its construction to its destruction.
If you master your own memory, you may want to control when performing the Garbage Collecting.
This Garbage Collecting may be quite efficient in reclaiming allocated memory in a single and efficient pass:
in such a case, you may not want calling the destructors of the containers as their operation of freeing the memory
back to the memory allocator will be redundant and inefficient.
As a consequence, the following guarantee is ensured:
The destructors of all containers except the thread safe ones only free back memory.
As such, it is safe not to call the destructors of these containers if you have another way to reclaim your memory.
If the destructor of a mutex is also a no-op on your system, this guarantee is extended to the thread safe containers too.
In order to use such feature, you need to:
* define globally `M_USE_CONTEXT` with your type.
* define globally an override of the memory functions `M_MEMORY_ALLOC`, `M_MEMORY_DEL`, `M_MEMORY_REALLOC` and `M_MEMORY_FREE`.
You will realize that the expected definitions of these macros don't expect the memory context parameter.
Instead, the macros themselves shall directly use the named argument `m_context` for this purpose.
This argument is ensure to be defined by the function when using this macro.
FIXME: Seems bad design when written...
Example
```C
// Define a memory context type
typedef int *context_t;
// Define the realloc / free that accepts the memory context.
static void *my_realloc(void *ptr, size_t old, size_t new, size_t base, context_t context)
{
(void) context; // TODO
(void) old; // TODO
return realloc(ptr, new*base);
}
static void my_free(void *ptr, size_t old, size_t base, context_t context)
{
(void) context; // TODO
(void) old; // TODO
(void) base; // TODO
free(ptr);
}
// Request M*LIB to generate functions accepting a memory context parameter that will be passed to the memory functions
# define M_USE_CONTEXT context_t
// Overloaded memory functions to use the custom ones.
// m_context is the name of the memory context parameter
# define M_MEMORY_REALLOC(type, ptr, o, n) my_realloc(ptr, o, n, sizeof (type), m_context)
# define M_MEMORY_FREE(type, ptr, o) my_free(ptr, o, sizeof (type), m_context)
# define M_MEMORY_ALLOC(type) my_realloc(NULL, 0, 1, sizeof (type), m_context)
# define M_MEMORY_DEL(ptr) my_free(ptr, 1, sizeof (*ptr), m_context)
// Now you may include M*LIB headers.
```
This works great for local allocators for a thread. However some containers are designed to handle
objects accross several threads: shared pointer, communication queue, ...
For such containers, a local allocator has no meaning: it will be very hard to ensure the same allocator
is used for both the producor thread and the user threads.
As a concequence, shared pointer, communication queue container and all thread containers
will use a global memory context:
M\*LIB won't add a new argument `m_context` to the functions of such containers. Instead it will generate
a local parameter initialize to the global memory context.
The global memory context is defined by the macro `M_USE_GLOBAL_CONTEXT` which shall define and initialize
the named argument to the global memory context. In the absence of definition of such macro, the default is
to initialize the context to '0'. The memory functions shall recognize such context as the global one.
FIXME: if it is expensive, it is useless to initialize a local variable rather than using the global variable directly...
The following methods are modified to support the memory context parameter:
* m-string:
** _clear
** _clear_get_cstr
** _reserve
** _set_cstr
** _set_cstrn
** _set
** _set_n
** _init_set
** _init_set_cstr
** _move
** _push_back
** _cat_cstr
** _cat
** _replace_cstr
** _replace
** _replace_at
** _replace_all_cstr
** _replace_all
** _set_ui
** _set_si
** _vprintf
** _printf
** _cat_vprintf
** _cat_printf
** _set_ui
** _set_si
** _fgets
** _fget_word
** _get_str
** _in_str
** _parse_str
** _out_serial
** _in_serial
** _it_set_ref
** _push_u
** _split
** _join
** _out_serial
** _in_serial
_________________
## Global User Customization
The behavior of M\*LIB can be customized globally by defining the following macros