]> mj.ucw.cz Git - libucw.git/blob - ucw/gbuf.h
xtypes: overflow detection updated
[libucw.git] / ucw / gbuf.h
1 /*
2  *      UCW Library -- A simple growing buffer
3  *
4  *      (c) 2004, Robert Spalek <robert@ucw.cz>
5  *      (c) 2005, Martin Mares <mj@ucw.cz>
6  *
7  *      Define the following macros:
8  *
9  *      GBUF_TYPE       data type of records stored in the buffer
10  *      GBUF_PREFIX(x)  add a name prefix to all global symbols
11  *      GBUF_TRACE(msg...) log growing of buffer [optional]
12  *
13  *      This software may be freely distributed and used according to the terms
14  *      of the GNU Lesser General Public License.
15  */
16
17 /**
18  * Type identifier of the buffer.
19  * The macro is not available outside the header file,
20  * but it is used in the definitions of functions.
21  **/
22 #define BUF_T   GBUF_PREFIX(t)
23
24 /**
25  * The growing buffer.
26  * `ptr` holds the memory and `len` is the current
27  * length of available memory.
28  **/
29 typedef struct BUF_T {
30   size_t len;
31   GBUF_TYPE *ptr;
32 } BUF_T;
33
34 /**
35  * Initializes an empty growing buffer in @b.
36  **/
37 static inline void GBUF_PREFIX(init)(BUF_T *b)
38 {
39   b->ptr = NULL;
40   b->len = 0;
41 }
42
43 /**
44  * Frees all memory in the buffer and returns it
45  * to an empty state.
46  **/
47 static void UNUSED GBUF_PREFIX(done)(BUF_T *b)
48 {
49   if (b->ptr)
50     xfree(b->ptr);
51   b->ptr = NULL;
52   b->len = 0;
53 }
54
55 /**
56  * Sets the length of the buffer @b to exactly @len.
57  * Do not use for the growing (you can use this at the end,
58  * when you know the exact size), it would be slow.
59  *
60  * Use <<fun__GENERIC_LINK_|GBUF_PREFIX|grow|,`GBUF_PREFIX(grow)()`>>
61  * for growing.
62  **/
63 static void UNUSED GBUF_PREFIX(set_size)(BUF_T *b, size_t len)
64 {
65   b->len = len;
66   b->ptr = xrealloc(b->ptr, len * sizeof(GBUF_TYPE));
67 #ifdef GBUF_TRACE
68   GBUF_TRACE(STRINGIFY_EXPANDED(BUF_T) " growing to %zu items", len);
69 #endif
70 }
71
72 static void UNUSED GBUF_PREFIX(do_grow)(BUF_T *b, size_t len)
73 {
74   if (len < 2*b->len)                   // to ensure logarithmic cost
75     len = 2*b->len;
76   GBUF_PREFIX(set_size)(b, len);
77 }
78
79 /**
80  * Sets the size of the buffer @b to at last @len.
81  * It grows in exponential manner, to ensure the total cost
82  * of reallocs is linear with the final size.
83  *
84  * You can tweak the final size (when you do not need to grow
85  * any more) by
86  * <<fun__GENERIC_LINK_|GBUF_PREFIX|set_size|,`GBUF_PREFIX(set_size)()`>>.
87  **/
88 static inline GBUF_TYPE *GBUF_PREFIX(grow)(BUF_T *b, size_t len)
89 {
90   if (unlikely(len > b->len))
91     GBUF_PREFIX(do_grow)(b, len);
92   return b->ptr;
93 }
94
95 #undef  GBUF_TYPE
96 #undef  GBUF_PREFIX
97 #undef  GBUF_TRACE
98 #undef  BUF_T