docs/src/modules.md

Wed, 07 Aug 2019 21:14:58 +0200

author
Mike Becker <universe@uap-core.de>
date
Wed, 07 Aug 2019 21:14:58 +0200
branch
feature/array
changeset 345
6089eb30a51a
parent 340
8acf182f6424
child 359
9f86bc73f96b
permissions
-rw-r--r--

ucx_array_sort() uses qsort_r(), if available

     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 Unlike an [UcxList](#list), the array structure is typically passed by value,
    54 unless it is subjected to change. Arrays are in most cases much faster than
    55 linked list.
    57 ### Remove duplicates from an array of strings
    59 The following example shows, how a `UcxArray` can be built with
    60 a standard dynamic C array (pointer+length) as basis.
    62 ```C
    63 #include <stdio.h>
    64 #include <ucx/array.h>
    65 #include <ucx/string.h>
    66 #include <ucx/utils.h>
    68 UcxArray remove_duplicates(sstr_t* array, size_t arrlen) {
    69     // worst case is no duplicates, hence the capacity is set to arrlen
    70     UcxArray result = ucx_array_new(arrlen, sizeof(sstr_t));
    71     // only append elements, if they are not already present in the array
    72     for (size_t i = 0 ; i < arrlen ; ++i) {
    73         if (!ucx_array_contains(result, array+i, ucx_cmp_sstr, NULL)) {
    74             ucx_array_append(&result, array+i);
    75         }
    76     }
    77     // make the array as small as possible
    78     ucx_array_shrink(&result);
    79     return result;
    80 }
    82 /* ... */
    84 sstr_t* array = /* some standard array of strings */
    85 size_t arrlen = /* the length of the array */
    87 UcxArray result = remove_duplicates(array,arrlen);
    89 /* Iterate over the array and print the elements */
    90 for (size_t i = 0 ; i < result.size ; i++) {
    91     sstr_t s = ucx_array_at_typed(sstr_t, result, i);
    92     printf("%" PRIsstr "\n", SFMT(s));
    93 }
    95 /* Free the array. */
    96 ucx_array_free(&result);
    97 ```
    99 ## AVL Tree
   101 *Header file:* [avl.h](api/avl_8h.html)  
   102 *Required modules:* [Allocator](#allocator)
   104 This binary search tree implementation allows average O(1) insertion and
   105 removal of elements (excluding binary search time).
   106 All common binary tree operations are implemented. Furthermore, this module
   107 provides search functions via lower and upper bounds.
   109 ### Filtering items with a time window
   111 Suppose you have a list of items which contain a `time_t` value and your task
   112 is to find all items within a time window `[t_start, t_end]`.
   113 With AVL Trees this is easy:
   114 ```C
   115 /* ---------------------
   116  * Somewhere in a header
   117  */
   118 typedef struct {
   119     time_t ts;
   120     /* other important data */
   121 } MyObject;
   123 /* -----------
   124  * Source code
   125  */
   127 UcxAVLTree* tree = ucx_avl_new(ucx_cmp_longint);
   128 /* ... populate tree with objects, use '& MyObject.ts' as key ... */
   131 /* Now find every item, with 30 <= ts <= 70 */
   132 time_t ts_start = 30;
   133 time_t ts_end = 70;
   135 printf("Values in range:\n");
   136 for (
   137         UcxAVLNode* node = ucx_avl_find_node(
   138             tree, (intptr_t) &ts_start,
   139             ucx_dist_longint, UCX_AVL_FIND_LOWER_BOUNDED);
   140         node && (*(time_t*)node->key) <= ts_end;
   141         node = ucx_avl_succ(node)
   142     ) {
   143     printf(" ts: %ld\n", ((MyObject*)node->value)->ts);
   144 }
   146 ucx_avl_free_content(tree, free);
   147 ucx_avl_free(tree);
   148 ```
   150 ## Buffer
   152 *Header file:* [buffer.h](api/buffer_8h.html)  
   153 *Required modules:* None.
   155 Instances of this buffer implementation can be used to read from or to write to
   156 memory like you would do with a stream. This allows the use of
   157 `ucx_stream_copy()` from the [Utilities](#utilities) module to copy contents
   158 from one buffer to another or from file or network streams to the buffer and
   159 vice-versa.
   161 More features for convenient use of the buffer can be enabled, like automatic
   162 memory management and automatic resizing of the buffer space.
   163 See the documentation of the macro constants in the header file for more
   164 information.
   166 ### Add line numbers to a file
   168 When reading a file line by line, you have three options: first, you could limit
   169 the maximum supported line length.
   170 Second, you allocate a god buffer large
   171 enough for the most lines a text file could have.
   172 And third, undoubtedly the best option, you start with a small buffer, which
   173 adjusts on demand.
   174 An `UcxBuffer` can be created to do just that for you.
   175 Just pass the `UCX_BUFFER_AUTOEXTEND` option to the initialization function.
   176 Here is a full working program, which adds line numbers to a file.
   177 ```C
   178 #include <stdio.h>
   179 #include <ucx/buffer.h>
   180 #include <ucx/utils.h>
   182 int main(int argc, char** argv) {
   184     if (argc != 2) {
   185         fprintf(stderr, "Usage: %s <file>\n", argv[0]);
   186         return 1;
   187     }
   189     FILE* input = fopen(argv[1], "r");
   190     if (!input) {
   191         perror("Canno read input");
   192         return 1;
   193     }
   195     const size_t chunksize = 256;
   197     UcxBuffer* linebuf =
   198         ucx_buffer_new(
   199             NULL,       /* the buffer should manage the memory area for us */
   200             2*chunksize,  /* initial size should be twice the chunk size */
   201             UCX_BUFFER_AUTOEXTEND); /* the buffer will grow when necessary */
   203     size_t lineno = 1;
   204     do {
   205         /* read line chunk */
   206         size_t read = ucx_stream_ncopy(
   207                 input, linebuf, fread, ucx_buffer_write, chunksize);
   208         if (read == 0) break;
   210         /* handle line endings */
   211         do {
   212             sstr_t bufstr = ucx_buffer_to_sstr(linebuf);
   213             sstr_t nl = sstrchr(bufstr, '\n');
   214             if (nl.length == 0) break;
   216             size_t linelen = bufstr.length - nl.length;
   217             sstr_t linestr = sstrsubsl(bufstr, 0, linelen);
   219             printf("%zu: %" PRIsstr "\n", lineno++, SFMT(linestr));
   221             /* shift the buffer to the next line */
   222             ucx_buffer_shift_left(linebuf, linelen+1);
   223         } while(1);
   225     } while(1);
   227     /* print the 'noeol' line, if any */
   228     sstr_t lastline = ucx_buffer_to_sstr(linebuf);
   229     if (lastline.length > 0) {
   230         printf("%zu: %" PRIsstr, lineno, SFMT(lastline));
   231     }
   233     fclose(input);
   234     ucx_buffer_free(linebuf);
   236     return 0;
   237 }
   238 ```
   240 ## List
   242 *Header file:* [list.h](api/list_8h.html)  
   243 *Required modules:* [Allocator](#allocator)
   245 This module provides the data structure and several functions for a doubly
   246 linked list. Among the common operations like insert, remove, search and sort,
   247 we allow convenient iteration via a special `UCX_FOREACH` macro.
   249 ### Remove duplicates from an array of strings
   251 Assume you are given an array of `sstr_t` and want to create a list of these
   252 strings without duplicates.
   253 This is a similar example to the one [above](#array), but here we are
   254 using a `UcxList`.
   255 ```C
   256 #include <stdio.h>
   257 #include <ucx/list.h>
   258 #include <ucx/string.h>
   259 #include <ucx/utils.h>
   261 UcxList* remove_duplicates(sstr_t* array, size_t arrlen) {
   262     UcxList* list = NULL;
   263     for (size_t i = 0 ; i < arrlen ; ++i) {
   264         if (ucx_list_find(list, array+i, ucx_cmp_sstr, NULL) == -1) {
   265             sstr_t* s = malloc(sizeof(sstr_t));
   266             *s = sstrdup(array[i]);
   267             list = ucx_list_append(list, s);
   268         }
   269     }
   270     return list;
   271 }
   273 /* we will need this function to clean up the list contents later */
   274 void free_sstr(void* ptr) {
   275     sstr_t* s = ptr;
   276     free(s->ptr);
   277     free(s);
   278 }
   280 /* ... */
   282 sstr_t* array = /* some array of strings */
   283 size_t arrlen = /* the length of the array */
   285 UcxList* list = remove_duplicates(array,arrlen);
   287 /* Iterate over the list and print the elements */
   288 UCX_FOREACH(elem, list) {
   289     sstr_t s = *((sstr_t*)elem->data);
   290     printf("%" PRIsstr "\n", SFMT(s));
   291 }
   293 /* Use our free function to free the duplicated strings. */
   294 ucx_list_free_content(list, free_sstr);
   295 ucx_list_free(list);
   296 ```
   298 ## Logging
   300 *Header file:* [logging.h](api/logging_8h.html)  
   301 *Required modules:* [Map](#map), [String](#string)
   303 The logging module comes with some predefined log levels and allows some more
   304 customization. You may choose if you want to get timestamps or source file and
   305 line number logged automatically when outputting a message.
   306 The following function call initializes a debug logger with all of the above
   307 information:
   308 ```C
   309     log = ucx_logger_new(stdout, UCX_LOGGER_DEBUG,
   310             UCX_LOGGER_LEVEL | UCX_LOGGER_TIMESTAMP | UCX_LOGGER_SOURCE);
   311 ```
   312 Afterwards you can use this logger with the predefined macros
   313 ```C
   314     ucx_logger_trace(log, "Verbose output");
   315     ucx_logger_debug(log, "Debug message");
   316     ucx_logger_info(log, "Information");
   317     ucx_logger_warn(log, "Warning");
   318     ucx_logger_error(log, "Error message");
   319 ```
   320 or you use
   321 ```C
   322     ucx_logger_log(log, CUSTOM_LEVEL, "Some message")
   323 ```
   324 When you use your custom log level, don't forget to register it with
   325 ```C
   326     ucx_logger_register_level(log, CUSTOM_LEVEL, "CUSTOM")
   327 ```
   328 where the last argument must be a string literal.
   330 ## Map
   332 *Header file:* [map.h](api/map_8h.html)  
   333 *Required modules:* [Allocator](#allocator), [String](#string)
   335 This module provides a hash map implementation using murmur hash 2 and separate
   336 chaining with linked lists. Similarly to the list module, we provide a
   337 `UCX_MAP_FOREACH` macro to conveniently iterate through the key/value pairs.
   339 ### Parsing command line options
   341 Assume you want to parse command line options and record them within a map.
   342 One way to do this is shown by the following code sample:
   343 ```C
   344     UcxMap* options = ucx_map_new(16);
   345     const char *NOARG = "";
   347     char *option = NULL;
   348     char optchar = 0;
   349     for(int i=1;i<argc;i++) {
   350         char *arg = argv[i];
   351         size_t len = strlen(arg);
   352         if(len > 1 && arg[0] == '-') {
   353             for(int c=1;c<len;c++) {
   354                 if(option) {
   355                     fprintf(stderr,
   356                             "Missing argument for option -%c\n", optchar);
   357                     return 1;
   358                 }
   359                 switch(arg[c]) {
   360                     default: {
   361                         fprintf(stderr, "Unknown option -%c\n\n", arg[c]);
   362                         return 1;
   363                     }
   364                     case 'v': {
   365                         ucx_map_cstr_put(options, "verbose", NOARG);
   366                         break;
   367                     }
   368                     case 'o': {
   369                         option = "output";
   370                         optchar = 'o';
   371                         break;
   372                     }
   373                 }
   374             }
   375         } else if(option) {
   376             ucx_map_cstr_put(options, option, arg);
   377             option = NULL;
   378         } else {
   379             /* ... handle argument that is not an option ... */
   380         }
   381     }
   382     if(option) {
   383         fprintf(stderr,
   384                 "Missing argument for option -%c\n", optchar);
   385         return 1;
   386     }
   387 ```
   388 With the following loop, you can access the previously recorded options:
   389 ```C
   390     UcxMapIterator iter = ucx_map_iterator(options);
   391     char *arg;
   392     UCX_MAP_FOREACH(optkey, arg, iter) {
   393         char* opt = optkey.data;
   394         if (*arg) {
   395             printf("%s = %s\n", opt, arg);
   396         } else {
   397             printf("%s active\n", opt);
   398         }
   399     }
   400 ```
   401 Don't forget to call `ucx_map_free()`, when you are done with the map.
   403 ## Memory Pool
   405 *Header file:* [mempool.h](api/mempool_8h.html)  
   406 *Required modules:* [Allocator](#allocator)
   408 Here we have a concrete allocator implementation in the sense of a memory pool.
   409 This pool allows you to register destructor functions for the allocated memory,
   410 which are automatically called on the destruction of the pool.
   411 But you may also register *independent* destructor functions within a pool in
   412 case some external library allocated memory for you, which should be
   413 destroyed together with this pool.
   415 Many UCX modules support the use of an allocator.
   416 The [String Module](#string), for instance, provides the `sstrdup_a()` function,
   417 which uses the specified allocator to allocate the memory for the duplicated
   418 string.
   419 This way, you can use a `UcxMempool` to keep track of the memory occupied by
   420 duplicated strings and cleanup everything with just a single call to
   421 `ucx_mempool_destroy()`.
   423 ### Read CSV data into a structure
   425 The following code example shows some of the basic memory pool functions and
   426 how they can be used with other UCX modules.
   427 ```C
   428 #include <stdio.h>
   429 #include <ucx/mempool.h>
   430 #include <ucx/list.h>
   431 #include <ucx/string.h>
   432 #include <ucx/buffer.h>
   433 #include <ucx/utils.h>
   435 typedef struct {
   436     sstr_t column_a;
   437     sstr_t column_b;
   438     sstr_t column_c;
   439 } CSVData;
   441 int main(int argc, char** argv) {
   443     UcxMempool* pool = ucx_mempool_new(128);
   445     FILE *f = fopen("test.csv", "r");
   446     if (!f) {
   447         perror("Cannot open file");
   448         return 1;
   449     }
   450     /* close the file automatically at pool destruction*/
   451     ucx_mempool_reg_destr(pool, f, (ucx_destructor) fclose);
   453     /* create a buffer and register it at the memory pool for destruction */
   454     UcxBuffer* content = ucx_buffer_new(NULL, 256, UCX_BUFFER_AUTOEXTEND);
   455     ucx_mempool_reg_destr(pool, content, (ucx_destructor) ucx_buffer_free);
   457     /* read the file and split it by lines first */
   458     ucx_stream_copy(f, content, fread, ucx_buffer_write);
   459     sstr_t contentstr = ucx_buffer_to_sstr(content);
   460     ssize_t lc = 0;
   461     sstr_t* lines = sstrsplit_a(pool->allocator, contentstr, S("\n"), &lc);
   463     /* skip the header and parse the remaining data */
   464     UcxList* datalist = NULL;
   465     for (size_t i = 1 ; i < lc ; i++) {
   466         if (lines[i].length == 0) continue;
   467         ssize_t fc = 3;
   468         sstr_t* fields = sstrsplit_a(pool->allocator, lines[i], S(";"), &fc);
   469         if (fc != 3) {
   470             fprintf(stderr, "Syntax error in line %zu.\n", i);
   471             ucx_mempool_destroy(pool);
   472             return 1;
   473         }
   474         CSVData* data = ucx_mempool_malloc(pool, sizeof(CSVData));
   475         data->column_a = fields[0];
   476         data->column_b = fields[1];
   477         data->column_c = fields[2];
   478         datalist = ucx_list_append_a(pool->allocator, datalist, data);
   479     }
   481     /* control output */
   482     UCX_FOREACH(elem, datalist) {
   483         CSVData* data = elem->data;
   484         printf("Column A: %" PRIsstr " | "
   485                "Column B: %" PRIsstr " | "
   486                "Column C: %" PRIsstr "\n",
   487                SFMT(data->column_a), SFMT(data->column_b), SFMT(data->column_c)
   488         );
   489     }
   491     /* cleanup everything, no manual free() needed */
   492     ucx_mempool_destroy(pool);
   494     return 0;
   495 } 
   496 ```
   498 ### Overriding the default destructor
   500 Sometimes you need to allocate memory with `ucx_mempool_malloc()`, but the
   501 memory is not supposed to be freed with a simple call to `free()`.
   502 In this case, you can overwrite the default destructor as follows:
   503 ```C
   504     MyObject* obj = ucx_mempool_malloc(pool, sizeof(MyObject));
   506     /* some special initialization with own resource management */
   507     my_object_init(obj);
   509     /* register destructor function */
   510     ucx_mempool_set_destr(obj, (ucx_destructor) my_object_destroy);
   511 ```
   512 Be aware, that your destructor function should not free any memory, that is
   513 also managed by the pool.
   514 Otherwise you might be risking a double-free.
   515 More precisely, a destructor function set with `ucx_mempool_set_destr()` MUST
   516 NOT call `free()` on the specified pointer whereas a desructor function
   517 registered with `ucx_mempool_reg_destr()` MAY (and in most cases will) call
   518 `free()`.
   520 ## Properties
   522 *Header file:* [properties.h](api/properties_8h.html)  
   523 *Required modules:* [Map](#map)
   525 This module provides load and store function for `*.properties` files.
   526 The key/value pairs are stored within an UCX Map.
   528 ### Example: Loading properties from a file
   530 ```C
   531 /* Open the file as usual */
   532 FILE* file = fopen("myprops.properties", "r");
   533 if (!file) {
   534     // error handling
   535     return 1;
   536 }
   538 /* Load the properties from the file */
   539 UcxMap* myprops = ucx_map_new(16);
   540 if (ucx_properties_load(myprops, file)) {
   541     /* ... error handling ... */
   542     fclose(file);
   543     ucx_map_free(myprops);
   544     return 1;
   545 }
   547 /* Print out the key/value pairs */
   548 char* propval;
   549 UcxMapIterator propiter = ucx_map_iterator(myprops);
   550 UCX_MAP_FOREACH(key, propval, propiter) {
   551     printf("%s = %s\n", (char*)key.data, propval);
   552 }
   554 /* Don't forget to free the values before freeing the map */
   555 ucx_map_free_content(myprops, NULL);
   556 ucx_map_free(myprops);
   557 fclose(file);
   558 ```
   560 ## Stack
   562 *Header file:* [stack.h](api/stack_8h.html)  
   563 *Required modules:* [Allocator](#allocator)
   565 This concrete implementation of an UCX Allocator allows you to grab some amount
   566 of memory which is then handled as a stack.
   567 Please note, that the term *stack* only refers to the behavior of this
   568 allocator. You may still choose to use either stack or heap memory
   569 for the underlying space.
   570 A typical use case is an algorithm where you need to allocate and free large
   571 amounts of memory very frequently.
   573 The following code sample shows how to initialize a stack and push and pop
   574 simple data.
   575 ```C
   576     const size_t len = 1024;
   577     char space[len];
   578     UcxStack stack;
   579     ucx_stack_init(&stack, space, len);
   581     int i = 42;
   582     float f = 3.14f;
   583     const char* str = "Hello!";
   584     size_t strn = 7;
   586     /* push the integer */
   587     ucx_stack_push(&stack, sizeof(int), &i);
   589     /* push the float and rember the address */
   590     float* remember = ucx_stack_push(&stack, sizeof(float), &f);
   592     /* push the string with zero terminator */
   593     ucx_stack_push(&stack, strn, str);
   595     /* if we forget, how big an element was, we can ask the stack */
   596     printf("Length of string: %zu\n", ucx_stack_topsize(&stack)-1);
   598     /* retrieve the string as sstr_t, without zero terminator! */
   599     sstr_t s;
   600     s.length = ucx_stack_topsize(&stack)-1;
   601     s.ptr = malloc(s.length);
   602     ucx_stack_popn(&stack, s.ptr, s.length);
   603     printf("%" PRIsstr "\n", SFMT(s));
   605     /* print the float directly from the stack and free it */
   606     printf("Float: %f\n", *remember);
   607     ucx_stack_free(&stack, remember);
   609     /* the last element is the integer */
   610     int j;
   611     ucx_stack_pop(&stack, &j);
   612     printf("Integer: %d\n", j);
   613 ```
   617 ## String
   619 *Header file:* [string.h](api/string_8h.html)  
   620 *Required modules:* [Allocator](#allocator)
   622 This module provides a safe implementation of bounded string.
   623 Usually C strings do not carry a length. While for zero-terminated strings you
   624 can easily get the length with `strlen`, this is not generally possible for
   625 arbitrary strings.
   626 The `sstr_t` type of this module always carries the string and its length to
   627 reduce the risk of buffer overflows dramatically.
   629 ### Initialization
   631 There are several ways to create an `sstr_t`:
   633 ```C
   634 /* (1) sstr() uses strlen() internally, hence cstr MUST be zero-terminated */
   635 sstr_t a = sstr(cstr);
   637 /* (2) cstr does not need to be zero-terminated, if length is specified */
   638 sstr_t b = sstrn(cstr, len);
   640 /* (3) S() macro creates sstr_t from a string using sizeof() and using sstrn().
   641        This version is especially useful for function arguments */
   642 sstr_t c = S("hello");
   644 /* (4) SC() macro works like S(), but makes the string immutable using scstr_t.
   645        (available since UCX 2.0) */
   646 scstr_t d = SC("hello");
   648 /* (5) ST() macro creates sstr_t struct literal using sizeof() */
   649 sstr_t e = ST("hello");
   650 ```
   652 You should not use the `S()`, `SC()`, or `ST()` macro with string of unknown
   653 origin, since the `sizeof()` call might not coincide with the string length in
   654 those cases. If you know what you are doing, it can save you some performance,
   655 because you do not need the `strlen()` call.
   657 ### Handling immutable strings
   659 *(Since: UCX 2.0)*
   661 For immutable strings (i.e. `const char*` strings), UCX provides the `scstr_t`
   662 type, which works exactly as the `sstr_t` type but with a pointer
   663 to `const char`. All UCX string functions come in two flavors: one that enforces
   664 the `scstr_t` type, and another that usually accepts both types and performs
   665 a conversion automatically, if necessary.
   667 There are some exceptions to this rule, as the return type may depend on the
   668 argument type.
   669 E.g. the `sstrchr()` function returns a substring starting at
   670 the first occurrence of the specified character.
   671 Since this substring points to the memory of the argument string, it does not
   672 accept `scstr_t` as input argument, because the return type would break the
   673 constness.
   676 ### Finding the position of a substring
   678 The `sstrstr()` function gives you a new `sstr_t` object starting with the
   679 requested substring. Thus determining the position comes down to a simple
   680 subtraction.
   682 ```C
   683 sstr_t haystack = ST("Here we go!");
   684 sstr_t needle = ST("we");
   685 sstr_t result = sstrstr(haystack, needle);
   686 if (result.ptr)
   687     printf("Found at position %zd.\n", haystack.length-result.length);
   688 else
   689     printf("Not found.\n");
   690 ```
   692 ### Spliting a string by a delimiter
   694 The `sstrsplit()` function (and its allocator based version `sstrsplit_a()`) is
   695 very powerful and might look a bit nasty at a first glance. But it is indeed
   696 very simple to use. It is even more convenient in combination with a memory
   697 pool.
   699 ```C
   700 sstr_t test = ST("here::are::some::strings");
   701 sstr_t delim = ST("::");
   703 ssize_t count = 0; /* no limit */
   704 UcxMempool* pool = ucx_mempool_new_default();
   706 sstr_t* result = sstrsplit_a(pool->allocator, test, delim, &count);
   707 for (ssize_t i = 0 ; i < count ; i++) {
   708     /* don't forget to specify the length via the %*s format specifier */
   709     printf("%*s\n", result[i].length, result[i].ptr);
   710 }
   712 ucx_mempool_destroy(pool);
   713 ```
   714 The output is:
   716     here
   717     are
   718     some
   719     strings
   721 The memory pool ensures, that all strings are freed.
   723 ### Disabling convenience macros
   725 If you are experiencing any troubles with the short convenience macros `S()`,
   726 `SC()`, or `ST()`, you can disable them by setting the macro
   727 `UCX_NO_SSTR_SHORTCUTS` before including the header (or via a compiler option).
   728 For the formatting macros `SFMT()` and `PRIsstr` you can use the macro
   729 `UCX_NO_SSTR_FORMAT_MACROS` to disable them.
   731 Please keep in mind, that after disabling the macros, you cannot use them in
   732 your code *and* foreign code that you might have included.
   733 You should only disable the macros, if you are experiencing a nasty name clash
   734 which cannot be otherwise resolved.
   736 ## Testing
   738 *Header file:* [test.h](api/test_8h.html)  
   739 *Required modules:* None.
   741 This module provides a testing framework which allows you to execute test cases
   742 within test suites.
   743 To avoid code duplication within tests, we also provide the possibility to
   744 define test subroutines.
   746 You should declare test cases and subroutines in a header file per test unit
   747 and implement them as you would implement normal functions.
   748 ```C
   749     /* myunit.h */
   750     UCX_TEST(function_name);
   751     UCX_TEST_SUBROUTINE(subroutine_name, paramlist); /* optional */
   754     /* myunit.c */
   755     UCX_TEST_SUBROUTINE(subroutine_name, paramlist) {
   756         /* ... reusable tests with UCX_TEST_ASSERT() ... */
   757     }
   759     UCX_TEST(function_name) {
   760         /* ... resource allocation and other test preparation ... */
   762         /* mandatory marker for the start of the tests */
   763         UCX_TEST_BEGIN
   765         /*  ... verifications with UCX_TEST_ASSERT() ...
   766          * (and/or calls with UCX_TEST_CALL_SUBROUTINE())
   767          */
   769         /* mandatory marker for the end of the tests */
   770         UCX_TEST_END
   772         /* ... resource cleanup ...
   773          * (all code after UCX_TEST_END is always executed)
   774          */
   775     }
   776 ```
   777 If you want to use the `UCX_TEST_ASSERT()` macro in a function, you are
   778 *required* to use a `UCX_TEST_SUBROUTINE`.
   779 Otherwise the testing framework does not know where to jump, when the assertion
   780 fails.
   782 After implementing the tests, you can easily build a test suite and execute it:
   783 ```C
   784     UcxTestSuite* suite = ucx_test_suite_new();
   785     ucx_test_register(suite, testMyTestCase01);
   786     ucx_test_register(suite, testMyTestCase02);
   787     /* ... */
   788     ucx_test_run(suite, stdout); /* stdout, or any other FILE stream */
   789 ```
   791 ## Utilities
   793 *Header file:* [utils.h](api/utils_8h.html)  
   794 *Required modules:* [Allocator](#allocator), [String](#string)
   796 In this module we provide very general utility function for copy and compare
   797 operations.
   798 We also provide several `printf` variants to conveniently print formatted data
   799 to streams or strings.
   801 ### A simple copy program
   803 The utilities package provides several stream copy functions.
   804 One of them has a very simple interface and can, for instance, be used to copy
   805 whole files in a single call.
   806 This is a minimal working example:
   807 ```C
   808 #include <stdio.h>
   809 #include <ucx/utils.h>
   811 int main(int argc, char** argv) {
   813     if (argc != 3) {
   814         fprintf(stderr, "Use %s <src> <dest>", argv[0]);
   815         return 1;
   816     }
   818     FILE *srcf = fopen(argv[1], "r");   /* insert error handling on your own */
   819     FILE *destf = fopen(argv[2], "w");
   821     size_t n =  ucx_stream_copy(srcf, destf, fread, fwrite);
   822     printf("%zu bytes copied.\n", n);
   824     fclose(srcf);
   825     fclose(destf);
   828     return 0;
   829 }
   830 ```
   832 ### Automatic allocation for formatted strings
   834 The UCX utility function `ucx_asprintf()` and it's convenient shortcut
   835 `ucx_sprintf` allow easy formatting of strings, without ever having to worry
   836 about the required space.
   837 ```C
   838 sstr_t mystring = ucx_sprintf("The answer is: %d!", 42);
   839 ```
   840 Still, you have to pass `mystring.ptr` to `free()` (or the free function of
   841 your allocator, if you use `ucx_asprintf`).
   842 If you don't have all the information ready to build your string, you can even
   843 use a [UcxBuffer](#buffer) as a target with the utility function
   844 `ucx_bprintf()`.
   845 ```C
   846 UcxBuffer* strbuffer = ucx_buffer_new(NULL, 512, UCX_BUFFER_AUTOEXTEND);
   848 for (unsigned int i = 2 ; i < 100 ; i++) {
   849         ucx_bprintf(strbuffer, "Integer %d is %s\n",
   850                         i, prime(i) ? "prime" : "not prime");
   851 }
   853 /* print the result to stdout */
   854 printf("%s", (char*)strbuffer->space);
   856 ucx_buffer_free(strbuffer);
   857 ```

mercurial