X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ucw%2Fdoc%2Fmempool.txt;h=456cf1c8757e17563edc05df270d8eefe638eac8;hb=1ddc0f01053b355c5805df3659866e11d50d60d0;hp=4ab8f67563eef98d521a2c1ea06f1bf7bbe5ee6d;hpb=f155e1e206037b53ac10bcfe5fbdbc2aefb3c48c;p=libucw.git diff --git a/ucw/doc/mempool.txt b/ucw/doc/mempool.txt index 4ab8f675..456cf1c8 100644 --- a/ucw/doc/mempool.txt +++ b/ucw/doc/mempool.txt @@ -12,6 +12,112 @@ 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); + }