Sat, 15 Feb 2025 17:43:21 +0100
complete the printf documentation and fix code formatting
relates to #451
--- a/docs/Writerside/topics/allocator.h.md Sat Feb 15 16:36:29 2025 +0100 +++ b/docs/Writerside/topics/allocator.h.md Sat Feb 15 17:43:21 2025 +0100 @@ -17,17 +17,17 @@ void *cxMalloc(const CxAllocator *allocator, size_t n); void *cxCalloc(const CxAllocator *allocator, - size_t nmemb, size_t size); + size_t nmemb, size_t size); void *cxRealloc(const CxAllocator *allocator, void *mem, size_t n); void *cxReallocArray(const CxAllocator *allocator, void *mem, - size_t nmemb, size_t size); + size_t nmemb, size_t size); int cxReallocate(const CxAllocator *allocator, void **mem, size_t n); int cxReallocateArray(const CxAllocator *allocator, void **mem, - size_t nmemb, size_t size); + size_t nmemb, size_t size); void cxFree(const CxAllocator *allocator, void *mem); @@ -124,21 +124,21 @@ 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 play a vital role in deep deallocations. +Another scenarios, besides destroying elements in a collection, are the deallocation of objects +stored in a [memory pool](mempool.h.md) or deallocations 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 +> * a destructor may only deallocate 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. +> function to also deallocate the element's memory when the element is removed from that list. <seealso> <category ref="apidoc">
--- a/docs/Writerside/topics/memory.md Sat Feb 15 16:36:29 2025 +0100 +++ b/docs/Writerside/topics/memory.md Sat Feb 15 17:43:21 2025 +0100 @@ -10,4 +10,4 @@ > Although not part of the public API, UCX is also implementing the allocator interface > in its own test suite: `CxTestingAllocator`. This allocator keeps track of memory allocations -> and de-allocations with the goal to detect memory management errors. +> and deallocations with the goal to detect memory management errors.
--- a/docs/Writerside/topics/printf.h.md Sat Feb 15 16:36:29 2025 +0100 +++ b/docs/Writerside/topics/printf.h.md Sat Feb 15 17:43:21 2025 +0100 @@ -6,26 +6,36 @@ With the help of these convenience functions, you do not need the libc `snprintf` to print your string to a temporary buffer anymore, plus you do not need to worry about too small buffer sizes, because the functions will automatically allocate enough memory to contain the entire formatted string. +> Although UCX usually uses `size_t` for sizes, the return type of all `printf`-like functions +> (except for the `cx_asprintf()` family of functions) is `int`, consistent with the stdio `printf` return type. +{style="note"} + ## Print to Streams and Buffers ```C #include <cx/printf.h> int cx_fprintf(void *stream, cx_write_func wfc, - const char *fmt, ...); + const char *fmt, ...); int cx_vfprintf(void *stream, cx_write_func wfc, - const char *fmt, va_list ap); + const char *fmt, va_list ap); int cx_bprintf(CxBuffer *buf, const char *fmt, ...); ``` -> TODO: document -{style="warning"} +The `cx_fprintf()` function uses the stdio `snprintf()` to prepare a formatted string +which is then written to the `stream` using the write function `wfc`. +The return value is the number of bytes written or a value less than zero when an error occurred. +If the resulting string is short enough, no additional memory is allocated on the heap. +See the Section about [](#small-buffer-optimization) for more details. The `cx_vfprintf()` function is equivalent to `cx_fprintf()`, except that instead of being called with a variable number of arguments, -they are called with an argument list as defined by `<stdarg.h>`. +it is called with an argument list as defined by `<stdarg.h>`. + +The `cx_bprintf()` function is implemented as macro for `cx_fprintf()` with the +`CxBuffer` as `stream` and the `cxBufferWriteFunc` as write function. ## Print to Freshly Allocated Memory @@ -35,16 +45,18 @@ cxmutstr cx_asprintf(const char *fmt, ...); cxmutstr cx_asprintf_a(const CxAllocator *allocator, - const char *fmt, ...); + const char *fmt, ...); cxmutstr cx_vasprintf(const char *fmt, va_list ap); cxmutstr cx_vasprintf_a(const CxAllocator *allocator, - const char *fmt, va_list ap); + const char *fmt, va_list ap); ``` -> TODO: document -{style="warning"} +The `cx_asprintf()` and `cx_asprintf_a()` functions print the formatted output directly to a freshly allocated +string which is then returned from the function. +On platforms (or when using allocators) where allocation can fail, +the returned string may be empty and the `ptr` field set to `NULL`. The `cx_vasprintf()` and `cx_vasprintf_a()` functions are equivalent to `cx_asprintf()` and `cx_asprintf_a()`, except that instead of being called with a variable number of arguments, @@ -55,18 +67,51 @@ ```C #include <cx/printf.h> -cx_sprintf -cx_sprintf_a -cx_sprintf_s -cx_sprintf_sa -cx_vsprintf -cx_vsprintf_a -cx_vsprintf_s -cx_vsprintf_sa +int cx_sprintf(char **str, size_t *len, + const char *fmt, ...); + +int cx_sprintf_a(CxAllocator *alloc, char **str, size_t *len, + const char *fmt, ...); + +int cx_sprintf_s(char *buf, size_t *len, char **str, + const char *fmt, ...); + +int cx_sprintf_sa(CxAllocator *alloc, + char *buf, size_t *len, char **str, + const char *fmt, ...); + +int cx_vsprintf(char **str, size_t *len, + const char *fmt, va_list ap); + +int cx_vsprintf_a(CxAllocator *alloc, char **str, size_t *len, + const char *fmt, va_list ap); + +int cx_vsprintf_s(char *buf, size_t *len, char **str, + const char *fmt, ...); + +int cx_vsprintf_sa(CxAllocator *alloc, + char *buf, size_t *len, char **str, + const char *fmt, va_list ap); ``` -> TODO: document -{style="warning"} +The `cx_sprintf()` and `cx_sprintf_a()` functions take a pointer `str` to a pointer to a pre-allocated buffer, +as well as a pointer `len` to `*str`'s length. +If the formatted output would not fit into this buffer, it is reallocated +and the new pointer to the buffer and the new length are written back to the variables pointed to by `str` and `len`. + +The `cx_sprintf_s()` and `cx_sprintf_sa()` functions differ from the previous function in that they take +the pointer to the pre-allocated buffer in the `buf` argument and not in the `str` argument +(which in this case is only used for storing the resulting pointer), and _always_ allocate an entirely new buffer +when the length is insufficient. +This is particularly useful when you want to print the formatted string to a buffer allocated on the stack, but also +want the option to switch to heap-allocated memory when necessary. + +In other words: when the formatted output fits into the buffer pointed to by `buf`, `buf` will be written to `*str`. +Otherwise, the pointer to the freshly allocated buffer is written to `*str`. + +> When using `cx_sprintf()` or `cx_sprintf_a()` you should always make sure that the string pointed to by `*str` +> was allocated by a matching allocator. +> This restriction does not apply for `cx_sprintf_s()` or `cx_sprintf_sa()` which would allocate a fresh buffer when needed. The `cx_vsprintf()`, `cx_vsprintf_a()`, `cx_vsprintf_s()`, and `cx_vsprintf_sa()` functions are equivalent to `cx_sprintf()`, `cx_sprintf_a()`, `cx_sprintf_s()`, and `cx_sprintf_sa()`,
--- a/docs/Writerside/topics/streams.h.md Sat Feb 15 16:36:29 2025 +0100 +++ b/docs/Writerside/topics/streams.h.md Sat Feb 15 17:43:21 2025 +0100 @@ -9,27 +9,19 @@ ```C #include <cx/streams.h> -size_t cx_stream_copy( - void *src, void *dest, - cx_read_func rfnc, cx_write_func wfnc -); -size_t cx_stream_ncopy( - void *src, void *dest, - cx_read_func rfnc, cx_write_func wfnc, - size_t n -); +size_t cx_stream_copy(void *src, void *dest, + cx_read_func rfnc, cx_write_func wfnc); + +size_t cx_stream_ncopy(void *src, void *dest, + cx_read_func rfnc, cx_write_func wfnc, size_t n); -size_t cx_stream_bcopy( - void *src, void *dest, - cx_read_func rfnc, cx_write_func wfnc, - char *buf, size_t bufsize -); -size_t cx_stream_bncopy( - void *src, void *dest, - cx_read_func rfnc, cx_write_func wfnc, - char *buf, size_t bufsize, - size_t n -); +size_t cx_stream_bcopy(void *src, void *dest, + cx_read_func rfnc, cx_write_func wfnc, + char *buf, size_t bufsize); + +size_t cx_stream_bncopy(void *src, void *dest, + cx_read_func rfnc, cx_write_func wfnc, + char *buf, size_t bufsize, size_t n); ``` ## Description