docs/src/modules.md

Mon, 30 Dec 2019 09:52:07 +0100

author
Mike Becker <universe@uap-core.de>
date
Mon, 30 Dec 2019 09:52:07 +0100
branch
feature/array
changeset 387
7e0f19fe23ff
parent 359
9f86bc73f96b
child 370
07ac32b385e4
permissions
-rw-r--r--

closes array branch towards ucx 2.1 release

     1 ---
     2 title: Modules
     3 ---
     5 UCX provides several modules for data structures and algorithms.
     6 You may choose to use specific modules by inclueding the corresponding header
     7 file.
     8 Please note, that some modules make use of other UCX modules.
     9 For instance, the [Allocator](#allocator) module is used by many other modules
    10 to allow flexible memory allocation.
    11 By default the header files are placed into an `ucx` directory within your
    12 systems include directory. In this case you can use a module by including it
    13 via `#include <ucx/MODULENAME.h>`.
    14 Required modules are included automatically.
    16 <div id="modules" align="center">
    18 ----------------------- ----------------------  --------------------------------  ---------------------------
    19 [String](#string)       [Buffer](#buffer)
    20 [Allocator](#allocator) [Stack](#stack)         [Memory&nbsp;Pool](#memory-pool)     
    21 [Array](#array)         [List](#list)           [Map](#map)                       [AVL&nbsp;Tree](#avl-tree)
    22 [Logging](#logging)     [Testing](#testing)     [Utilities](#utilities)           [Properties](#properties)                         
    23 ----------------------- ----------------------  --------------------------------  ---------------------------
    25 </div>
    27 ## Allocator
    29 *Header file:* [allocator.h](api/allocator_8h.html)  
    30 *Required modules:* None.
    32 A UCX allocator consists of a pointer to the memory area / pool and four
    33 function pointers to memory management functions operating on this memory
    34 area / pool. These functions shall behave equivalent to the standard libc
    35 functions `malloc`, `calloc`, `realloc` and `free`.
    37 The signature of the memory management functions is based on the signature
    38 of the respective libc function but each of them takes the pointer to the
    39 memory area / pool as first argument.
    41 As the pointer to the memory area / pool can be arbitrarily chosen, any data
    42 can be provided to the memory management functions. One example is the
    43 [UCX Memory Pool](#memory-pool).
    45 ## Array
    47 *Header file:* [array.h](api/array_8h.html)  
    48 *Required modules:* [Allocator](#allocator)
    50 The UCX Array is an implementation of a dynamic array with automatic
    51 reallocation. The array structure contains a capacity, the current size,
    52 the size of each element, the raw pointer to the memory area and an allocator.
    53 Arrays are in most cases much faster than linked list.
    54 One can decide, whether to create a new array on the heap with `ucx_array_new()`
    55 or to save one indirection by initializing a `UcxArray` structure on the stack
    56 with `ucx_array_init()`.
    58 ### Remove duplicates from an array of strings
    60 The following example shows, how a `UcxArray` can be built with
    61 a standard dynamic C array (pointer+length) as basis.
    63 ```C
    64 #include <stdio.h>
    65 #include <ucx/array.h>
    66 #include <ucx/string.h>
    67 #include <ucx/utils.h>
    69 UcxArray remove_duplicates(sstr_t* array, size_t arrlen) {
    70     // worst case is no duplicates, hence the capacity is set to arrlen
    71     UcxArray result = ucx_array_new(arrlen, sizeof(sstr_t));
    72     // only append elements, if they are not already present in the array
    73     for (size_t i = 0 ; i < arrlen ; ++i) {
    74         if (!ucx_array_contains(result, array+i, ucx_cmp_sstr, NULL)) {
    75             ucx_array_append(&result, array+i);
    76         }
    77     }
    78     // make the array as small as possible
    79     ucx_array_shrink(&result);
    80     return result;
    81 }
    83 /* ... */
    85 sstr_t* array = /* some standard array of strings */
    86 size_t arrlen = /* the length of the array */
    88 UcxArray result = remove_duplicates(array,arrlen);
    90 /* Iterate over the array and print the elements */
    91 for (size_t i = 0 ; i < result.size ; i++) {
    92     sstr_t s = ucx_array_at_typed(sstr_t, result, i);
    93     printf("%" PRIsstr "\n", SFMT(s));
    94 }
    96 /* Free the array. */
    97 ucx_array_free(&result);
    98 ```
   100 ## AVL Tree
   102 *Header file:* [avl.h](api/avl_8h.html)  
   103 *Required modules:* [Allocator](#allocator)
   105 This binary search tree implementation allows average O(1) insertion and
   106 removal of elements (excluding binary search time).
   107 All common binary tree operations are implemented. Furthermore, this module
   108 provides search functions via lower and upper bounds.
   110 ### Filtering items with a time window
   112 Suppose you have a list of items which contain a `time_t` value and your task
   113 is to find all items within a time window `[t_start, t_end]`.
   114 With AVL Trees this is easy:
   115 ```C
   116 /* ---------------------
   117  * Somewhere in a header
   118  */
   119 typedef struct {
   120     time_t ts;
   121     /* other important data */
   122 } MyObject;
   124 /* -----------
   125  * Source code
   126  */
   128 UcxAVLTree* tree = ucx_avl_new(ucx_cmp_longint);
   129 /* ... populate tree with objects, use '& MyObject.ts' as key ... */
   132 /* Now find every item, with 30 <= ts <= 70 */
   133 time_t ts_start = 30;
   134 time_t ts_end = 70;
   136 printf("Values in range:\n");
   137 for (
   138         UcxAVLNode* node = ucx_avl_find_node(
   139             tree, (intptr_t) &ts_start,
   140             ucx_dist_longint, UCX_AVL_FIND_LOWER_BOUNDED);
   141         node && (*(time_t*)node->key) <= ts_end;
   142         node = ucx_avl_succ(node)
   143     ) {
   144     printf(" ts: %ld\n", ((MyObject*)node->value)->ts);
   145 }
   147 ucx_avl_free_content(tree, free);
   148 ucx_avl_free(tree);
   149 ```
   151 ## Buffer
   153 *Header file:* [buffer.h](api/buffer_8h.html)  
   154 *Required modules:* None.
   156 Instances of this buffer implementation can be used to read from or to write to
   157 memory like you would do with a stream. This allows the use of
   158 `ucx_stream_copy()` from the [Utilities](#utilities) module to copy contents
   159 from one buffer to another or from file or network streams to the buffer and
   160 vice-versa.
   162 More features for convenient use of the buffer can be enabled, like automatic
   163 memory management and automatic resizing of the buffer space.
   164 See the documentation of the macro constants in the header file for more
   165 information.
   167 ### Add line numbers to a file
   169 When reading a file line by line, you have three options: first, you could limit
   170 the maximum supported line length.
   171 Second, you allocate a god buffer large
   172 enough for the most lines a text file could have.
   173 And third, undoubtedly the best option, you start with a small buffer, which
   174 adjusts on demand.
   175 An `UcxBuffer` can be created to do just that for you.
   176 Just pass the `UCX_BUFFER_AUTOEXTEND` option to the initialization function.
   177 Here is a full working program, which adds line numbers to a file.
   178 ```C
   179 #include <stdio.h>
   180 #include <ucx/buffer.h>
   181 #include <ucx/utils.h>
   183 int main(int argc, char** argv) {
   185     if (argc != 2) {
   186         fprintf(stderr, "Usage: %s <file>\n", argv[0]);
   187         return 1;
   188     }
   190     FILE* input = fopen(argv[1], "r");
   191     if (!input) {
   192         perror("Canno read input");
   193         return 1;
   194     }
   196     const size_t chunksize = 256;
   198     UcxBuffer* linebuf =
   199         ucx_buffer_new(
   200             NULL,       /* the buffer should manage the memory area for us */
   201             2*chunksize,  /* initial size should be twice the chunk size */
   202             UCX_BUFFER_AUTOEXTEND); /* the buffer will grow when necessary */
   204     size_t lineno = 1;
   205     do {
   206         /* read line chunk */
   207         size_t read = ucx_stream_ncopy(
   208                 input, linebuf, fread, ucx_buffer_write, chunksize);
   209         if (read == 0) break;
   211         /* handle line endings */
   212         do {
   213             sstr_t bufstr = ucx_buffer_to_sstr(linebuf);
   214             sstr_t nl = sstrchr(bufstr, '\n');
   215             if (nl.length == 0) break;
   217             size_t linelen = bufstr.length - nl.length;
   218             sstr_t linestr = sstrsubsl(bufstr, 0, linelen);
   220             printf("%zu: %" PRIsstr "\n", lineno++, SFMT(linestr));
   222             /* shift the buffer to the next line */
   223             ucx_buffer_shift_left(linebuf, linelen+1);
   224         } while(1);
   226     } while(1);
   228     /* print the 'noeol' line, if any */
   229     sstr_t lastline = ucx_buffer_to_sstr(linebuf);
   230     if (lastline.length > 0) {
   231         printf("%zu: %" PRIsstr, lineno, SFMT(lastline));
   232     }
   234     fclose(input);
   235     ucx_buffer_free(linebuf);
   237     return 0;
   238 }
   239 ```
   241 ## List
   243 *Header file:* [list.h](api/list_8h.html)  
   244 *Required modules:* [Allocator](#allocator)
   246 This module provides the data structure and several functions for a doubly
   247 linked list. Among the common operations like insert, remove, search and sort,
   248 we allow convenient iteration via a special `UCX_FOREACH` macro.
   250 ### Remove duplicates from an array of strings
   252 Assume you are given an array of `sstr_t` and want to create a list of these
   253 strings without duplicates.
   254 This is a similar example to the one [above](#array), but here we are
   255 using a `UcxList`.
   256 ```C
   257 #include <stdio.h>
   258 #include <ucx/list.h>
   259 #include <ucx/string.h>
   260 #include <ucx/utils.h>
   262 UcxList* remove_duplicates(sstr_t* array, size_t arrlen) {
   263     UcxList* list = NULL;
   264     for (size_t i = 0 ; i < arrlen ; ++i) {
   265         if (ucx_list_find(list, array+i, ucx_cmp_sstr, NULL) == -1) {
   266             sstr_t* s = malloc(sizeof(sstr_t));
   267             *s = sstrdup(array[i]);
   268             list = ucx_list_append(list, s);
   269         }
   270     }
   271     return list;
   272 }
   274 /* we will need this function to clean up the list contents later */
   275 void free_sstr(void* ptr) {
   276     sstr_t* s = ptr;
   277     free(s->ptr);
   278     free(s);
   279 }
   281 /* ... */
   283 sstr_t* array = /* some array of strings */
   284 size_t arrlen = /* the length of the array */
   286 UcxList* list = remove_duplicates(array,arrlen);
   288 /* Iterate over the list and print the elements */
   289 UCX_FOREACH(elem, list) {
   290     sstr_t s = *((sstr_t*)elem->data);
   291     printf("%" PRIsstr "\n", SFMT(s));
   292 }
   294 /* Use our free function to free the duplicated strings. */
   295 ucx_list_free_content(list, free_sstr);
   296 ucx_list_free(list);
   297 ```
   299 ## Logging
   301 *Header file:* [logging.h](api/logging_8h.html)  
   302 *Required modules:* [Map](#map), [String](#string)
   304 The logging module comes with some predefined log levels and allows some more
   305 customization. You may choose if you want to get timestamps or source file and
   306 line number logged automatically when outputting a message.
   307 The following function call initializes a debug logger with all of the above
   308 information:
   309 ```C
   310     log = ucx_logger_new(stdout, UCX_LOGGER_DEBUG,
   311             UCX_LOGGER_LEVEL | UCX_LOGGER_TIMESTAMP | UCX_LOGGER_SOURCE);
   312 ```
   313 Afterwards you can use this logger with the predefined macros
   314 ```C
   315     ucx_logger_trace(log, "Verbose output");
   316     ucx_logger_debug(log, "Debug message");
   317     ucx_logger_info(log, "Information");
   318     ucx_logger_warn(log, "Warning");
   319     ucx_logger_error(log, "Error message");
   320 ```
   321 or you use
   322 ```C
   323     ucx_logger_log(log, CUSTOM_LEVEL, "Some message")
   324 ```
   325 When you use your custom log level, don't forget to register it with
   326 ```C
   327     ucx_logger_register_level(log, CUSTOM_LEVEL, "CUSTOM")
   328 ```
   329 where the last argument must be a string literal.
   331 ## Map
   333 *Header file:* [map.h](api/map_8h.html)  
   334 *Required modules:* [Allocator](#allocator), [String](#string)
   336 This module provides a hash map implementation using murmur hash 2 and separate
   337 chaining with linked lists. Similarly to the list module, we provide a
   338 `UCX_MAP_FOREACH` macro to conveniently iterate through the key/value pairs.
   340 ### Parsing command line options
   342 Assume you want to parse command line options and record them within a map.
   343 One way to do this is shown by the following code sample:
   344 ```C
   345     UcxMap* options = ucx_map_new(16);
   346     const char *NOARG = "";
   348     char *option = NULL;
   349     char optchar = 0;
   350     for(int i=1;i<argc;i++) {
   351         char *arg = argv[i];
   352         size_t len = strlen(arg);
   353         if(len > 1 && arg[0] == '-') {
   354             for(int c=1;c<len;c++) {
   355                 if(option) {
   356                     fprintf(stderr,
   357                             "Missing argument for option -%c\n", optchar);
   358                     return 1;
   359                 }
   360                 switch(arg[c]) {
   361                     default: {
   362                         fprintf(stderr, "Unknown option -%c\n\n", arg[c]);
   363                         return 1;
   364                     }
   365                     case 'v': {
   366                         ucx_map_cstr_put(options, "verbose", NOARG);
   367                         break;
   368                     }
   369                     case 'o': {
   370                         option = "output";
   371                         optchar = 'o';
   372                         break;
   373                     }
   374                 }
   375             }
   376         } else if(option) {
   377             ucx_map_cstr_put(options, option, arg);
   378             option = NULL;
   379         } else {
   380             /* ... handle argument that is not an option ... */
   381         }
   382     }
   383     if(option) {
   384         fprintf(stderr,
   385                 "Missing argument for option -%c\n", optchar);
   386         return 1;
   387     }
   388 ```
   389 With the following loop, you can access the previously recorded options:
   390 ```C
   391     UcxMapIterator iter = ucx_map_iterator(options);
   392     char *arg;
   393     UCX_MAP_FOREACH(optkey, arg, iter) {
   394         char* opt = optkey.data;
   395         if (*arg) {
   396             printf("%s = %s\n", opt, arg);
   397         } else {
   398             printf("%s active\n", opt);
   399         }
   400     }
   401 ```
   402 Don't forget to call `ucx_map_free()`, when you are done with the map.
   404 ## Memory Pool
   406 *Header file:* [mempool.h](api/mempool_8h.html)  
   407 *Required modules:* [Allocator](#allocator)
   409 Here we have a concrete allocator implementation in the sense of a memory pool.
   410 This pool allows you to register destructor functions for the allocated memory,
   411 which are automatically called on the destruction of the pool.
   412 But you may also register *independent* destructor functions within a pool in
   413 case some external library allocated memory for you, which should be
   414 destroyed together with this pool.
   416 Many UCX modules support the use of an allocator.
   417 The [String Module](#string), for instance, provides the `sstrdup_a()` function,
   418 which uses the specified allocator to allocate the memory for the duplicated
   419 string.
   420 This way, you can use a `UcxMempool` to keep track of the memory occupied by
   421 duplicated strings and cleanup everything with just a single call to
   422 `ucx_mempool_destroy()`.
   424 ### Read CSV data into a structure
   426 The following code example shows some of the basic memory pool functions and
   427 how they can be used with other UCX modules.
   428 ```C
   429 #include <stdio.h>
   430 #include <ucx/mempool.h>
   431 #include <ucx/list.h>
   432 #include <ucx/string.h>
   433 #include <ucx/buffer.h>
   434 #include <ucx/utils.h>
   436 typedef struct {
   437     sstr_t column_a;
   438     sstr_t column_b;
   439     sstr_t column_c;
   440 } CSVData;
   442 int main(int argc, char** argv) {
   444     UcxMempool* pool = ucx_mempool_new(128);
   446     FILE *f = fopen("test.csv", "r");
   447     if (!f) {
   448         perror("Cannot open file");
   449         return 1;
   450     }
   451     /* close the file automatically at pool destruction*/
   452     ucx_mempool_reg_destr(pool, f, (ucx_destructor) fclose);
   454     /* create a buffer and register it at the memory pool for destruction */
   455     UcxBuffer* content = ucx_buffer_new(NULL, 256, UCX_BUFFER_AUTOEXTEND);
   456     ucx_mempool_reg_destr(pool, content, (ucx_destructor) ucx_buffer_free);
   458     /* read the file and split it by lines first */
   459     ucx_stream_copy(f, content, fread, ucx_buffer_write);
   460     sstr_t contentstr = ucx_buffer_to_sstr(content);
   461     ssize_t lc = 0;
   462     sstr_t* lines = sstrsplit_a(pool->allocator, contentstr, S("\n"), &lc);
   464     /* skip the header and parse the remaining data */
   465     UcxList* datalist = NULL;
   466     for (size_t i = 1 ; i < lc ; i++) {
   467         if (lines[i].length == 0) continue;
   468         ssize_t fc = 3;
   469         sstr_t* fields = sstrsplit_a(pool->allocator, lines[i], S(";"), &fc);
   470         if (fc != 3) {
   471             fprintf(stderr, "Syntax error in line %zu.\n", i);
   472             ucx_mempool_destroy(pool);
   473             return 1;
   474         }
   475         CSVData* data = ucx_mempool_malloc(pool, sizeof(CSVData));
   476         data->column_a = fields[0];
   477         data->column_b = fields[1];
   478         data->column_c = fields[2];
   479         datalist = ucx_list_append_a(pool->allocator, datalist, data);
   480     }
   482     /* control output */
   483     UCX_FOREACH(elem, datalist) {
   484         CSVData* data = elem->data;
   485         printf("Column A: %" PRIsstr " | "
   486                "Column B: %" PRIsstr " | "
   487                "Column C: %" PRIsstr "\n",
   488                SFMT(data->column_a), SFMT(data->column_b), SFMT(data->column_c)
   489         );
   490     }
   492     /* cleanup everything, no manual free() needed */
   493     ucx_mempool_destroy(pool);
   495     return 0;
   496 } 
   497 ```
   499 ### Overriding the default destructor
   501 Sometimes you need to allocate memory with `ucx_mempool_malloc()`, but the
   502 memory is not supposed to be freed with a simple call to `free()`.
   503 In this case, you can overwrite the default destructor as follows:
   504 ```C
   505     MyObject* obj = ucx_mempool_malloc(pool, sizeof(MyObject));
   507     /* some special initialization with own resource management */
   508     my_object_init(obj);
   510     /* register destructor function */
   511     ucx_mempool_set_destr(obj, (ucx_destructor) my_object_destroy);
   512 ```
   513 Be aware, that your destructor function should not free any memory, that is
   514 also managed by the pool.
   515 Otherwise you might be risking a double-free.
   516 More precisely, a destructor function set with `ucx_mempool_set_destr()` MUST
   517 NOT call `free()` on the specified pointer whereas a desructor function
   518 registered with `ucx_mempool_reg_destr()` MAY (and in most cases will) call
   519 `free()`.
   521 ## Properties
   523 *Header file:* [properties.h](api/properties_8h.html)  
   524 *Required modules:* [Map](#map)
   526 This module provides load and store function for `*.properties` files.
   527 The key/value pairs are stored within an UCX Map.
   529 ### Example: Loading properties from a file
   531 ```C
   532 /* Open the file as usual */
   533 FILE* file = fopen("myprops.properties", "r");
   534 if (!file) {
   535     // error handling
   536     return 1;
   537 }
   539 /* Load the properties from the file */
   540 UcxMap* myprops = ucx_map_new(16);
   541 if (ucx_properties_load(myprops, file)) {
   542     /* ... error handling ... */
   543     fclose(file);
   544     ucx_map_free(myprops);
   545     return 1;
   546 }
   548 /* Print out the key/value pairs */
   549 char* propval;
   550 UcxMapIterator propiter = ucx_map_iterator(myprops);
   551 UCX_MAP_FOREACH(key, propval, propiter) {
   552     printf("%s = %s\n", (char*)key.data, propval);
   553 }
   555 /* Don't forget to free the values before freeing the map */
   556 ucx_map_free_content(myprops, NULL);
   557 ucx_map_free(myprops);
   558 fclose(file);
   559 ```
   561 ## Stack
   563 *Header file:* [stack.h](api/stack_8h.html)  
   564 *Required modules:* [Allocator](#allocator)
   566 This concrete implementation of an UCX Allocator allows you to grab some amount
   567 of memory which is then handled as a stack.
   568 Please note, that the term *stack* only refers to the behavior of this
   569 allocator. You may still choose to use either stack or heap memory
   570 for the underlying space.
   571 A typical use case is an algorithm where you need to allocate and free large
   572 amounts of memory very frequently.
   574 The following code sample shows how to initialize a stack and push and pop
   575 simple data.
   576 ```C
   577     const size_t len = 1024;
   578     char space[len];
   579     UcxStack stack;
   580     ucx_stack_init(&stack, space, len);
   582     int i = 42;
   583     float f = 3.14f;
   584     const char* str = "Hello!";
   585     size_t strn = 7;
   587     /* push the integer */
   588     ucx_stack_push(&stack, sizeof(int), &i);
   590     /* push the float and rember the address */
   591     float* remember = ucx_stack_push(&stack, sizeof(float), &f);
   593     /* push the string with zero terminator */
   594     ucx_stack_push(&stack, strn, str);
   596     /* if we forget, how big an element was, we can ask the stack */
   597     printf("Length of string: %zu\n", ucx_stack_topsize(&stack)-1);
   599     /* retrieve the string as sstr_t, without zero terminator! */
   600     sstr_t s;
   601     s.length = ucx_stack_topsize(&stack)-1;
   602     s.ptr = malloc(s.length);
   603     ucx_stack_popn(&stack, s.ptr, s.length);
   604     printf("%" PRIsstr "\n", SFMT(s));
   606     /* print the float directly from the stack and free it */
   607     printf("Float: %f\n", *remember);
   608     ucx_stack_free(&stack, remember);
   610     /* the last element is the integer */
   611     int j;
   612     ucx_stack_pop(&stack, &j);
   613     printf("Integer: %d\n", j);
   614 ```
   618 ## String
   620 *Header file:* [string.h](api/string_8h.html)  
   621 *Required modules:* [Allocator](#allocator)
   623 This module provides a safe implementation of bounded string.
   624 Usually C strings do not carry a length. While for zero-terminated strings you
   625 can easily get the length with `strlen`, this is not generally possible for
   626 arbitrary strings.
   627 The `sstr_t` type of this module always carries the string and its length to
   628 reduce the risk of buffer overflows dramatically.
   630 ### Initialization
   632 There are several ways to create an `sstr_t`:
   634 ```C
   635 /* (1) sstr() uses strlen() internally, hence cstr MUST be zero-terminated */
   636 sstr_t a = sstr(cstr);
   638 /* (2) cstr does not need to be zero-terminated, if length is specified */
   639 sstr_t b = sstrn(cstr, len);
   641 /* (3) S() macro creates sstr_t from a string using sizeof() and using sstrn().
   642        This version is especially useful for function arguments */
   643 sstr_t c = S("hello");
   645 /* (4) SC() macro works like S(), but makes the string immutable using scstr_t.
   646        (available since UCX 2.0) */
   647 scstr_t d = SC("hello");
   649 /* (5) ST() macro creates sstr_t struct literal using sizeof() */
   650 sstr_t e = ST("hello");
   651 ```
   653 You should not use the `S()`, `SC()`, or `ST()` macro with string of unknown
   654 origin, since the `sizeof()` call might not coincide with the string length in
   655 those cases. If you know what you are doing, it can save you some performance,
   656 because you do not need the `strlen()` call.
   658 ### Handling immutable strings
   660 *(Since: UCX 2.0)*
   662 For immutable strings (i.e. `const char*` strings), UCX provides the `scstr_t`
   663 type, which works exactly as the `sstr_t` type but with a pointer
   664 to `const char`. All UCX string functions come in two flavors: one that enforces
   665 the `scstr_t` type, and another that usually accepts both types and performs
   666 a conversion automatically, if necessary.
   668 There are some exceptions to this rule, as the return type may depend on the
   669 argument type.
   670 E.g. the `sstrchr()` function returns a substring starting at
   671 the first occurrence of the specified character.
   672 Since this substring points to the memory of the argument string, it does not
   673 accept `scstr_t` as input argument, because the return type would break the
   674 constness.
   677 ### Finding the position of a substring
   679 The `sstrstr()` function gives you a new `sstr_t` object starting with the
   680 requested substring. Thus determining the position comes down to a simple
   681 subtraction.
   683 ```C
   684 sstr_t haystack = ST("Here we go!");
   685 sstr_t needle = ST("we");
   686 sstr_t result = sstrstr(haystack, needle);
   687 if (result.ptr)
   688     printf("Found at position %zd.\n", haystack.length-result.length);
   689 else
   690     printf("Not found.\n");
   691 ```
   693 ### Spliting a string by a delimiter
   695 The `sstrsplit()` function (and its allocator based version `sstrsplit_a()`) is
   696 very powerful and might look a bit nasty at a first glance. But it is indeed
   697 very simple to use. It is even more convenient in combination with a memory
   698 pool.
   700 ```C
   701 sstr_t test = ST("here::are::some::strings");
   702 sstr_t delim = ST("::");
   704 ssize_t count = 0; /* no limit */
   705 UcxMempool* pool = ucx_mempool_new_default();
   707 sstr_t* result = sstrsplit_a(pool->allocator, test, delim, &count);
   708 for (ssize_t i = 0 ; i < count ; i++) {
   709     /* don't forget to specify the length via the %*s format specifier */
   710     printf("%*s\n", result[i].length, result[i].ptr);
   711 }
   713 ucx_mempool_destroy(pool);
   714 ```
   715 The output is:
   717     here
   718     are
   719     some
   720     strings
   722 The memory pool ensures, that all strings are freed.
   724 ### Disabling convenience macros
   726 If you are experiencing any troubles with the short convenience macros `S()`,
   727 `SC()`, or `ST()`, you can disable them by setting the macro
   728 `UCX_NO_SSTR_SHORTCUTS` before including the header (or via a compiler option).
   729 For the formatting macros `SFMT()` and `PRIsstr` you can use the macro
   730 `UCX_NO_SSTR_FORMAT_MACROS` to disable them.
   732 Please keep in mind, that after disabling the macros, you cannot use them in
   733 your code *and* foreign code that you might have included.
   734 You should only disable the macros, if you are experiencing a nasty name clash
   735 which cannot be otherwise resolved.
   737 ## Testing
   739 *Header file:* [test.h](api/test_8h.html)  
   740 *Required modules:* None.
   742 This module provides a testing framework which allows you to execute test cases
   743 within test suites.
   744 To avoid code duplication within tests, we also provide the possibility to
   745 define test subroutines.
   747 You should declare test cases and subroutines in a header file per test unit
   748 and implement them as you would implement normal functions.
   749 ```C
   750     /* myunit.h */
   751     UCX_TEST(function_name);
   752     UCX_TEST_SUBROUTINE(subroutine_name, paramlist); /* optional */
   755     /* myunit.c */
   756     UCX_TEST_SUBROUTINE(subroutine_name, paramlist) {
   757         /* ... reusable tests with UCX_TEST_ASSERT() ... */
   758     }
   760     UCX_TEST(function_name) {
   761         /* ... resource allocation and other test preparation ... */
   763         /* mandatory marker for the start of the tests */
   764         UCX_TEST_BEGIN
   766         /*  ... verifications with UCX_TEST_ASSERT() ...
   767          * (and/or calls with UCX_TEST_CALL_SUBROUTINE())
   768          */
   770         /* mandatory marker for the end of the tests */
   771         UCX_TEST_END
   773         /* ... resource cleanup ...
   774          * (all code after UCX_TEST_END is always executed)
   775          */
   776     }
   777 ```
   778 If you want to use the `UCX_TEST_ASSERT()` macro in a function, you are
   779 *required* to use a `UCX_TEST_SUBROUTINE`.
   780 Otherwise the testing framework does not know where to jump, when the assertion
   781 fails.
   783 After implementing the tests, you can easily build a test suite and execute it:
   784 ```C
   785     UcxTestSuite* suite = ucx_test_suite_new();
   786     ucx_test_register(suite, testMyTestCase01);
   787     ucx_test_register(suite, testMyTestCase02);
   788     /* ... */
   789     ucx_test_run(suite, stdout); /* stdout, or any other FILE stream */
   790 ```
   792 ## Utilities
   794 *Header file:* [utils.h](api/utils_8h.html)  
   795 *Required modules:* [Allocator](#allocator), [String](#string)
   797 In this module we provide very general utility function for copy and compare
   798 operations.
   799 We also provide several `printf` variants to conveniently print formatted data
   800 to streams or strings.
   802 ### A simple copy program
   804 The utilities package provides several stream copy functions.
   805 One of them has a very simple interface and can, for instance, be used to copy
   806 whole files in a single call.
   807 This is a minimal working example:
   808 ```C
   809 #include <stdio.h>
   810 #include <ucx/utils.h>
   812 int main(int argc, char** argv) {
   814     if (argc != 3) {
   815         fprintf(stderr, "Use %s <src> <dest>", argv[0]);
   816         return 1;
   817     }
   819     FILE *srcf = fopen(argv[1], "r");   /* insert error handling on your own */
   820     FILE *destf = fopen(argv[2], "w");
   822     size_t n =  ucx_stream_copy(srcf, destf, fread, fwrite);
   823     printf("%zu bytes copied.\n", n);
   825     fclose(srcf);
   826     fclose(destf);
   829     return 0;
   830 }
   831 ```
   833 ### Automatic allocation for formatted strings
   835 The UCX utility function `ucx_asprintf()` and it's convenient shortcut
   836 `ucx_sprintf` allow easy formatting of strings, without ever having to worry
   837 about the required space.
   838 ```C
   839 sstr_t mystring = ucx_sprintf("The answer is: %d!", 42);
   840 ```
   841 Still, you have to pass `mystring.ptr` to `free()` (or the free function of
   842 your allocator, if you use `ucx_asprintf`).
   843 If you don't have all the information ready to build your string, you can even
   844 use a [UcxBuffer](#buffer) as a target with the utility function
   845 `ucx_bprintf()`.
   846 ```C
   847 UcxBuffer* strbuffer = ucx_buffer_new(NULL, 512, UCX_BUFFER_AUTOEXTEND);
   849 for (unsigned int i = 2 ; i < 100 ; i++) {
   850         ucx_bprintf(strbuffer, "Integer %d is %s\n",
   851                         i, prime(i) ? "prime" : "not prime");
   852 }
   854 /* print the result to stdout */
   855 printf("%s", (char*)strbuffer->space);
   857 ucx_buffer_free(strbuffer);
   858 ```

mercurial