membuf: add membuf_added and membuf_unadd APIs.
[ccan] / ccan / membuf / membuf.h
1 /* MIT (BSD) license - see LICENSE file for details */
2 #ifndef CCAN_MEMBUF_H
3 #define CCAN_MEMBUF_H
4 #include "config.h"
5 #include <assert.h>
6 #include <ccan/tcon/tcon.h>
7
8 /**
9  * struct membuf - representation of a memory buffer.
10  *
11  * It's exposed here to allow you to embed it and so we can inline the
12  * trivial functions.
13  */
14 struct membuf {
15         /* These are the cursors into buf elements */
16         size_t start;
17         size_t end;
18
19         /* Number of elements in buf */
20         size_t max_elems;
21         /* The buffer; at this low-level, untyped. */
22         char *elems;
23
24         void *(*expandfn)(struct membuf *, void *elems, size_t max_elems);
25 };
26
27 /**
28  * MEMBUF - declare a type-specific membuf
29  * @membertype: type for this buffer's values.
30  *
31  * You use this to create your own typed membuf.
32  *
33  * Example:
34  *      MEMBUF(int *) intp_membuf;
35  *      printf("Address of our int * membuf = %p\n", &intp_membuf);
36  */
37 #define MEMBUF(membertype)                                      \
38         TCON_WRAP(struct membuf, membertype canary)
39
40 /**
41  * membuf_init - initialize a type-specfic membuf.
42  * @mb: the MEMBUF() declared membuf.
43  * @elems: the initial buffer, if any.
44  * @max_elems: the initial space @elems, in number of elements.
45  * @expandfn: the function to enlarge buf (eg. membuf_realloc).
46  *
47  * Example:
48  *      membuf_init(&intp_membuf, NULL, 0, membuf_realloc);
49  */
50 #define membuf_init(mb, elems, num, expandfn)                           \
51         membuf_init_(tcon_unwrap(tcon_check_ptr((mb), canary, (elems))), \
52                      (elems), (num), tcon_sizeof((mb), canary), (expandfn))
53
54 void membuf_init_(struct membuf *mb,
55                   void *elems, size_t max_elems, size_t elemsize,
56                   void *(*expandfn)(struct membuf *, void *, size_t));
57
58 /**
59  * membuf_realloc - simple membuf helper to do realloc().
60  *
61  * Assumes initial buffer was NULL, or malloc().
62  */
63 void *membuf_realloc(struct membuf *mb, void *rawelems, size_t newsize);
64
65 /**
66  * membuf_num_elems - number of populated elements in the membuf.
67  * @mb: the MEMBUF() declared membuf.
68  */
69 #define membuf_num_elems(mb) membuf_num_elems_(tcon_unwrap(mb))
70
71 static inline size_t membuf_num_elems_(const struct membuf *mb)
72 {
73         return mb->end - mb->start;
74 }
75
76 /**
77  * membuf_elems - pointer to the populated elements in the membuf.
78  * @mb: the MEMBUF() declared membuf.
79  */
80 #define membuf_elems(mb)                                                \
81         tcon_cast_ptr(mb, canary,                                       \
82                       membuf_elems_(tcon_unwrap(mb), tcon_sizeof((mb), canary)))
83
84 static inline void *membuf_elems_(const struct membuf *mb, size_t elemsize)
85 {
86         return mb->elems + mb->start * elemsize;
87 }
88
89 /**
90  * membuf_consume - we've used up this many membuf_elems.
91  * @mb: the MEMBUF() declared membuf.
92  * @num: the number of elems.
93  *
94  * Returns a pointer to the old start of membuf, so you can mark consumed
95  * and actually process in a single call.
96  */
97 #define membuf_consume(mb, num)                                         \
98         tcon_cast_ptr(mb, canary,                                       \
99                       membuf_consume_(tcon_unwrap(mb), (num),           \
100                                       tcon_sizeof((mb), canary)))
101
102 static inline void *membuf_consume_(struct membuf *mb,
103                                     size_t num, size_t elemsize)
104 {
105         void *old_start = membuf_elems_(mb, elemsize);
106         assert(num <= membuf_num_elems_(mb));
107         mb->start += num;
108
109         return old_start;
110 }
111
112 /**
113  * membuf_num_space - number of unpopulated elements at end of the membuf.
114  * @mb: the MEMBUF() declared membuf.
115  */
116 #define membuf_num_space(mb) membuf_num_space_(tcon_unwrap(mb))
117
118 static inline size_t membuf_num_space_(const struct membuf *mb)
119 {
120         return mb->max_elems - mb->end;
121 }
122
123 /**
124  * membuf_space - pointer to the unpopulated elements at end of membuf.
125  * @mb: the MEMBUF() declared membuf.
126  */
127 #define membuf_space(mb)                                                \
128         tcon_cast_ptr(mb, canary,                                       \
129                       membuf_space_(tcon_unwrap(mb), tcon_sizeof((mb), canary)))
130
131 static inline void *membuf_space_(struct membuf *mb, size_t elemsize)
132 {
133         return mb->elems + mb->end * elemsize;
134 }
135
136 /**
137  * membuf_added - declare that we've added this many elements.
138  * @mb: the MEMBUF() declared membuf.
139  * @n: the number of elements we added (must be < membuf_num_space()).
140  */
141 #define membuf_added(mb, num)                                           \
142         membuf_added_(tcon_unwrap(mb), (num))
143
144 static inline void membuf_added_(struct membuf *mb, size_t num)
145 {
146         assert(num <= membuf_num_space_(mb));
147         mb->end += num;
148 }
149
150 /**
151  * membuf_prepare_space - internal routine to make sure we've got space.
152  * @mb: the MEMBUF() declared membuf.
153  * @num_extra: the minimum number of elements of space we need
154  *
155  * Usually you wouldn't call this yourself; see membuf_add() below.  But
156  * you might use this if you need to know about moves within mb->elements
157  * so you can adjust your own pointers/offsets.
158  *
159  * It returns the offset *in bytes* between the old locations and the new.
160  * This is because it may not be a whole number of elements, in the case
161  * of realloc!
162  *
163  * If you want to check for expandfn failure (which sets errno to
164  * ENOMEM), you can check if membuf_num_space() is < num_extra which will
165  * never otherwise happen.
166  */
167 #define membuf_prepare_space(mb, num_extra)                     \
168         membuf_prepare_space_(tcon_unwrap(mb),                  \
169                               (num_extra),                      \
170                               tcon_sizeof((mb), canary))
171
172 size_t membuf_prepare_space_(struct membuf *mb,
173                              size_t num_extra, size_t elemsize);
174
175 /**
176  * membuf_add - add to the end of the membuf.
177  * @mb: the MEMBUF() declared membuf.
178  * @num: the number of elements (must be that much space available!).
179  *
180  * Returns the pointer to the space just added, in case you want to
181  * populate it afterwards.
182  *
183  * Note that this may invalidate existing buf pointers!  If you want to
184  * avoid that, call membuf_prepare_space(mb, num) first.
185  */
186 #define membuf_add(mb, num)                                             \
187         tcon_cast_ptr(mb, canary,                                       \
188                       membuf_add_(tcon_unwrap(mb), (num),               \
189                                   tcon_sizeof((mb), canary)))
190
191 static inline void *membuf_add_(struct membuf *mb, size_t num, size_t elemsize)
192 {
193         void *oldend;
194         membuf_prepare_space_(mb, num, elemsize);
195
196         oldend = membuf_space_(mb, elemsize);
197         /* We assume expandfn succeeded. */
198         membuf_added_(mb, num);
199
200         return oldend;
201 }
202
203 /**
204  * membuf_unadd - remove this many added elements.
205  * @mb: the MEMBUF() declared membuf.
206  * @n: the number of elements we want to "unadd" (must be < membuf_num_elems()).
207  */
208 #define membuf_unadd(mb, num)                                           \
209         membuf_unadd_(tcon_unwrap(mb), (num))
210
211 static inline void membuf_unadd_(struct membuf *mb, size_t num)
212 {
213         assert(num <= membuf_num_elems_(mb));
214         mb->end -= num;
215 }
216
217 /**
218  * membuf_cleanup - reset membuf, return elems array for freeing.
219  * @mb: the MEMBUF() declared membuf.
220  *
221  * The mb will be empty after this, and crash if you try to expand it.
222  * You can membuf_init() it again, however.
223  *
224  * Example:
225  *      free(membuf_cleanup(&intp_membuf));
226  */
227 #define membuf_cleanup(mb) membuf_cleanup_(tcon_unwrap(mb))
228
229 static inline void *membuf_cleanup_(struct membuf *mb)
230 {
231         mb->start = mb->end = mb->max_elems = 0;
232         mb->expandfn = NULL;
233
234         return mb->elems;
235 }
236 #endif /* CCAN_MEMBUF_H */