#ifndef _UCW_ALLOC_H
#define _UCW_ALLOC_H
+/**
+ * This structure describes a generic allocator. It provides pointers
+ * to three functions, which handle the actual (re)allocations.
+ **/
struct ucw_allocator {
void * (*alloc)(struct ucw_allocator *alloc, size_t size);
void * (*realloc)(struct ucw_allocator *alloc, void *ptr, size_t old_size, size_t new_size);
/* alloc-std.c */
+/**
+ * [[std]]
+ * This allocator uses xmalloc(), xrealloc() and xfree(). The memory
+ * it allocates is left unitialized.
+ **/
extern struct ucw_allocator ucw_allocator_std;
+
+/**
+ * [[zeroing]]
+ * This allocator uses xmalloc(), xrealloc() and xfree(). All memory
+ * is zeroed upon allocation.
+ **/
extern struct ucw_allocator ucw_allocator_zeroed;
#endif
DIRS+=ucw/doc
-UCW_DOCS=basics log fastbuf index config configure install basecode hash docsys conf mempool eltpool mainloop generic growbuf unaligned lists chartype unicode prime binsearch heap binheap compress sort hashtable relnotes trans string time daemon signal varint opt
+UCW_DOCS=basics log fastbuf index config configure install basecode hash docsys conf mempool eltpool mainloop generic growbuf unaligned lists chartype unicode prime binsearch heap binheap compress sort hashtable relnotes trans string time daemon signal varint opt alloc gary
UCW_INDEX=$(o)/ucw/doc/def_index.html
UCW_DOCS_HTML=$(addprefix $(o)/ucw/doc/,$(addsuffix .html,$(UCW_DOCS)))
--- /dev/null
+Generic allocators
+==================
+
+Sometimes, we want to define data structures, whose memory allocation can be
+parametrized. If we wish to squeeze out the last bit of performance, we
+tie the structure to a certain allocator in compile time (as we do for
+ <<hashtable:,hash tables>>). If performance is not so critical, allocators
+can be swapped in run time.
+
+This module defines a generic interface to memory allocators. You can use
+the following pre-defined allocators, or define some of your own.
+
+* <<std,Standard malloc-based allocator>>
+* <<zeroing,Zeroing malloc-based allocator>>
+* <<mempool:fun_mp_get_allocator,Memory pools>>
+
+These data structures accept an allocator (more will come later):
+
+* Growing arrays
+
+ucw/alloc.h
+-----------
+
+!!ucw/alloc.h
*Dynamic arrays*::
Similar to static array, but you provide pointer
to pointer to the given item (eg. if you want dynamic array of
- integers, you give `**int`). The parser allocates a growing array
- (see `gary.h`) of the required size.
+ integers, you give `**int`). The parser allocates a <<gary:,growing array>>
+ of the required size.
+
If you want dynamic array of strings, you would use:
+
--- /dev/null
+Growing arrays
+==============
+
+This module provides growing arrays with items of an arbitrary type.
+(Alternatively, you might want to use <<mempool:gbuf,growing mempool buffers>>,
+or the somewhat obsolete <<growbuf:,growing buffers>>.)
+
+From the user's point of view, the array is represented as a pointer to
+its first element, so it can be indexed by the usual `[]` operator. Please
+keep in mind that this pointer can change, whenever the array is resized.
+
+Additional book-keeping information is stored before the first element
+and it can be accessed using the macros below.
+
+ucw/gary.h
+----------
+
+!!ucw/gary.h
Growing buffers
===============
+*This module is obsolete. Please use <<gary:,growing arrays>> instead.*
+
It is quite usual situation when you need an array of items and you
don not know how large it will be in the time you allocate it. Then
you need some kind of dynamically growing buffer.
-You can either use <<mempool:gbuf,mempools>>, which has similar
-functionality, or this module.
-
- <<gbuf,Generic growing buffers>>
- <<bbuf,Growing buffers for byte-sized items>>
- <<conf:,Configuration and command line parser>>
- <<mempool:,Memory pools>>
- <<eltpool:,Fixed-sized allocators>>
+- <<alloc:,Generic allocators>>
- <<mainloop:,Mainloop>>
- <<unaligned:,Unaligned data>>
- <<lists:,Linked lists>>
+- <<gary:,Growing arrays>>
- <<heap:,Binary heaps>>
- <<binheap:,Binomial heaps>>
- <<hashtable:,Hash tables>>
-- <<growbuf:,Growing buffers>>
+- <<growbuf:,Growing buffers>> (obsolete)
- <<chartype:,Single-byte characters>>
- <<unicode:,Multi-byte characters>>
- <<varint:,Encoding of integers>>
Yet undocumented modules
------------------------
-- Allocators
- * `gary.h`
- Trie
* `trie.h`
- Red-black trees
our <<conf:,configuration file parser>>. The <<conf:getopt_h,getopt>> module
has been obsoleted
* `<stdbool.h>` is automatically included by `<ucw/lib.h>`.
-* *Incompatible:* It turned out that almost all users of the growing array
+* *Incompatible:* It turned out that almost all users of the <<gary:,growing array>>
module push/pop individual elements. Therefore, we have removed the second
argument (item count) of `GARY_PUSH` and `GARY_POP`. If you want to push/pop
multiple elements at once, use `GARY_PUSH_MULTI` and `GARY_POP_MULTI`.
operation was renamed to `HEAP_DELETE_MIN`. New operations `HEAP_REPLACE` and
`HEAP_REPLACE_MIN` have been added. If you need to track positions of elements
in the heap, please check the notes at individual functions.
+* <<alloc:,Generic allocators>> have been introduced, providing an abstract
+ way of memory allocation. <<gary:,Growing arrays>> are now based on such
+ allocators, which allows for example growing arrays in memory pools.
* The <<conf:,configuration file parser>> has been improved:
** Multiple instances of the configuration parser are supported.
** *Incompatible:* As there may be more instances, we can no longer use
<<conf:fun_cf_open_group,`cf_open_group()`>>,
<<conf:fun_cf_close_group,`cf_close_group()`>>, and
<<conf:fun_cf_revert,`cf_revert()`>>.
+** *Incompatible:* Dynamic configuration arrays have been re-implemented in
+ terms of our generic <<gary:,growing arrays>>. This makes them easier to
+ use and most of the interface has been preserved. The only exception is
+ static allocation via the DARY_ALLOC() macro, which is no longer available.
* <<daemon:,Daemon helpers>> have been added including a new `daemon-control`
utility. The old `daemon-helper` utility has been obsoleted and it is not
compiled by default.
mechanism for tracking resources and reporting errors. It is still considered
experimental, so the API can change in future releases.
-* Added a growing array module `gary.h`, similar to `gbuf.h`, but with
+* Added a <<gary:,growing array>> module `gary.h`, similar to `gbuf.h`, but with
a much more convenient interface.
* The <<lists:,Circular linked lists>> can recognize unlinked nodes,
#define GARY_HDR(ptr) ((struct gary_hdr *)((byte*)(ptr) - GARY_HDR_SIZE))
#define GARY_BODY(ptr) ((byte *)(ptr) + GARY_HDR_SIZE)
+/**
+ * Create a new growing array, initially containing @n elements,
+ * and let @ptr point to its first element. The memory used by the
+ * array is allocated by xmalloc().
+ **/
#define GARY_INIT(ptr, n) (ptr) = gary_init(sizeof(*(ptr)), (n), &ucw_allocator_std)
+
+/**
+ * Create a growing array like GARY_INIT() does, but all newly
+ * allocated elements will be automatically zeroed.
+ **/
#define GARY_INIT_ZERO(ptr, n) (ptr) = gary_init(sizeof(*(ptr)), (n), &ucw_allocator_zeroed)
+
+/**
+ * Create a growing array like GARY_INIT() does, but based upon the given
+ * <<alloc:,generic allocator>>.
+ **/
#define GARY_INIT_ALLOC(ptr, n, a) (ptr) = gary_init(sizeof(*(ptr)), (n), (a))
+
+/**
+ * Create a growing array, initially containing 0 elements, but with enough
+ * space to keep @n of them without needing reallocation. The @ptr variable
+ * will point to the first element of the array.
+ **/
#define GARY_INIT_SPACE(ptr, n) do { GARY_INIT(ptr, n); (GARY_HDR(ptr))->num_elts = 0; } while (0)
+
+/** A combination of GARY_INIT_ZERO() and GARY_INIT_SPACE(). **/
#define GARY_INIT_SPACE_ZERO(ptr, n) do { GARY_INIT_ZERO(ptr, n); (GARY_HDR(ptr))->num_elts = 0; } while (0)
+
+/** A combination of GARY_INIT_ALLOC() and GARY_INIT_SPACE(). **/
#define GARY_INIT_SPACE_ALLOC(ptr, n, a) do { GARY_INIT_ALLOC(ptr, n, a); (GARY_HDR(ptr))->num_elts = 0; } while (0)
+
+/** Destroy a growing array and free memory used by it. If @ptr is NULL, nothing happens. **/
#define GARY_FREE(ptr) gary_free(ptr)
+
+/** Return the current number elements of the given growing array. **/
#define GARY_SIZE(ptr) (GARY_HDR(ptr)->num_elts)
+
+/**
+ * Resize the given growing array to @n elements.
+ * The @ptr can change, if the array has to be re-allocated.
+ **/
#define GARY_RESIZE(ptr, n) ((ptr) = gary_set_size((ptr), (n)))
-#define GARY_INIT_OR_RESIZE(ptr, n) (ptr) = (ptr) ? gary_set_size((ptr), (n)) : gary_init(sizeof(*(ptr)), (n), 0)
+/** Create a new growing array, or resize it if it already exists. **/
+#define GARY_INIT_OR_RESIZE(ptr, n) (ptr) = (ptr) ? gary_set_size((ptr), (n)) : gary_init(sizeof(*(ptr)), (n), &ucw_allocator_std)
+
+/**
+ * Push @n elements to a growing array. That is, make space for @n more elements
+ * at the end of the array and return a pointer to the first of these elements.
+ * The @ptr can change, if the array has to be re-allocated.
+ **/
#define GARY_PUSH_MULTI(ptr, n) ({ \
struct gary_hdr *_h = GARY_HDR(ptr); \
typeof(*(ptr)) *_c = &(ptr)[_h->num_elts]; \
if (_h->num_elts > _h->have_space) \
(ptr) = gary_push_helper((ptr), _n, (byte **) &_c); \
_c; })
+
+/**
+ * Push a single element at the end of a growing array and return a pointer to it.
+ * The @ptr can change, if the array has to be re-allocated.
+ **/
#define GARY_PUSH(ptr) GARY_PUSH_MULTI(ptr, 1)
+/**
+ * Pop @n elements from the end of a growing array.
+ * The @ptr can change, if the array has to be re-allocated.
+ **/
#define GARY_POP_MULTI(ptr, n) GARY_HDR(ptr)->num_elts -= (n)
+
+/**
+ * Pop a single element from the end of a growing array.
+ * The @ptr can change, if the array has to be re-allocated.
+ **/
#define GARY_POP(ptr) GARY_POP_MULTI(ptr, 1)
+
+/**
+ * Fix size of a growing array, returning all unused memory to the
+ * system (or more precisely, to the underlying allocator).
+ * The @ptr can change.
+ **/
#define GARY_FIX(ptr) (ptr) = gary_fix((ptr))
/* Internal functions */