From c84af708825e4193518880437aec3d0ed48b61d4 Mon Sep 17 00:00:00 2001 From: Michal Vaner Date: Tue, 7 Oct 2008 15:34:37 +0200 Subject: [PATCH] ucw docs: Mempool examples Added three examples of how a mempool can be used: * string trie * rollback an action which may fail * loading whole stdin --- ucw/doc/mempool.txt | 106 ++++++++++++++++++++++++++++++++++++++++++++ ucw/mempool.h | 2 +- 2 files changed, 107 insertions(+), 1 deletion(-) diff --git a/ucw/doc/mempool.txt b/ucw/doc/mempool.txt index e7cbdd73..d3fc4c06 100644 --- a/ucw/doc/mempool.txt +++ b/ucw/doc/mempool.txt @@ -13,5 +13,111 @@ allocated, growing and shrinking the last block and other tricks. * <> * <> * <> +* <> + - <> + - <> + - <> !!ucw/mempool.h + +[[examples]] +Examples +-------- + +You can find few examples of mempools use. But their actual use is +limited only by your fantasy. + +[[ex_trie]] +String trie +~~~~~~~~~~~ + +There are two advantages for a trie to use a mempool. One, it has less +overhead than malloc (with the cost you can not free the blocks one by +one as you allocated them). Second is freeing the whole trie, you do +not need to walk trough it and free each node, you just +<> the whole mempool. + + struct trie_node { + struct trie_node *subs[256]; + bool present; + }; + + struct trie { + struct trie_node root; + struct mempool *pool; + }; + + struct trie *trie_new(void) { + struct mempool *pool = mn_new(4096); + struct trie *result = mp_alloc_zero(pool, sizeof *result); + result->pool = pool; + return result; + } + + void trie_insert_internal(struct trie_node *where, struct mempool *pool, const char *string) { + if(*string) { + if(!where->subs[*string]) + where->subs[*string] = mp_alloc_zero(pool, sizeof *where->subs[*string]); + trie_insert_internal(where->subs[*string], pool, string + 1); + } else { + where->present = 1; + } + } + + void trie_insert(struct trie *trie, const char *string) { + trie_insert_internal(&trie->root, trie->pool, string); + } + + void trie_delete(struct trie *trie) { + mp_delete(trie->pool); //Free everything, including the trie structure + } + +[[ex_try]] +Action which may fail +~~~~~~~~~~~~~~~~~~~~~ + +Imagine a situation where you want to load information from few files. +Loading of each file consists of list of actions, each can allocate +some memory and each can fail. If an action fails, the whole file is +considered invalid, you want to ignore that file and keep loading the +others. + +The problem with memory is you want to return the already allocated +amount for the file which failed. You can use <> of +mempool state. + + void load_file(struct mempool *pool, const char *file) { + struct mempool_state state; + mp_save(pool, &state); // Store the current state + struct file_data *data = mp_alloc_zero(pool, sizeof *data); + if(!( + file_open(file, data, pool) && // Load the file + header_load(data, pool) && + part1_load(data, pool) && + part2_load(data, pool) && + file_close(data) && + data_link(data, pool))) // Link the loaded data into global state + mp_restore(pool, &state); // Failed -> return all used memory + } + +[[ex_stdin]] +Load all data from stdin +~~~~~~~~~~~~~~~~~~~~~~~~ + +You may want to load all data from stdin into a memory buffer. But +there is the problem you do not know how many of them there is. You +may use mempool and it's <> feature. + +This example uses libucw's own IO system, <>. + + void *stdin_data(struct mempool *pool) { + struct fastbuf *fb = bopen_fd(0, NULL); // Read from stdin + uns amount; + char *ptr = mp_start(pool, 1024); + while(amount = bread(fb, ptr, 1024)) { // Read a block + ptr += amount; // Move after it + ptr = mp_spread(pool, ptr, 1024); // Get space for the next block + } + bclose(fb); + return mp_end(pool, ptr); + } diff --git a/ucw/mempool.h b/ucw/mempool.h index 7e4b662d..91da7f98 100644 --- a/ucw/mempool.h +++ b/ucw/mempool.h @@ -73,7 +73,7 @@ struct mempool *mp_new(uns chunk_size); void mp_delete(struct mempool *pool); /** - * Free all data on a memory pool, but leaves it working. + * Frees all data on a memory pool, but leaves it working. * It can keep some of the chunks allocated to serve * further allocation requests. Leaves the @pool alive, * even if it was created with @mp_new(). -- 2.39.2