You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
99 lines
2.3 KiB
99 lines
2.3 KiB
2 months ago
|
/*
|
||
|
* UCW Library -- A simple growing buffer
|
||
|
*
|
||
|
* (c) 2004, Robert Spalek <robert@ucw.cz>
|
||
|
* (c) 2005, Martin Mares <mj@ucw.cz>
|
||
|
*
|
||
|
* Define the following macros:
|
||
|
*
|
||
|
* GBUF_TYPE data type of records stored in the buffer
|
||
|
* GBUF_PREFIX(x) add a name prefix to all global symbols
|
||
|
* GBUF_TRACE(msg...) log growing of buffer [optional]
|
||
|
*
|
||
|
* This software may be freely distributed and used according to the terms
|
||
|
* of the GNU Lesser General Public License.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Type identifier of the buffer.
|
||
|
* The macro is not available outside the header file,
|
||
|
* but it is used in the definitions of functions.
|
||
|
**/
|
||
|
#define BUF_T GBUF_PREFIX(t)
|
||
|
|
||
|
/**
|
||
|
* The growing buffer.
|
||
|
* `ptr` holds the memory and `len` is the current
|
||
|
* length of available memory.
|
||
|
**/
|
||
|
typedef struct BUF_T {
|
||
|
size_t len;
|
||
|
GBUF_TYPE *ptr;
|
||
|
} BUF_T;
|
||
|
|
||
|
/**
|
||
|
* Initializes an empty growing buffer in @b.
|
||
|
**/
|
||
|
static inline void GBUF_PREFIX(init)(BUF_T *b)
|
||
|
{
|
||
|
b->ptr = NULL;
|
||
|
b->len = 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Frees all memory in the buffer and returns it
|
||
|
* to an empty state.
|
||
|
**/
|
||
|
static void UNUSED GBUF_PREFIX(done)(BUF_T *b)
|
||
|
{
|
||
|
if (b->ptr)
|
||
|
xfree(b->ptr);
|
||
|
b->ptr = NULL;
|
||
|
b->len = 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the length of the buffer @b to exactly @len.
|
||
|
* Do not use for the growing (you can use this at the end,
|
||
|
* when you know the exact size), it would be slow.
|
||
|
*
|
||
|
* Use <<fun__GENERIC_LINK_|GBUF_PREFIX|grow|,`GBUF_PREFIX(grow)()`>>
|
||
|
* for growing.
|
||
|
**/
|
||
|
static void UNUSED GBUF_PREFIX(set_size)(BUF_T *b, size_t len)
|
||
|
{
|
||
|
b->len = len;
|
||
|
b->ptr = xrealloc(b->ptr, len * sizeof(GBUF_TYPE));
|
||
|
#ifdef GBUF_TRACE
|
||
|
GBUF_TRACE(STRINGIFY_EXPANDED(BUF_T) " growing to %zu items", len);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static void UNUSED GBUF_PREFIX(do_grow)(BUF_T *b, size_t len)
|
||
|
{
|
||
|
if (len < 2*b->len) // to ensure logarithmic cost
|
||
|
len = 2*b->len;
|
||
|
GBUF_PREFIX(set_size)(b, len);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the size of the buffer @b to at last @len.
|
||
|
* It grows in exponential manner, to ensure the total cost
|
||
|
* of reallocs is linear with the final size.
|
||
|
*
|
||
|
* You can tweak the final size (when you do not need to grow
|
||
|
* any more) by
|
||
|
* <<fun__GENERIC_LINK_|GBUF_PREFIX|set_size|,`GBUF_PREFIX(set_size)()`>>.
|
||
|
**/
|
||
|
static inline GBUF_TYPE *GBUF_PREFIX(grow)(BUF_T *b, size_t len)
|
||
|
{
|
||
|
if (unlikely(len > b->len))
|
||
|
GBUF_PREFIX(do_grow)(b, len);
|
||
|
return b->ptr;
|
||
|
}
|
||
|
|
||
|
#undef GBUF_TYPE
|
||
|
#undef GBUF_PREFIX
|
||
|
#undef GBUF_TRACE
|
||
|
#undef BUF_T
|