1.1 --- a/docs/src/modules.md Mon Dec 30 09:54:10 2019 +0100 1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 1.3 @@ -1,873 +0,0 @@ 1.4 ---- 1.5 -title: Modules 1.6 ---- 1.7 - 1.8 -UCX provides several modules for data structures and algorithms. 1.9 -You may choose to use specific modules by inclueding the corresponding header 1.10 -file. 1.11 -Please note, that some modules make use of other UCX modules. 1.12 -For instance, the [Allocator](#allocator) module is used by many other modules 1.13 -to allow flexible memory allocation. 1.14 -By default the header files are placed into an `ucx` directory within your 1.15 -systems include directory. In this case you can use a module by including it 1.16 -via `#include <ucx/MODULENAME.h>`. 1.17 -Required modules are included automatically. 1.18 - 1.19 -<div id="modules" align="center"> 1.20 - 1.21 ------------------------ ---------------------- -------------------------------- --------------------------- 1.22 -[String](#string) [Buffer](#buffer) 1.23 -[Allocator](#allocator) [Stack](#stack) [Memory Pool](#memory-pool) 1.24 -[Array](#array) [List](#list) [Map](#map) [AVL Tree](#avl-tree) 1.25 -[Logging](#logging) [Testing](#testing) [Utilities](#utilities) [Properties](#properties) 1.26 ------------------------ ---------------------- -------------------------------- --------------------------- 1.27 - 1.28 -</div> 1.29 - 1.30 -## Allocator 1.31 - 1.32 -*Header file:* [allocator.h](api/allocator_8h.html) 1.33 -*Required modules:* None. 1.34 - 1.35 -A UCX allocator consists of a pointer to the memory area / pool and four 1.36 -function pointers to memory management functions operating on this memory 1.37 -area / pool. These functions shall behave equivalent to the standard libc 1.38 -functions `malloc`, `calloc`, `realloc` and `free`. 1.39 - 1.40 -The signature of the memory management functions is based on the signature 1.41 -of the respective libc function but each of them takes the pointer to the 1.42 -memory area / pool as first argument. 1.43 - 1.44 -As the pointer to the memory area / pool can be arbitrarily chosen, any data 1.45 -can be provided to the memory management functions. One example is the 1.46 -[UCX Memory Pool](#memory-pool). 1.47 - 1.48 -## Array 1.49 - 1.50 -*Header file:* [array.h](api/array_8h.html) 1.51 -*Required modules:* [Allocator](#allocator) 1.52 - 1.53 -The UCX Array is an implementation of a dynamic array with automatic 1.54 -reallocation. The array structure contains a capacity, the current size, 1.55 -the size of each element, the raw pointer to the memory area and an allocator. 1.56 -Arrays are in most cases much faster than linked list. 1.57 -One can decide, whether to create a new array on the heap with `ucx_array_new()` 1.58 -or to save one indirection by initializing a `UcxArray` structure on the stack 1.59 -with `ucx_array_init()`. 1.60 - 1.61 -### Remove duplicates from an array of strings 1.62 - 1.63 -The following example shows, how a `UcxArray` can be built with 1.64 -a standard dynamic C array (pointer+length) as basis. 1.65 - 1.66 -```C 1.67 -UcxArray* create_unique(sstr_t* array, size_t arrlen) { 1.68 - // worst case is no duplicates, hence the capacity is set to arrlen 1.69 - UcxArray* result = ucx_array_new(arrlen, sizeof(sstr_t)); 1.70 - // only append elements, if they are not already present in the array 1.71 - for (size_t i = 0 ; i < arrlen ; ++i) { 1.72 - if (!ucx_array_contains(result, array+i, ucx_cmp_sstr, NULL)) { 1.73 - ucx_array_append_from(result, array+i, 1); 1.74 - } 1.75 - } 1.76 - // make the array as small as possible 1.77 - ucx_array_shrink(result); 1.78 - return result; 1.79 -} 1.80 - 1.81 -/* ... */ 1.82 - 1.83 -sstr_t* array = /* some standard array of strings */ 1.84 -size_t arrlen = /* the length of the array */ 1.85 - 1.86 -UcxArray* result = create_unique(array,arrlen); 1.87 - 1.88 -/* Iterate over the array and print the elements */ 1.89 -sstr_t* unique = result->data; 1.90 -for (size_t i = 0 ; i < result->size ; i++) { 1.91 - printf("%" PRIsstr "\n", SFMT(unique[i])); 1.92 -} 1.93 - 1.94 -/* Free the array. */ 1.95 -ucx_array_free(result); 1.96 -``` 1.97 -### Preventing out of bounds writes 1.98 - 1.99 -The functions `ucx_array_reserve()`, `ucx_array_resize()`, `ucx_array_grow()`, 1.100 -and `ucx_array_shrink()` allow easy management of the array capacity. 1.101 -Imagine you want to add `n` elements to an array. If your `n` elements are 1.102 -already somewhere else consecutively in memory, you can use 1.103 -`ucx_array_append_from()` and benefit from the autogrow facility in this family 1.104 -of functions. Otherwise, you can ask the array to have enough capacity for 1.105 -holding additional `n` elements. 1.106 - 1.107 -```C 1.108 -size_t n = // ... elements to add 1.109 -if (ucx_array_grow(array, n)) { 1.110 - fprintf(stderr, "Cannot add %zu elements to the array.\n", n); 1.111 - return 1; 1.112 -} 1.113 -for (size_t i = 0 ; i < n ; i++) { 1.114 - ((int*)array->data)[array->size++] = 80; 1.115 -} 1.116 -``` 1.117 - 1.118 -## AVL Tree 1.119 - 1.120 -*Header file:* [avl.h](api/avl_8h.html) 1.121 -*Required modules:* [Allocator](#allocator) 1.122 - 1.123 -This binary search tree implementation allows average O(1) insertion and 1.124 -removal of elements (excluding binary search time). 1.125 -All common binary tree operations are implemented. Furthermore, this module 1.126 -provides search functions via lower and upper bounds. 1.127 - 1.128 -### Filtering items with a time window 1.129 - 1.130 -Suppose you have a list of items which contain a `time_t` value and your task 1.131 -is to find all items within a time window `[t_start, t_end]`. 1.132 -With AVL Trees this is easy: 1.133 -```C 1.134 -/* --------------------- 1.135 - * Somewhere in a header 1.136 - */ 1.137 -typedef struct { 1.138 - time_t ts; 1.139 - /* other important data */ 1.140 -} MyObject; 1.141 - 1.142 -/* ----------- 1.143 - * Source code 1.144 - */ 1.145 - 1.146 -UcxAVLTree* tree = ucx_avl_new(ucx_cmp_longint); 1.147 -/* ... populate tree with objects, use '& MyObject.ts' as key ... */ 1.148 - 1.149 - 1.150 -/* Now find every item, with 30 <= ts <= 70 */ 1.151 -time_t ts_start = 30; 1.152 -time_t ts_end = 70; 1.153 - 1.154 -printf("Values in range:\n"); 1.155 -for ( 1.156 - UcxAVLNode* node = ucx_avl_find_node( 1.157 - tree, (intptr_t) &ts_start, 1.158 - ucx_dist_longint, UCX_AVL_FIND_LOWER_BOUNDED); 1.159 - node && (*(time_t*)node->key) <= ts_end; 1.160 - node = ucx_avl_succ(node) 1.161 - ) { 1.162 - printf(" ts: %ld\n", ((MyObject*)node->value)->ts); 1.163 -} 1.164 - 1.165 -ucx_avl_free_content(tree, free); 1.166 -ucx_avl_free(tree); 1.167 -``` 1.168 - 1.169 -## Buffer 1.170 - 1.171 -*Header file:* [buffer.h](api/buffer_8h.html) 1.172 -*Required modules:* None. 1.173 - 1.174 -Instances of this buffer implementation can be used to read from or to write to 1.175 -memory like you would do with a stream. This allows the use of 1.176 -`ucx_stream_copy()` from the [Utilities](#utilities) module to copy contents 1.177 -from one buffer to another or from file or network streams to the buffer and 1.178 -vice-versa. 1.179 - 1.180 -More features for convenient use of the buffer can be enabled, like automatic 1.181 -memory management and automatic resizing of the buffer space. 1.182 -See the documentation of the macro constants in the header file for more 1.183 -information. 1.184 - 1.185 -### Add line numbers to a file 1.186 - 1.187 -When reading a file line by line, you have three options: first, you could limit 1.188 -the maximum supported line length. 1.189 -Second, you allocate a god buffer large 1.190 -enough for the most lines a text file could have. 1.191 -And third, undoubtedly the best option, you start with a small buffer, which 1.192 -adjusts on demand. 1.193 -An `UcxBuffer` can be created to do just that for you. 1.194 -Just pass the `UCX_BUFFER_AUTOEXTEND` option to the initialization function. 1.195 -Here is a full working program, which adds line numbers to a file. 1.196 -```C 1.197 -#include <stdio.h> 1.198 -#include <ucx/buffer.h> 1.199 -#include <ucx/utils.h> 1.200 - 1.201 -int main(int argc, char** argv) { 1.202 - 1.203 - if (argc != 2) { 1.204 - fprintf(stderr, "Usage: %s <file>\n", argv[0]); 1.205 - return 1; 1.206 - } 1.207 - 1.208 - FILE* input = fopen(argv[1], "r"); 1.209 - if (!input) { 1.210 - perror("Canno read input"); 1.211 - return 1; 1.212 - } 1.213 - 1.214 - const size_t chunksize = 256; 1.215 - 1.216 - UcxBuffer* linebuf = 1.217 - ucx_buffer_new( 1.218 - NULL, /* the buffer should manage the memory area for us */ 1.219 - 2*chunksize, /* initial size should be twice the chunk size */ 1.220 - UCX_BUFFER_AUTOEXTEND); /* the buffer will grow when necessary */ 1.221 - 1.222 - size_t lineno = 1; 1.223 - do { 1.224 - /* read line chunk */ 1.225 - size_t read = ucx_stream_ncopy( 1.226 - input, linebuf, fread, ucx_buffer_write, chunksize); 1.227 - if (read == 0) break; 1.228 - 1.229 - /* handle line endings */ 1.230 - do { 1.231 - sstr_t bufstr = ucx_buffer_to_sstr(linebuf); 1.232 - sstr_t nl = sstrchr(bufstr, '\n'); 1.233 - if (nl.length == 0) break; 1.234 - 1.235 - size_t linelen = bufstr.length - nl.length; 1.236 - sstr_t linestr = sstrsubsl(bufstr, 0, linelen); 1.237 - 1.238 - printf("%zu: %" PRIsstr "\n", lineno++, SFMT(linestr)); 1.239 - 1.240 - /* shift the buffer to the next line */ 1.241 - ucx_buffer_shift_left(linebuf, linelen+1); 1.242 - } while(1); 1.243 - 1.244 - } while(1); 1.245 - 1.246 - /* print the 'noeol' line, if any */ 1.247 - sstr_t lastline = ucx_buffer_to_sstr(linebuf); 1.248 - if (lastline.length > 0) { 1.249 - printf("%zu: %" PRIsstr, lineno, SFMT(lastline)); 1.250 - } 1.251 - 1.252 - fclose(input); 1.253 - ucx_buffer_free(linebuf); 1.254 - 1.255 - return 0; 1.256 -} 1.257 -``` 1.258 - 1.259 -## List 1.260 - 1.261 -*Header file:* [list.h](api/list_8h.html) 1.262 -*Required modules:* [Allocator](#allocator) 1.263 - 1.264 -This module provides the data structure and several functions for a doubly 1.265 -linked list. Among the common operations like insert, remove, search and sort, 1.266 -we allow convenient iteration via a special `UCX_FOREACH` macro. 1.267 - 1.268 -### Remove duplicates from an array of strings 1.269 - 1.270 -Assume you are given an array of `sstr_t` and want to create a list of these 1.271 -strings without duplicates. 1.272 -This is a similar example to the one [above](#array), but here we are 1.273 -using a `UcxList`. 1.274 -```C 1.275 -#include <stdio.h> 1.276 -#include <ucx/list.h> 1.277 -#include <ucx/string.h> 1.278 -#include <ucx/utils.h> 1.279 - 1.280 -UcxList* remove_duplicates(sstr_t* array, size_t arrlen) { 1.281 - UcxList* list = NULL; 1.282 - for (size_t i = 0 ; i < arrlen ; ++i) { 1.283 - if (ucx_list_find(list, array+i, ucx_cmp_sstr, NULL) == -1) { 1.284 - sstr_t* s = malloc(sizeof(sstr_t)); 1.285 - *s = sstrdup(array[i]); 1.286 - list = ucx_list_append(list, s); 1.287 - } 1.288 - } 1.289 - return list; 1.290 -} 1.291 - 1.292 -/* we will need this function to clean up the list contents later */ 1.293 -void free_sstr(void* ptr) { 1.294 - sstr_t* s = ptr; 1.295 - free(s->ptr); 1.296 - free(s); 1.297 -} 1.298 - 1.299 -/* ... */ 1.300 - 1.301 -sstr_t* array = /* some array of strings */ 1.302 -size_t arrlen = /* the length of the array */ 1.303 - 1.304 -UcxList* list = remove_duplicates(array,arrlen); 1.305 - 1.306 -/* Iterate over the list and print the elements */ 1.307 -UCX_FOREACH(elem, list) { 1.308 - sstr_t s = *((sstr_t*)elem->data); 1.309 - printf("%" PRIsstr "\n", SFMT(s)); 1.310 -} 1.311 - 1.312 -/* Use our free function to free the duplicated strings. */ 1.313 -ucx_list_free_content(list, free_sstr); 1.314 -ucx_list_free(list); 1.315 -``` 1.316 - 1.317 -## Logging 1.318 - 1.319 -*Header file:* [logging.h](api/logging_8h.html) 1.320 -*Required modules:* [Map](#map), [String](#string) 1.321 - 1.322 -The logging module comes with some predefined log levels and allows some more 1.323 -customization. You may choose if you want to get timestamps or source file and 1.324 -line number logged automatically when outputting a message. 1.325 -The following function call initializes a debug logger with all of the above 1.326 -information: 1.327 -```C 1.328 - log = ucx_logger_new(stdout, UCX_LOGGER_DEBUG, 1.329 - UCX_LOGGER_LEVEL | UCX_LOGGER_TIMESTAMP | UCX_LOGGER_SOURCE); 1.330 -``` 1.331 -Afterwards you can use this logger with the predefined macros 1.332 -```C 1.333 - ucx_logger_trace(log, "Verbose output"); 1.334 - ucx_logger_debug(log, "Debug message"); 1.335 - ucx_logger_info(log, "Information"); 1.336 - ucx_logger_warn(log, "Warning"); 1.337 - ucx_logger_error(log, "Error message"); 1.338 -``` 1.339 -or you use 1.340 -```C 1.341 - ucx_logger_log(log, CUSTOM_LEVEL, "Some message") 1.342 -``` 1.343 -When you use your custom log level, don't forget to register it with 1.344 -```C 1.345 - ucx_logger_register_level(log, CUSTOM_LEVEL, "CUSTOM") 1.346 -``` 1.347 -where the last argument must be a string literal. 1.348 - 1.349 -## Map 1.350 - 1.351 -*Header file:* [map.h](api/map_8h.html) 1.352 -*Required modules:* [Allocator](#allocator), [String](#string) 1.353 - 1.354 -This module provides a hash map implementation using murmur hash 2 and separate 1.355 -chaining with linked lists. Similarly to the list module, we provide a 1.356 -`UCX_MAP_FOREACH` macro to conveniently iterate through the key/value pairs. 1.357 - 1.358 -### Parsing command line options 1.359 - 1.360 -Assume you want to parse command line options and record them within a map. 1.361 -One way to do this is shown by the following code sample: 1.362 -```C 1.363 - UcxMap* options = ucx_map_new(16); 1.364 - const char *NOARG = ""; 1.365 - 1.366 - char *option = NULL; 1.367 - char optchar = 0; 1.368 - for(int i=1;i<argc;i++) { 1.369 - char *arg = argv[i]; 1.370 - size_t len = strlen(arg); 1.371 - if(len > 1 && arg[0] == '-') { 1.372 - for(int c=1;c<len;c++) { 1.373 - if(option) { 1.374 - fprintf(stderr, 1.375 - "Missing argument for option -%c\n", optchar); 1.376 - return 1; 1.377 - } 1.378 - switch(arg[c]) { 1.379 - default: { 1.380 - fprintf(stderr, "Unknown option -%c\n\n", arg[c]); 1.381 - return 1; 1.382 - } 1.383 - case 'v': { 1.384 - ucx_map_cstr_put(options, "verbose", NOARG); 1.385 - break; 1.386 - } 1.387 - case 'o': { 1.388 - option = "output"; 1.389 - optchar = 'o'; 1.390 - break; 1.391 - } 1.392 - } 1.393 - } 1.394 - } else if(option) { 1.395 - ucx_map_cstr_put(options, option, arg); 1.396 - option = NULL; 1.397 - } else { 1.398 - /* ... handle argument that is not an option ... */ 1.399 - } 1.400 - } 1.401 - if(option) { 1.402 - fprintf(stderr, 1.403 - "Missing argument for option -%c\n", optchar); 1.404 - return 1; 1.405 - } 1.406 -``` 1.407 -With the following loop, you can access the previously recorded options: 1.408 -```C 1.409 - UcxMapIterator iter = ucx_map_iterator(options); 1.410 - char *arg; 1.411 - UCX_MAP_FOREACH(optkey, arg, iter) { 1.412 - char* opt = optkey.data; 1.413 - if (*arg) { 1.414 - printf("%s = %s\n", opt, arg); 1.415 - } else { 1.416 - printf("%s active\n", opt); 1.417 - } 1.418 - } 1.419 -``` 1.420 -Don't forget to call `ucx_map_free()`, when you are done with the map. 1.421 - 1.422 -## Memory Pool 1.423 - 1.424 -*Header file:* [mempool.h](api/mempool_8h.html) 1.425 -*Required modules:* [Allocator](#allocator) 1.426 - 1.427 -Here we have a concrete allocator implementation in the sense of a memory pool. 1.428 -This pool allows you to register destructor functions for the allocated memory, 1.429 -which are automatically called on the destruction of the pool. 1.430 -But you may also register *independent* destructor functions within a pool in 1.431 -case some external library allocated memory for you, which should be 1.432 -destroyed together with this pool. 1.433 - 1.434 -Many UCX modules support the use of an allocator. 1.435 -The [String Module](#string), for instance, provides the `sstrdup_a()` function, 1.436 -which uses the specified allocator to allocate the memory for the duplicated 1.437 -string. 1.438 -This way, you can use a `UcxMempool` to keep track of the memory occupied by 1.439 -duplicated strings and cleanup everything with just a single call to 1.440 -`ucx_mempool_destroy()`. 1.441 - 1.442 -### Read CSV data into a structure 1.443 - 1.444 -The following code example shows some of the basic memory pool functions and 1.445 -how they can be used with other UCX modules. 1.446 -```C 1.447 -#include <stdio.h> 1.448 -#include <ucx/mempool.h> 1.449 -#include <ucx/list.h> 1.450 -#include <ucx/string.h> 1.451 -#include <ucx/buffer.h> 1.452 -#include <ucx/utils.h> 1.453 - 1.454 -typedef struct { 1.455 - sstr_t column_a; 1.456 - sstr_t column_b; 1.457 - sstr_t column_c; 1.458 -} CSVData; 1.459 - 1.460 -int main(int argc, char** argv) { 1.461 - 1.462 - UcxMempool* pool = ucx_mempool_new(128); 1.463 - 1.464 - FILE *f = fopen("test.csv", "r"); 1.465 - if (!f) { 1.466 - perror("Cannot open file"); 1.467 - return 1; 1.468 - } 1.469 - /* close the file automatically at pool destruction*/ 1.470 - ucx_mempool_reg_destr(pool, f, (ucx_destructor) fclose); 1.471 - 1.472 - /* create a buffer and register it at the memory pool for destruction */ 1.473 - UcxBuffer* content = ucx_buffer_new(NULL, 256, UCX_BUFFER_AUTOEXTEND); 1.474 - ucx_mempool_reg_destr(pool, content, (ucx_destructor) ucx_buffer_free); 1.475 - 1.476 - /* read the file and split it by lines first */ 1.477 - ucx_stream_copy(f, content, fread, ucx_buffer_write); 1.478 - sstr_t contentstr = ucx_buffer_to_sstr(content); 1.479 - ssize_t lc = 0; 1.480 - sstr_t* lines = sstrsplit_a(pool->allocator, contentstr, S("\n"), &lc); 1.481 - 1.482 - /* skip the header and parse the remaining data */ 1.483 - UcxList* datalist = NULL; 1.484 - for (size_t i = 1 ; i < lc ; i++) { 1.485 - if (lines[i].length == 0) continue; 1.486 - ssize_t fc = 3; 1.487 - sstr_t* fields = sstrsplit_a(pool->allocator, lines[i], S(";"), &fc); 1.488 - if (fc != 3) { 1.489 - fprintf(stderr, "Syntax error in line %zu.\n", i); 1.490 - ucx_mempool_destroy(pool); 1.491 - return 1; 1.492 - } 1.493 - CSVData* data = ucx_mempool_malloc(pool, sizeof(CSVData)); 1.494 - data->column_a = fields[0]; 1.495 - data->column_b = fields[1]; 1.496 - data->column_c = fields[2]; 1.497 - datalist = ucx_list_append_a(pool->allocator, datalist, data); 1.498 - } 1.499 - 1.500 - /* control output */ 1.501 - UCX_FOREACH(elem, datalist) { 1.502 - CSVData* data = elem->data; 1.503 - printf("Column A: %" PRIsstr " | " 1.504 - "Column B: %" PRIsstr " | " 1.505 - "Column C: %" PRIsstr "\n", 1.506 - SFMT(data->column_a), SFMT(data->column_b), SFMT(data->column_c) 1.507 - ); 1.508 - } 1.509 - 1.510 - /* cleanup everything, no manual free() needed */ 1.511 - ucx_mempool_destroy(pool); 1.512 - 1.513 - return 0; 1.514 -} 1.515 -``` 1.516 - 1.517 -### Overriding the default destructor 1.518 - 1.519 -Sometimes you need to allocate memory with `ucx_mempool_malloc()`, but the 1.520 -memory is not supposed to be freed with a simple call to `free()`. 1.521 -In this case, you can overwrite the default destructor as follows: 1.522 -```C 1.523 - MyObject* obj = ucx_mempool_malloc(pool, sizeof(MyObject)); 1.524 - 1.525 - /* some special initialization with own resource management */ 1.526 - my_object_init(obj); 1.527 - 1.528 - /* register destructor function */ 1.529 - ucx_mempool_set_destr(obj, (ucx_destructor) my_object_destroy); 1.530 -``` 1.531 -Be aware, that your destructor function should not free any memory, that is 1.532 -also managed by the pool. 1.533 -Otherwise you might be risking a double-free. 1.534 -More precisely, a destructor function set with `ucx_mempool_set_destr()` MUST 1.535 -NOT call `free()` on the specified pointer whereas a desructor function 1.536 -registered with `ucx_mempool_reg_destr()` MAY (and in most cases will) call 1.537 -`free()`. 1.538 - 1.539 -## Properties 1.540 - 1.541 -*Header file:* [properties.h](api/properties_8h.html) 1.542 -*Required modules:* [Map](#map) 1.543 - 1.544 -This module provides load and store function for `*.properties` files. 1.545 -The key/value pairs are stored within an UCX Map. 1.546 - 1.547 -### Example: Loading properties from a file 1.548 - 1.549 -```C 1.550 -/* Open the file as usual */ 1.551 -FILE* file = fopen("myprops.properties", "r"); 1.552 -if (!file) { 1.553 - // error handling 1.554 - return 1; 1.555 -} 1.556 - 1.557 -/* Load the properties from the file */ 1.558 -UcxMap* myprops = ucx_map_new(16); 1.559 -if (ucx_properties_load(myprops, file)) { 1.560 - /* ... error handling ... */ 1.561 - fclose(file); 1.562 - ucx_map_free(myprops); 1.563 - return 1; 1.564 -} 1.565 - 1.566 -/* Print out the key/value pairs */ 1.567 -char* propval; 1.568 -UcxMapIterator propiter = ucx_map_iterator(myprops); 1.569 -UCX_MAP_FOREACH(key, propval, propiter) { 1.570 - printf("%s = %s\n", (char*)key.data, propval); 1.571 -} 1.572 - 1.573 -/* Don't forget to free the values before freeing the map */ 1.574 -ucx_map_free_content(myprops, NULL); 1.575 -ucx_map_free(myprops); 1.576 -fclose(file); 1.577 -``` 1.578 - 1.579 -## Stack 1.580 - 1.581 -*Header file:* [stack.h](api/stack_8h.html) 1.582 -*Required modules:* [Allocator](#allocator) 1.583 - 1.584 -This concrete implementation of an UCX Allocator allows you to grab some amount 1.585 -of memory which is then handled as a stack. 1.586 -Please note, that the term *stack* only refers to the behavior of this 1.587 -allocator. You may still choose to use either stack or heap memory 1.588 -for the underlying space. 1.589 -A typical use case is an algorithm where you need to allocate and free large 1.590 -amounts of memory very frequently. 1.591 - 1.592 -The following code sample shows how to initialize a stack and push and pop 1.593 -simple data. 1.594 -```C 1.595 - const size_t len = 1024; 1.596 - char space[len]; 1.597 - UcxStack stack; 1.598 - ucx_stack_init(&stack, space, len); 1.599 - 1.600 - int i = 42; 1.601 - float f = 3.14f; 1.602 - const char* str = "Hello!"; 1.603 - size_t strn = 7; 1.604 - 1.605 - /* push the integer */ 1.606 - ucx_stack_push(&stack, sizeof(int), &i); 1.607 - 1.608 - /* push the float and rember the address */ 1.609 - float* remember = ucx_stack_push(&stack, sizeof(float), &f); 1.610 - 1.611 - /* push the string with zero terminator */ 1.612 - ucx_stack_push(&stack, strn, str); 1.613 - 1.614 - /* if we forget, how big an element was, we can ask the stack */ 1.615 - printf("Length of string: %zu\n", ucx_stack_topsize(&stack)-1); 1.616 - 1.617 - /* retrieve the string as sstr_t, without zero terminator! */ 1.618 - sstr_t s; 1.619 - s.length = ucx_stack_topsize(&stack)-1; 1.620 - s.ptr = malloc(s.length); 1.621 - ucx_stack_popn(&stack, s.ptr, s.length); 1.622 - printf("%" PRIsstr "\n", SFMT(s)); 1.623 - 1.624 - /* print the float directly from the stack and free it */ 1.625 - printf("Float: %f\n", *remember); 1.626 - ucx_stack_free(&stack, remember); 1.627 - 1.628 - /* the last element is the integer */ 1.629 - int j; 1.630 - ucx_stack_pop(&stack, &j); 1.631 - printf("Integer: %d\n", j); 1.632 -``` 1.633 - 1.634 - 1.635 - 1.636 -## String 1.637 - 1.638 -*Header file:* [string.h](api/string_8h.html) 1.639 -*Required modules:* [Allocator](#allocator) 1.640 - 1.641 -This module provides a safe implementation of bounded string. 1.642 -Usually C strings do not carry a length. While for zero-terminated strings you 1.643 -can easily get the length with `strlen`, this is not generally possible for 1.644 -arbitrary strings. 1.645 -The `sstr_t` type of this module always carries the string and its length to 1.646 -reduce the risk of buffer overflows dramatically. 1.647 - 1.648 -### Initialization 1.649 - 1.650 -There are several ways to create an `sstr_t`: 1.651 - 1.652 -```C 1.653 -/* (1) sstr() uses strlen() internally, hence cstr MUST be zero-terminated */ 1.654 -sstr_t a = sstr(cstr); 1.655 - 1.656 -/* (2) cstr does not need to be zero-terminated, if length is specified */ 1.657 -sstr_t b = sstrn(cstr, len); 1.658 - 1.659 -/* (3) S() macro creates sstr_t from a string using sizeof() and using sstrn(). 1.660 - This version is especially useful for function arguments */ 1.661 -sstr_t c = S("hello"); 1.662 - 1.663 -/* (4) SC() macro works like S(), but makes the string immutable using scstr_t. 1.664 - (available since UCX 2.0) */ 1.665 -scstr_t d = SC("hello"); 1.666 - 1.667 -/* (5) ST() macro creates sstr_t struct literal using sizeof() */ 1.668 -sstr_t e = ST("hello"); 1.669 -``` 1.670 - 1.671 -You should not use the `S()`, `SC()`, or `ST()` macro with string of unknown 1.672 -origin, since the `sizeof()` call might not coincide with the string length in 1.673 -those cases. If you know what you are doing, it can save you some performance, 1.674 -because you do not need the `strlen()` call. 1.675 - 1.676 -### Handling immutable strings 1.677 - 1.678 -*(Since: UCX 2.0)* 1.679 - 1.680 -For immutable strings (i.e. `const char*` strings), UCX provides the `scstr_t` 1.681 -type, which works exactly as the `sstr_t` type but with a pointer 1.682 -to `const char`. All UCX string functions come in two flavors: one that enforces 1.683 -the `scstr_t` type, and another that usually accepts both types and performs 1.684 -a conversion automatically, if necessary. 1.685 - 1.686 -There are some exceptions to this rule, as the return type may depend on the 1.687 -argument type. 1.688 -E.g. the `sstrchr()` function returns a substring starting at 1.689 -the first occurrence of the specified character. 1.690 -Since this substring points to the memory of the argument string, it does not 1.691 -accept `scstr_t` as input argument, because the return type would break the 1.692 -constness. 1.693 - 1.694 - 1.695 -### Finding the position of a substring 1.696 - 1.697 -The `sstrstr()` function gives you a new `sstr_t` object starting with the 1.698 -requested substring. Thus determining the position comes down to a simple 1.699 -subtraction. 1.700 - 1.701 -```C 1.702 -sstr_t haystack = ST("Here we go!"); 1.703 -sstr_t needle = ST("we"); 1.704 -sstr_t result = sstrstr(haystack, needle); 1.705 -if (result.ptr) 1.706 - printf("Found at position %zd.\n", haystack.length-result.length); 1.707 -else 1.708 - printf("Not found.\n"); 1.709 -``` 1.710 - 1.711 -### Spliting a string by a delimiter 1.712 - 1.713 -The `sstrsplit()` function (and its allocator based version `sstrsplit_a()`) is 1.714 -very powerful and might look a bit nasty at a first glance. But it is indeed 1.715 -very simple to use. It is even more convenient in combination with a memory 1.716 -pool. 1.717 - 1.718 -```C 1.719 -sstr_t test = ST("here::are::some::strings"); 1.720 -sstr_t delim = ST("::"); 1.721 - 1.722 -ssize_t count = 0; /* no limit */ 1.723 -UcxMempool* pool = ucx_mempool_new_default(); 1.724 - 1.725 -sstr_t* result = sstrsplit_a(pool->allocator, test, delim, &count); 1.726 -for (ssize_t i = 0 ; i < count ; i++) { 1.727 - /* don't forget to specify the length via the %*s format specifier */ 1.728 - printf("%*s\n", result[i].length, result[i].ptr); 1.729 -} 1.730 - 1.731 -ucx_mempool_destroy(pool); 1.732 -``` 1.733 -The output is: 1.734 - 1.735 - here 1.736 - are 1.737 - some 1.738 - strings 1.739 - 1.740 -The memory pool ensures, that all strings are freed. 1.741 - 1.742 -### Disabling convenience macros 1.743 - 1.744 -If you are experiencing any troubles with the short convenience macros `S()`, 1.745 -`SC()`, or `ST()`, you can disable them by setting the macro 1.746 -`UCX_NO_SSTR_SHORTCUTS` before including the header (or via a compiler option). 1.747 -For the formatting macros `SFMT()` and `PRIsstr` you can use the macro 1.748 -`UCX_NO_SSTR_FORMAT_MACROS` to disable them. 1.749 - 1.750 -Please keep in mind, that after disabling the macros, you cannot use them in 1.751 -your code *and* foreign code that you might have included. 1.752 -You should only disable the macros, if you are experiencing a nasty name clash 1.753 -which cannot be otherwise resolved. 1.754 - 1.755 -## Testing 1.756 - 1.757 -*Header file:* [test.h](api/test_8h.html) 1.758 -*Required modules:* None. 1.759 - 1.760 -This module provides a testing framework which allows you to execute test cases 1.761 -within test suites. 1.762 -To avoid code duplication within tests, we also provide the possibility to 1.763 -define test subroutines. 1.764 - 1.765 -You should declare test cases and subroutines in a header file per test unit 1.766 -and implement them as you would implement normal functions. 1.767 -```C 1.768 - /* myunit.h */ 1.769 - UCX_TEST(function_name); 1.770 - UCX_TEST_SUBROUTINE(subroutine_name, paramlist); /* optional */ 1.771 - 1.772 - 1.773 - /* myunit.c */ 1.774 - UCX_TEST_SUBROUTINE(subroutine_name, paramlist) { 1.775 - /* ... reusable tests with UCX_TEST_ASSERT() ... */ 1.776 - } 1.777 - 1.778 - UCX_TEST(function_name) { 1.779 - /* ... resource allocation and other test preparation ... */ 1.780 - 1.781 - /* mandatory marker for the start of the tests */ 1.782 - UCX_TEST_BEGIN 1.783 - 1.784 - /* ... verifications with UCX_TEST_ASSERT() ... 1.785 - * (and/or calls with UCX_TEST_CALL_SUBROUTINE()) 1.786 - */ 1.787 - 1.788 - /* mandatory marker for the end of the tests */ 1.789 - UCX_TEST_END 1.790 - 1.791 - /* ... resource cleanup ... 1.792 - * (all code after UCX_TEST_END is always executed) 1.793 - */ 1.794 - } 1.795 -``` 1.796 -If you want to use the `UCX_TEST_ASSERT()` macro in a function, you are 1.797 -*required* to use a `UCX_TEST_SUBROUTINE`. 1.798 -Otherwise the testing framework does not know where to jump, when the assertion 1.799 -fails. 1.800 - 1.801 -After implementing the tests, you can easily build a test suite and execute it: 1.802 -```C 1.803 - UcxTestSuite* suite = ucx_test_suite_new(); 1.804 - ucx_test_register(suite, testMyTestCase01); 1.805 - ucx_test_register(suite, testMyTestCase02); 1.806 - /* ... */ 1.807 - ucx_test_run(suite, stdout); /* stdout, or any other FILE stream */ 1.808 -``` 1.809 - 1.810 -## Utilities 1.811 - 1.812 -*Header file:* [utils.h](api/utils_8h.html) 1.813 -*Required modules:* [Allocator](#allocator), [String](#string) 1.814 - 1.815 -In this module we provide very general utility function for copy and compare 1.816 -operations. 1.817 -We also provide several `printf` variants to conveniently print formatted data 1.818 -to streams or strings. 1.819 - 1.820 -### A simple copy program 1.821 - 1.822 -The utilities package provides several stream copy functions. 1.823 -One of them has a very simple interface and can, for instance, be used to copy 1.824 -whole files in a single call. 1.825 -This is a minimal working example: 1.826 -```C 1.827 -#include <stdio.h> 1.828 -#include <ucx/utils.h> 1.829 - 1.830 -int main(int argc, char** argv) { 1.831 - 1.832 - if (argc != 3) { 1.833 - fprintf(stderr, "Use %s <src> <dest>", argv[0]); 1.834 - return 1; 1.835 - } 1.836 - 1.837 - FILE *srcf = fopen(argv[1], "r"); /* insert error handling on your own */ 1.838 - FILE *destf = fopen(argv[2], "w"); 1.839 - 1.840 - size_t n = ucx_stream_copy(srcf, destf, fread, fwrite); 1.841 - printf("%zu bytes copied.\n", n); 1.842 - 1.843 - fclose(srcf); 1.844 - fclose(destf); 1.845 - 1.846 - 1.847 - return 0; 1.848 -} 1.849 -``` 1.850 - 1.851 -### Automatic allocation for formatted strings 1.852 - 1.853 -The UCX utility function `ucx_asprintf()` and it's convenient shortcut 1.854 -`ucx_sprintf` allow easy formatting of strings, without ever having to worry 1.855 -about the required space. 1.856 -```C 1.857 -sstr_t mystring = ucx_sprintf("The answer is: %d!", 42); 1.858 -``` 1.859 -Still, you have to pass `mystring.ptr` to `free()` (or the free function of 1.860 -your allocator, if you use `ucx_asprintf`). 1.861 -If you don't have all the information ready to build your string, you can even 1.862 -use a [UcxBuffer](#buffer) as a target with the utility function 1.863 -`ucx_bprintf()`. 1.864 -```C 1.865 -UcxBuffer* strbuffer = ucx_buffer_new(NULL, 512, UCX_BUFFER_AUTOEXTEND); 1.866 - 1.867 -for (unsigned int i = 2 ; i < 100 ; i++) { 1.868 - ucx_bprintf(strbuffer, "Integer %d is %s\n", 1.869 - i, prime(i) ? "prime" : "not prime"); 1.870 -} 1.871 - 1.872 -/* print the result to stdout */ 1.873 -printf("%s", (char*)strbuffer->space); 1.874 - 1.875 -ucx_buffer_free(strbuffer); 1.876 -```