docs/src/modules.md

Fri, 11 May 2018 18:46:31 +0200

author
Mike Becker <universe@uap-core.de>
date
Fri, 11 May 2018 18:46:31 +0200
changeset 294
bfa935ab7f85
parent 290
d5d6ab809ad3
child 295
7fc65395188e
permissions
-rw-r--r--

example code for the usage of a UcxList

     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 [Allocator](#allocator) [AVL&nbsp;Tree](#avl-tree)  [Buffer](#buffer)                [List](#list)
    20 [Logging](#logging)     [Map](#map)                 [Memory&nbsp;Pool](#memory-pool) [Properties](#properties)
    21 [Stack](#stack)         [String](#string)           [Testing](#testing)              [Utilities](#utilities)
    22 ----------------------- ----------------------      ----------------------------     -------------------------
    24 </div>
    26 ## Allocator
    28 *Header file:* [allocator.h](api/allocator_8h.html)  
    29 *Required modules:* None.
    31 A UCX allocator consists of a pointer to the memory area / pool and four
    32 function pointers to memory management functions operating on this memory
    33 area / pool. These functions shall behave equivalent to the standard libc
    34 functions `malloc`, `calloc`, `realloc` and `free`.
    36 The signature of the memory management functions is based on the signature
    37 of the respective libc function but each of them takes the pointer to the
    38 memory area / pool as first argument.
    40 As the pointer to the memory area / pool can be arbitrarily chosen, any data
    41 can be provided to the memory management functions. One example is the
    42 [UCX Memory Pool](#memory-pool).
    44 ## AVL Tree
    46 *Header file:* [avl.h](api/avl_8h.html)  
    47 *Required modules:* [Allocator](#allocator)
    49 This binary search tree implementation allows average O(1) insertion and
    50 removal of elements (excluding binary search time).
    51 All common binary tree operations are implemented. Furthermore, this module
    52 provides search functions via lower and upper bounds.
    54 ### Filtering items with a time window
    56 Suppose you have a list of items which contain a `time_t` value and your task
    57 is to find all items within a time window `[t_start, t_end]`.
    58 With AVL Trees this is easy:
    59 ```C
    60 /* ---------------------
    61  * Somewhere in a header
    62  */
    63 typedef struct {
    64     time_t ts;
    65     /* other important data */
    66 } MyObject;
    68 /* -----------
    69  * Source code
    70  */
    72 UcxAVLTree* tree = ucx_avl_new(ucx_longintcmp);
    73 /* ... populate tree with objects, use '& MyObject.ts' as key ... */
    76 /* Now find every item, with 30 <= ts <= 70 */
    77 time_t ts_start = 30;
    78 time_t ts_end = 70;
    80 printf("Values in range:\n");
    81 for (
    82         UcxAVLNode* node = ucx_avl_find_node(
    83             tree, (intptr_t) &ts_start,
    84             ucx_longintdist, UCX_AVL_FIND_LOWER_BOUNDED);
    85         node && (*(time_t*)node->key) <= ts_end;
    86         node = ucx_avl_succ(node)
    87     ) {
    88     printf(" ts: %ld\n", ((MyObject*)node->value)->ts);
    89 }
    91 ucx_avl_free_content(tree, free);
    92 ucx_avl_free(tree);
    93 ```
    95 ## Buffer
    97 *Header file:* [buffer.h](api/buffer_8h.html)  
    98 *Required modules:* None.
   100 Instances of this buffer implementation can be used to read from or to write to
   101 memory like you would do with a stream. This allows the use of
   102 `ucx_stream_copy()` from the [Utilities](#utilities) module to copy contents
   103 from one buffer to another or from file or network streams to the buffer and
   104 vice-versa.
   106 More features for convenient use of the buffer can be enabled, like automatic
   107 memory management and automatic resizing of the buffer space.
   108 See the documentation of the macro constants in the header file for more
   109 information.
   111 ### Add line numbers to a file
   113 When reading a file line by line, you have three options: first, you could limit
   114 the maximum supported line length.
   115 Second, you allocate a god buffer large
   116 enough for the most lines a text file could have.
   117 And third, undoubtedly the best option, you start with a small buffer, which
   118 adjusts on demand.
   119 An `UcxBuffer` can be created to do just that for you.
   120 Just pass the `UCX_BUFFER_AUTOEXTEND` option to the initialization function.
   121 Here is a full working program, which adds line numbers to a file.
   122 ```C
   123 #include <stdio.h>
   124 #include <ucx/buffer.h>
   125 #include <ucx/utils.h>
   127 int main(int argc, char** argv) {
   129     if (argc != 2) {
   130         fprintf(stderr, "Usage: %s <file>\n", argv[0]);
   131         return 1;
   132     }
   134     FILE* input = fopen(argv[1], "r");
   135     if (!input) {
   136         perror("Canno read input");
   137         return 1;
   138     }
   140     const size_t chunksize = 256;
   142     UcxBuffer* linebuf =
   143         ucx_buffer_new(
   144             NULL,       /* the buffer should manage the memory area for us */
   145             2*chunksize,  /* initial size should be twice the chunk size */
   146             UCX_BUFFER_AUTOEXTEND); /* the buffer will grow when necessary */
   148     size_t lineno = 1;
   149     do {
   150         /* read line chunk */
   151         size_t read = ucx_stream_ncopy(
   152                 input, linebuf, fread, ucx_buffer_write, chunksize);
   153         if (read == 0) break;
   155         /* handle line endings */
   156         do {
   157             sstr_t bufstr = ucx_buffer_to_sstr(linebuf);
   158             sstr_t nl = sstrchr(bufstr, '\n');
   159             if (nl.length == 0) break;
   161             size_t linelen = bufstr.length - nl.length;
   162             sstr_t linestr = sstrsubsl(bufstr, 0, linelen);
   164             printf("%zu: %" PRIsstr "\n", lineno++, SFMT(linestr));
   166             /* shift the buffer to the next line */
   167             ucx_buffer_shift_left(linebuf, linelen+1);
   168         } while(1);
   170     } while(1);
   172     /* print the 'noeol' line, if any */
   173     sstr_t lastline = ucx_buffer_to_sstr(linebuf);
   174     if (lastline.length > 0) {
   175         printf("%zu: %" PRIsstr, lineno, SFMT(lastline));
   176     }
   178     fclose(input);
   179     ucx_buffer_free(linebuf);
   181     return 0;
   182 }
   183 ```
   185 ## List
   187 *Header file:* [list.h](api/list_8h.html)  
   188 *Required modules:* [Allocator](#allocator)
   190 This module provides the data structure and several functions for a doubly
   191 linked list. Among the common operations like insert, remove, search and sort,
   192 we allow convenient iteration via a special `UCX_FOREACH` macro.
   194 ### Remove duplicates from an array of strings
   196 Assume you are given an array of `sstr_t` and want to create a list of these
   197 strings without duplicates.
   198 ```C
   199 #include <stdio.h>
   200 #include <ucx/list.h>
   201 #include <ucx/string.h>
   202 #include <ucx/utils.h>
   204 UcxList* remove_duplicates(sstr_t* array, size_t arrlen) {
   205     UcxList* list = NULL;
   206     for (size_t i = 0 ; i < arrlen ; ++i) {
   207         if (ucx_list_find(list, array+i, ucx_sstrcmp, NULL) == -1) {
   208             sstr_t* s = malloc(sizeof(sstr_t));
   209             *s = sstrdup(array[i]);
   210             list = ucx_list_append(list, s);
   211         }
   212     }
   213     return list;
   214 }
   216 /* we will need this function to clean up the list contents later */
   217 void free_sstr(void* ptr) {
   218     sstr_t* s = ptr;
   219     free(s->ptr);
   220     free(s);
   221 }
   223 /* ... */
   225 sstr_t* array = /* some array of strings */
   226 size_t arrlen = /* the length of the array */
   228 UcxList* list = remove_duplicates(array,arrlen);
   230 /* Iterate over the list and print the elements */
   231 UCX_FOREACH(elem, list) {
   232     sstr_t s = *((sstr_t*)elem->data);
   233     printf("%" PRIsstr "\n", SFMT(s));
   234 }
   236 /* Use our free function to free the duplicated strings. */
   237 ucx_list_free_content(list, free_sstr);
   238 ucx_list_free(list);
   239 ```
   241 ## Logging
   243 *Header file:* [logging.h](api/logging_8h.html)  
   244 *Required modules:* [Map](#map), [String](#string)
   246 The logging module comes with some predefined log levels and allows some more
   247 customization. You may choose if you want to get timestamps or source file and
   248 line number logged automatically when outputting a message.
   251 ## Map
   253 *Header file:* [map.h](api/map_8h.html)  
   254 *Required modules:* [Allocator](#allocator), [String](#string)
   256 This module provides a hash map implementation using murmur hash 2 and separate
   257 chaining with linked lists. Similarly to the list module, we provide a
   258 `UCX_MAP_FOREACH` macro to conveniently iterate through the key/value pairs.
   260 ## Memory Pool
   262 *Header file:* [mempool.h](api/mempool_8h.html)  
   263 *Required modules:* [Allocator](#allocator)
   265 Here we have a concrete allocator implementation in the sense of a memory pool.
   266 This pool allows you to register destructor functions for the allocated memory,
   267 which are automatically called on the destruction of the pool.
   268 But you may also register *independent* destructor functions within a pool in
   269 case, some external library allocated memory for you, which you wish to be
   270 destroyed together with this pool.
   272 ## Properties
   274 *Header file:* [properties.h](api/properties_8h.html)  
   275 *Required modules:* [Map](#map)
   277 This module provides load and store function for `*.properties` files.
   278 The key/value pairs are stored within an UCX Map.
   280 ### Example: Loading properties from a file
   282 ```C
   283 /* Open the file as usual */
   284 FILE* file = fopen("myprops.properties", "r");
   285 if (!file) {
   286     // error handling
   287     return 1;
   288 }
   290 /* Load the properties from the file */
   291 UcxMap* myprops = ucx_map_new(16);
   292 if (ucx_properties_load(myprops, file)) {
   293     /* ... error handling ... */
   294     fclose(file);
   295     ucx_map_free(myprops);
   296     return 1;
   297 }
   299 /* Print out the key/value pairs */
   300 char* propval;
   301 UcxMapIterator propiter = ucx_map_iterator(myprops);
   302 UCX_MAP_FOREACH(key, propval, propiter) {
   303     printf("%s = %s\n", (char*)key.data, propval);
   304 }
   306 /* Don't forget to free the values before freeing the map */
   307 ucx_map_free_content(myprops, NULL);
   308 ucx_map_free(myprops);
   309 fclose(file);
   310 ```
   311 ## Stack
   313 *Header file:* [stack.h](api/stack_8h.html)  
   314 *Required modules:* [Allocator](#allocator)
   316 This concrete implementation of an UCX Allocator allows you to grab some amount
   317 of memory which is then handled as a stack.
   318 Please note, that the term *stack* only refers to the behavior of this
   319 allocator. You may still choose if you want to use stack or heap memory
   320 for the underlying space.
   322 A typical use case is an algorithm where you need to allocate and free large
   323 amounts of memory very frequently.
   325 ## String
   327 *Header file:* [string.h](api/string_8h.html)  
   328 *Required modules:* [Allocator](#allocator)
   330 This module provides a safe implementation of bounded string.
   331 Usually C strings do not carry a length. While for zero-terminated strings you
   332 can easily get the length with `strlen`, this is not generally possible for
   333 arbitrary strings.
   334 The `sstr_t` type of this module always carries the string and its length to
   335 reduce the risk of buffer overflows dramatically.
   337 ### Initialization
   339 There are several ways to create an `sstr_t`:
   341 ```C
   342 /* (1) sstr() uses strlen() internally, hence cstr MUST be zero-terminated */
   343 sstr_t a = sstr(cstr);
   345 /* (2) cstr does not need to be zero-terminated, if length is specified */
   346 sstr_t b = sstrn(cstr, len);
   348 /* (3) S() macro creates sstr_t from a string using sizeof() and using sstrn().
   349        This version is especially useful for function arguments */
   350 sstr_t c = S("hello");
   352 /* (4) ST() macro creates sstr_t struct literal using sizeof() */
   353 sstr_t d = ST("hello");
   354 ```
   356 You should not use the `S()` or `ST()` macro with string of unknown origin,
   357 since the `sizeof()` call might not coincide with the string length in those
   358 cases. If you know what you are doing, it can save you some performance,
   359 because you do not need the `strlen()` call.
   361 ### Finding the position of a substring
   363 The `sstrstr()` function gives you a new `sstr_t` object starting with the
   364 requested substring. Thus determining the position comes down to a simple
   365 subtraction.
   367 ```C
   368 sstr_t haystack = ST("Here we go!");
   369 sstr_t needle = ST("we");
   370 sstr_t result = sstrstr(haystack, needle);
   371 if (result.ptr)
   372     printf("Found at position %zd.\n", haystack.length-result.length);
   373 else
   374     printf("Not found.\n");
   375 ```
   377 ### Spliting a string by a delimiter
   379 The `sstrsplit()` function (and its allocator based version `sstrsplit_a()`) is
   380 very powerful and might look a bit nasty at a first glance. But it is indeed
   381 very simple to use. It is even more convenient in combination with a memory
   382 pool.
   384 ```C
   385 sstr_t test = ST("here::are::some::strings");
   386 sstr_t delim = ST("::");
   388 ssize_t count = 0; /* no limit */
   389 UcxMempool* pool = ucx_mempool_new_default();
   391 sstr_t* result = sstrsplit_a(pool->allocator, test, delim, &count);
   392 for (ssize_t i = 0 ; i < count ; i++) {
   393     /* don't forget to specify the length via the %*s format specifier */
   394     printf("%*s\n", result[i].length, result[i].ptr);
   395 }
   397 ucx_mempool_destroy(pool);
   398 ```
   399 The output is:
   401     here
   402     are
   403     some
   404     strings
   406 The memory pool ensures, that all strings are freed.
   408 ## Testing
   410 *Header file:* [test.h](api/test_8h.html)  
   411 *Required modules:* None.
   413 This module provides a testing framework which allows you to execute test cases
   414 within test suites.
   415 To avoid code duplication within tests, we also provide the possibility to
   416 define test subroutines.
   418 ## Utilities
   420 *Header file:* [utils.h](api/utils_8h.html)  
   421 *Required modules:* [Allocator](#allocator), [String](#string)
   423 In this module we provide very general utility function for copy and compare
   424 operations.
   425 We also provide several `printf` variants to conveniently print formatted data
   426 to streams or strings.
   428 ### A simple copy program
   430 The utilities package provides several stream copy functions.
   431 One of them has a very simple interface and can, for instance, be used to copy
   432 whole files in a single call.
   433 This is a minimal working example:
   434 ```C
   435 #include <stdio.h>
   436 #include <ucx/utils.h>
   438 int main(int argc, char** argv) {
   440     if (argc != 3) {
   441         fprintf(stderr, "Use %s <src> <dest>", argv[0]);
   442         return 1;
   443     }
   445     FILE *srcf = fopen(argv[1], "r");   /* insert error handling on your own */
   446     FILE *destf = fopen(argv[2], "w");
   448     size_t n =  ucx_stream_copy(srcf, destf, fread, fwrite);
   449     printf("%zu bytes copied.\n", n);
   451     fclose(srcf);
   452     fclose(destf);
   455     return 0;
   456 }
   457 ```
   459 ### Automatic allocation for formatted strings
   461 The UCX utility function `ucx_asprintf()` and it's convenient shortcut
   462 `ucx_sprintf` allow easy formatting of strings, without ever having to worry
   463 about the required space.
   464 ```C
   465 sstr_t mystring = ucx_sprintf("The answer is: %d!", 42);
   466 ```
   467 Still, you have to pass `mystring.ptr` to `free()` (or the free function of
   468 your allocator, if you use `ucx_asprintf`).
   469 If you don't have all the information ready to build your string, you can even
   470 use a [UcxBuffer](#buffer) as a target with the utility function
   471 `ucx_bprintf()`.
   472 ```C
   473 UcxBuffer* strbuffer = ucx_buffer_new(NULL, 512, UCX_BUFFER_AUTOEXTEND);
   475 for (unsigned int i = 2 ; i < 100 ; i++) {
   476         ucx_bprintf(strbuffer, "Integer %d is %s\n",
   477                         i, prime(i) ? "prime" : "not prime");
   478 }
   480 /* print the result to stdout */
   481 printf("%s", (char*)strbuffer->space);
   483 ucx_buffer_free(strbuffer);
   484 ```

mercurial