crypto/shachain/tools: update to new rbuf API.
[ccan] / ccan / membuf / membuf.c
1 /* MIT (BSD) license - see LICENSE file for details */
2 #include <ccan/membuf/membuf.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <stdlib.h>
6
7 void membuf_init_(struct membuf *mb,
8                   void *elems, size_t num_elems, size_t elemsize,
9                   void *(*expandfn)(struct membuf *, void *, size_t))
10 {
11
12         mb->start = mb->end = 0;
13         mb->max_elems = num_elems;
14         mb->elems = elems;
15         mb->expandfn = expandfn;
16 }
17
18 size_t membuf_prepare_space_(struct membuf *mb,
19                              size_t num_extra, size_t elemsize)
20 {
21         char *oldstart = membuf_elems_(mb, elemsize);
22
23         /* Always reset in the trivial empty case. */
24         if (mb->start == mb->end)
25                 mb->start = mb->end = 0;
26         
27         if (membuf_num_space_(mb) >= num_extra)
28                 return 0;
29
30         /* There are two ways to make space: enlarge buffer, and memmove
31          * down.  We use a simple heuristic: if we are using less than half
32          * the buffer, and memmove would get us sufficient space, do that. */
33         if (membuf_num_elems_(mb) <= mb->max_elems / 2
34             && membuf_num_elems_(mb) + num_extra <= mb->max_elems) {
35                 memmove(mb->elems, oldstart, (mb->end - mb->start) * elemsize);
36                 mb->end -= mb->start;
37                 mb->start = 0;
38         } else {
39                 void *expand;
40
41                 /* Since we're going to expand, at least double. */
42                 if (num_extra < mb->max_elems)
43                         num_extra = mb->max_elems;
44
45                 expand = mb->expandfn(mb, mb->elems,
46                                       (mb->max_elems + num_extra) * elemsize);
47                 if (!expand) {
48                         errno = ENOMEM;
49                 } else {
50                         mb->max_elems += num_extra;
51                         mb->elems = expand;
52                 }
53         }
54         return (char *)membuf_elems_(mb, elemsize) - oldstart;
55 }
56
57 void *membuf_realloc(struct membuf *mb, void *rawelems, size_t newsize)
58 {
59         return realloc(rawelems, newsize);
60 }