This repository has been archived by the owner on Sep 1, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
buf.h
99 lines (86 loc) · 3.33 KB
/
buf.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/* buf.h --- growable memory buffers for C99
* This is free and unencumbered software released into the public domain.
*
* buf_size(v) : return the number of elements in the buffer (size_t)
* buf_capacity(v) : return the total capacity of the buffer (size_t)
* buf_free(v) : destroy and free the buffer
* buf_push(v, e) : append an element E to the end
* buf_pop(v) : remove and return an element E from the end
* buf_grow(v, n) : increase buffer capactity by (ptrdiff_t) N elements
* buf_trunc(v, n) : set buffer capactity to exactly (ptrdiff_t) N elements
* buf_clear(v, n) : set buffer size to 0 (for push/pop)
*
* Note: buf_push(), buf_grow(), buf_trunc(), and buf_free() may change
* the buffer pointer, and any previously-taken pointers should be
* considered invalidated.
*
* Example usage:
*
* float *values = 0;
* for (size_t i = 0; i < 25; i++)
* buf_push(values, rand() / (float)RAND_MAX);
* for (size_t i = 0; i < buf_size(values); i++)
* printf("values[%zu] = %f\n", i, values[i]);
* buf_free(values);
*/
#include <stddef.h>
#include <stdlib.h>
#ifndef BUF_INIT_CAPACITY
#define BUF_INIT_CAPACITY 8
#endif
#ifndef BUF_ABORT
#define BUF_ABORT abort()
#endif
struct buf {
size_t capacity;
size_t size;
char buffer[];
};
#define buf_ptr(v) ((struct buf *)((char *)(v)-offsetof(struct buf, buffer)))
#define buf_free(v) \
do { \
if (v) { \
free(buf_ptr((v))); \
(v) = 0; \
} \
} while (0)
#define buf_size(v) ((v) ? buf_ptr((v))->size : 0)
#define buf_capacity(v) ((v) ? buf_ptr((v))->capacity : 0)
#define buf_push(v, e) \
do { \
if (buf_capacity((v)) == buf_size((v))) { \
(v) = buf_grow1( \
v, sizeof(*(v)), \
(ptrdiff_t)(!buf_capacity((v)) ? BUF_INIT_CAPACITY \
: buf_capacity((v)))); \
} \
(v)[buf_ptr((v))->size++] = (e); \
} while (0)
#define buf_pop(v) ((v)[--buf_ptr(v)->size])
#define buf_grow(v, n) ((v) = buf_grow1((v), sizeof(*(v)), n))
#define buf_trunc(v, n) \
((v) = buf_grow1((v), sizeof(*(v)), n - buf_capacity(v)))
#define buf_clear(v) ((v) ? (buf_ptr((v))->size = 0) : 0)
static void *buf_grow1(void *v, size_t esize, ptrdiff_t n) {
struct buf *p;
size_t max = (size_t)-1 - sizeof(struct buf);
if (v) {
p = buf_ptr(v);
if (n > 0 && p->capacity + (size_t)n > max / esize)
goto fail; /* overflow */
p = realloc(p, sizeof(struct buf) + esize * (p->capacity + (size_t)n));
if (!p) goto fail;
p->capacity += (size_t)n;
if (p->size > p->capacity) p->size = p->capacity;
} else {
if ((size_t)n > max / esize) goto fail; /* overflow */
p = malloc(sizeof(struct buf) + esize * (size_t)n);
if (!p) goto fail;
p->capacity = (size_t)n;
p->size = 0;
}
return p->buffer;
fail:
BUF_ABORT;
return 0;
}