350 |
350 |
351 Here we have a concrete allocator implementation in the sense of a memory pool. |
351 Here we have a concrete allocator implementation in the sense of a memory pool. |
352 This pool allows you to register destructor functions for the allocated memory, |
352 This pool allows you to register destructor functions for the allocated memory, |
353 which are automatically called on the destruction of the pool. |
353 which are automatically called on the destruction of the pool. |
354 But you may also register *independent* destructor functions within a pool in |
354 But you may also register *independent* destructor functions within a pool in |
355 case, some external library allocated memory for you, which you wish to be |
355 case some external library allocated memory for you, which should be |
356 destroyed together with this pool. |
356 destroyed together with this pool. |
|
357 |
|
358 Many UCX modules support the use of an allocator. |
|
359 The [String Module](#string), for instance, provides the `sstrdup_a()` function, |
|
360 which uses the specified allocator to allocate the memory for the duplicated |
|
361 string. |
|
362 This way, you can use a `UcxMempool` to keep track of the memory occupied by |
|
363 duplicated strings and cleanup everything with just a single call to |
|
364 `ucx_mempool_destroy()`. |
|
365 |
|
366 ### Read CSV data into a structure |
|
367 |
|
368 The following code example shows some of the basic memory pool functions and |
|
369 how they can be used with other UCX modules. |
|
370 ```C |
|
371 #include <stdio.h> |
|
372 #include <ucx/mempool.h> |
|
373 #include <ucx/list.h> |
|
374 #include <ucx/string.h> |
|
375 #include <ucx/buffer.h> |
|
376 #include <ucx/utils.h> |
|
377 |
|
378 typedef struct { |
|
379 sstr_t column_a; |
|
380 sstr_t column_b; |
|
381 sstr_t column_c; |
|
382 } CSVData; |
|
383 |
|
384 int main(int argc, char** argv) { |
|
385 |
|
386 UcxMempool* pool = ucx_mempool_new(128); |
|
387 |
|
388 FILE *f = fopen("test.csv", "r"); |
|
389 if (!f) { |
|
390 perror("Cannot open file"); |
|
391 return 1; |
|
392 } |
|
393 /* close the file automatically at pool destruction*/ |
|
394 ucx_mempool_reg_destr(pool, f, (ucx_destructor) fclose); |
|
395 |
|
396 /* create a buffer and register it at the memory pool for destruction */ |
|
397 UcxBuffer* content = ucx_buffer_new(NULL, 256, UCX_BUFFER_AUTOEXTEND); |
|
398 ucx_mempool_reg_destr(pool, content, (ucx_destructor) ucx_buffer_free); |
|
399 |
|
400 /* read the file and split it by lines first */ |
|
401 ucx_stream_copy(f, content, fread, ucx_buffer_write); |
|
402 sstr_t contentstr = ucx_buffer_to_sstr(content); |
|
403 ssize_t lc = 0; |
|
404 sstr_t* lines = sstrsplit_a(pool->allocator, contentstr, S("\n"), &lc); |
|
405 |
|
406 /* skip the header and parse the remaining data */ |
|
407 UcxList* datalist = NULL; |
|
408 for (size_t i = 1 ; i < lc ; i++) { |
|
409 if (lines[i].length == 0) continue; |
|
410 ssize_t fc = 3; |
|
411 sstr_t* fields = sstrsplit_a(pool->allocator, lines[i], S(";"), &fc); |
|
412 if (fc != 3) { |
|
413 fprintf(stderr, "Syntax error in line %zu.\n", i); |
|
414 ucx_mempool_destroy(pool); |
|
415 return 1; |
|
416 } |
|
417 CSVData* data = ucx_mempool_malloc(pool, sizeof(CSVData)); |
|
418 data->column_a = fields[0]; |
|
419 data->column_b = fields[1]; |
|
420 data->column_c = fields[2]; |
|
421 datalist = ucx_list_append_a(pool->allocator, datalist, data); |
|
422 } |
|
423 |
|
424 /* control output */ |
|
425 UCX_FOREACH(elem, datalist) { |
|
426 CSVData* data = elem->data; |
|
427 printf("Column A: %" PRIsstr " | " |
|
428 "Column B: %" PRIsstr " | " |
|
429 "Column C: %" PRIsstr "\n", |
|
430 SFMT(data->column_a), SFMT(data->column_b), SFMT(data->column_c) |
|
431 ); |
|
432 } |
|
433 |
|
434 /* cleanup everything, no manual free() needed */ |
|
435 ucx_mempool_destroy(pool); |
|
436 |
|
437 return 0; |
|
438 } |
|
439 ``` |
|
440 |
|
441 ### Overriding the default destructor |
|
442 |
|
443 Sometimes you need to allocate memory with `ucx_mempool_malloc()`, but the |
|
444 memory is not supposed to be freed with a simple call to `free()`. |
|
445 In this case, you can overwrite the default destructor as follows: |
|
446 ```C |
|
447 MyObject* obj = ucx_mempool_malloc(pool, sizeof(MyObject)); |
|
448 |
|
449 /* some special initialization with own resource management */ |
|
450 my_object_init(obj); |
|
451 |
|
452 /* register destructor function */ |
|
453 ucx_mempool_set_destr(obj, (ucx_destructor) my_object_destroy); |
|
454 ``` |
|
455 But aware, that your destructor function should not free any memory, that is |
|
456 also managed by the pool. |
|
457 Otherwise you might be risking a double-free. |
357 |
458 |
358 ## Properties |
459 ## Properties |
359 |
460 |
360 *Header file:* [properties.h](api/properties_8h.html) |
461 *Header file:* [properties.h](api/properties_8h.html) |
361 *Required modules:* [Map](#map) |
462 *Required modules:* [Map](#map) |