docs/src/features.md

Sat, 01 Jul 2023 14:05:52 +0200

author
Mike Becker <universe@uap-core.de>
date
Sat, 01 Jul 2023 14:05:52 +0200
changeset 729
600d72644919
parent 727
d92a59f5d261
child 730
9fecb2769d32
permissions
-rw-r--r--

add mempool example

     1 ---
     2 title: UCX Features
     3 ---
     5 <div id="modules">
     7 ------------------------ -------------------------  -------------------  ---------------------------------
     8 [Allocator](#allocator)  [String](#string)          [Buffer](#buffer)    [Memory&nbsp;Pool](#memory-pool)
     9 [Iterator](#iterator)    [Collection](#collection)  [List](#list)        [Map](#map)
    10 [Utilities](#utilities)
    11 ------------------------ -------------------------  -------------------  ---------------------------------
    13 </div>
    15 ## Allocator
    17 *Header file:* [allocator.h](api/allocator_8h.html)  
    19 The UCX allocator provides an interface for implementing an own memory allocation mechanism.
    20 Various function in UCX provide an additional alternative signature that takes an allocator as
    21 argument. A default allocator implementation using the stdlib memory management functions is
    22 available via the global symbol `cxDefaultAllocator`.
    24 If you want to define your own allocator, you need to initialize the `CxAllocator` structure
    25 with a pointer to an allocator class (containing function pointers for the memory management
    26 functions) and an optional pointer to an arbitrary memory region that can be used to store
    27 state information for the allocator. An example is shown below:
    29 ```c
    30 struct my_allocator_state {
    31     size_t total;
    32     size_t avail;
    33     char mem[];
    34 };
    36 static cx_allocator_class my_allocator_class = {
    37         my_malloc_impl,
    38         my_realloc_impl,   // all these functions are somewhere defined
    39         my_calloc_impl,
    40         my_free_impl
    41 };
    43 CxAllocator create_my_allocator(size_t n) {
    44     CxAllocator alloc;
    45     alloc.cl = &my_allocator_class;
    46     alloc.data = calloc(1, sizeof(struct my_allocator_state) + n);
    47     return alloc;
    48 }
    50 void free_my_allocator(CxAllocator *alloc) {
    51     free(alloc.data);
    52     free(alloc);
    53 }
    54 ```
    56 ## String
    58 *Header file:* [string.h](api/string_8h.html)
    60 UCX strings come in two variants: immutable (`cxstring`) and mutable (`cxmutstr`).
    61 The functions of UCX are designed to work with immutable strings by default but in situations where it is necessary,
    62 the API also provides alternative functions that work directly with mutable strings.
    63 Functions that change a string in-place are, of course, only accepting mutable strings.
    65 When you are using UCX functions, or defining your own functions, you are sometimes facing the "problem",
    66 that the function only accepts arguments of type `cxstring` but you only have a `cxmutstr` at hand.
    67 In this case you _should not_ introduce a wrapper function that accepts the `cxmutstr`,
    68 but instead you should use the `cx_strcast()` function to cast the argument to the correct type.
    70 In general, UCX strings are **not** necessarily zero-terminated. If a function guarantees to return zero-terminated
    71 string, it is explicitly mentioned in the documentation of the respective function.
    72 As a rule of thumb, you _should not_ pass the strings of a UCX string structure to another API without explicitly
    73 ensuring that the string is zero-terminated.
    75 ## Buffer
    77 *Header file:* [buffer.h](api/buffer_8h.html)
    79 Instances of this buffer implementation can be used to read from or write to memory like you would do with a stream.
    80 This allows the use of `cx_stream_copy()` (see [Utilities](#utilities)) to copy contents from one buffer to another,
    81 or from a file or network streams to the buffer and vice-versa.
    83 More features for convenient use of the buffer can be enabled, like automatic memory management and automatic
    84 resizing of the buffer space.
    86 Since UCX 3.0, the buffer also supports automatic flushing of contents to another stream (or buffer) as an alternative
    87 to automatically resizing the buffer space.
    88 Please refer to the API doc for the fields prefixed with `flush_` to learn more. 
    90 ## Memory Pool
    92 *Header file:* [mempool.h](api/mempool_8h.html)
    94 A memory pool is providing an allocator implementation that automatically deallocates the memory upon its destruction. 
    95 It also allows you to register destructor functions for the allocated memory, which are automatically called before
    96 the memory is deallocated.
    97 Additionally, you may also register _independent_ destructor functions within a pool in case some external library
    98 allocated memory for you, which should be destroyed together with this pool.
   100 Many UCX features support the use of an allocator.
   101 The [strings](#string), for instance, provide several functions suffixed with `_a` that allow specifying an allocator.
   102 You can use this to keep track of the memory occupied by dynamically allocated strings and cleanup everything with
   103 just a single call to `cxMempoolDestroy()`.
   105 The following code illustrates this on the example of reading a CSV file into memory. 
   106 ```C
   107 #include <stdio.h>
   108 #include <cx/mempool.h>
   109 #include <cx/linked_list.h>
   110 #include <cx/string.h>
   111 #include <cx/buffer.h>
   112 #include <cx/utils.h>
   114 typedef struct {
   115     cxstring column_a;
   116     cxstring column_b;
   117     cxstring column_c;
   118 } CSVData;
   120 int main(void) {
   121     CxMempool* pool = cxBasicMempoolCreate(128);
   123     FILE *f = fopen("test.csv", "r");
   124     if (!f) {
   125         perror("Cannot open file");
   126         return 1;
   127     }
   128     // close the file automatically at pool destruction
   129     cxMempoolRegister(pool, f, (cx_destructor_func) fclose);
   131     // create a buffer using the memory pool for destruction
   132     CxBuffer *content = cxBufferCreate(NULL, 256, pool->allocator, CX_BUFFER_AUTO_EXTEND);
   134     // read the file into the buffer and turn it into a string
   135     cx_stream_copy(f, content, (cx_read_func) fread, (cx_write_func) cxBufferWrite);
   136     cxstring contentstr = cx_strn(content->space, content->size);
   138     // split the string into lines - use the mempool for allocating the target array
   139     cxstring* lines;
   140     size_t lc = cx_strsplit_a(pool->allocator, contentstr,
   141                               CX_STR("\n"), SIZE_MAX, &lines);
   143     // skip the header and parse the remaining data into a linked list
   144     // the nodes of the linked list shall also be allocated by the mempool
   145     CxList* datalist = cxLinkedListCreate(pool->allocator, NULL, sizeof(CSVData));
   146     for (size_t i = 1 ; i < lc ; i++) {
   147         if (lines[i].length == 0) continue;
   148         cxstring fields[3];
   149         size_t fc = cx_strsplit(lines[i], CX_STR(";"), 3, fields);
   150         if (fc != 3) {
   151             fprintf(stderr, "Syntax error in line %zu.\n", i);
   152             cxMempoolDestroy(pool);
   153             return 1;
   154         }
   155         CSVData* data = cxMalloc(pool->allocator, sizeof(CSVData));
   156         data->column_a = fields[0];
   157         data->column_b = fields[1];
   158         data->column_c = fields[2];
   159         cxListAdd(datalist, data);
   160     }
   162     // iterate through the list and output the data
   163     CxIterator iter = cxListIterator(datalist);
   164     cx_foreach(CSVData*, data, iter) {
   165         printf("Column A: %.*s | "
   166                "Column B: %.*s | "
   167                "Column C: %.*s\n",
   168                (int)data->column_a.length, data->column_a.ptr,
   169                (int)data->column_b.length, data->column_b.ptr,
   170                (int)data->column_c.length, data->column_c.ptr
   171         );
   172     }
   174     // cleanup everything, no manual free() needed 
   175     cxMempoolDestroy(pool);
   177     return 0;
   178 } 
   179 ```
   181 ## Iterator
   183 *Header file:* [iterator.h](api/iterator_8h.html)
   185 ## Collection
   187 *Header file:* [collection.h](api/collection_8h.html)
   189 ## List
   191 *Header file:* [list.h](api/list_8h.html)
   193 ### Linked List
   195 *Header file:* [linked_list.h](api/linked__list_8h.html)
   197 ### Array List
   199 *Header file:* [array_list.h](api/array__list_8h.html)
   201 ## Map
   203 *Header file:* [map.h](api/map_8h.html)
   205 ### Hash Map
   207 *Header file:* [hash_map.h](api/hash__map_8h.html)
   209 ## Utilities
   211 *Header file:* [utils.h](api/utils_8h.html)
   213 UCX provides some utilities for routine tasks. Most of them are simple macros, like e.g. the `cx_for_n()` macro,
   214 creating a `for` loop counting from zero to (n-1) which is extremely useful to traverse the indices of
   215 an array.
   217 But the most useful utilities are the *stream copy* functions, which provide a simple way to copy all - or a
   218 bounded amount of - data from one stream to another. Since the read/write functions of a UCX buffer are
   219 fully compatible with stream read/write functions, you can easily transfer data from file or network streams to
   220 a UCX buffer or vice-versa.
   222 The following example shows, how easy it is to read the contents of a file into a buffer:
   223 ```c
   224 FILE *inputfile = fopen(infilename, "r");
   225 if (inputfile) {
   226     CxBuffer fbuf;
   227     cxBufferInit(&fbuf, NULL, 4096, NULL, CX_BUFFER_AUTO_EXTEND);
   228     cx_stream_copy(inputfile, &fbuf,
   229                    (cx_read_func) fread,
   230                    (cx_write_func) cxBufferWrite);
   231     fclose(inputfile);
   233     // ... do something meaningful with the contents ...
   235     cxBufferDestroy(&fbuf);
   236 } else {
   237     perror("Error opening input file");
   238     if (fout != stdout) {
   239         fclose(fout);
   240     }
   241 }
   242 ```
   244 ### Printf Functions
   246 *Header file:* [printf.h](api/printf_8h.html)
   248 In this utility header you can find `printf()`-like functions that can write the formatted output to an arbitrary
   249 stream (or UCX buffer, resp.), or to memory allocated by an allocator within a single function call.
   250 With the help of these convenience functions, you do not need to `snprintf` your string to a temporary buffer anymore,
   251 plus you do not need to worry about too small buffer sizes, because the functions will automatically allocate enough
   252 memory to contain the entire formatted string.
   254 ### Compare Functions
   256 *Header file:* [compare.h](api/compare_8h.html)
   258 This header file contains a collection of compare functions for various data types.
   259 Their signatures are designed to be compatible with the `cx_compare_func` function pointer type.

mercurial