-
Notifications
You must be signed in to change notification settings - Fork 0
/
buffer.h
128 lines (122 loc) · 3.75 KB
/
buffer.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#ifndef __buffer_h
#define __buffer_h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#define BUFFER_INITIALISER { 0, 0, 0 }
#define DECLARE_BUFFER(TYPE, NAME) \
\
typedef struct \
{ \
TYPE *contents; \
size_t position; \
size_t capacity; \
} NAME; \
\
extern inline NAME *new##NAME(NAME *b) \
{ \
return calloc(1, sizeof(NAME)); \
} \
\
extern inline NAME *NAME##_release(NAME *b) \
{ \
if (b->contents) free(b->contents); \
memset(b, 0, sizeof(NAME)); \
return b; \
} \
\
extern inline void NAME##_delete(NAME *b) \
{ \
NAME##_release(b); \
free(b); \
} \
\
extern inline void NAME##_clear(NAME *b) \
{ \
b->position= 0; \
} \
\
extern inline size_t NAME##_position(NAME *b) \
{ \
return b->position; \
} \
\
extern inline void NAME##_errorBounds(NAME *b, ssize_t index) \
{ \
fprintf(stderr, "index %zi out of bounds for "#NAME" of size %zi\n", index, b->capacity); \
abort(); \
} \
\
extern inline void NAME##_errorMemory(NAME *b) \
{ \
fprintf(stderr, "out of memory typing to grow "#NAME" of size %zi\n", b->capacity); \
abort(); \
} \
\
extern inline TYPE NAME##_get(NAME *b, ssize_t index) \
{ \
if (index >= 0) { \
if (index < b->position) return b->contents[index]; \
} \
else { \
if (b->position + index >= 0) return b->contents[b->position + index]; \
} \
NAME##_errorBounds(b, index); \
abort(); \
/* NOTREACHED */ \
} \
\
extern inline NAME *NAME##_grow(NAME *b, size_t size) \
{ \
if (0 == size) size= 2; \
if (b->capacity < size) { \
b->contents= b->contents \
? realloc(b->contents, sizeof(TYPE) * size) \
: malloc ( sizeof(TYPE) * size); \
if (!b->contents) NAME##_errorMemory(b); \
memset(b->contents + b->capacity, 0, sizeof(TYPE) * (size - b->capacity)); \
b->capacity= size; \
} \
return b; \
} \
\
extern inline TYPE NAME##_append(NAME *b, TYPE value) \
{ \
if (b->position == b->capacity) NAME##_grow(b, b->capacity * 2); \
return b->contents[b->position++]= value; \
} \
\
extern inline void NAME##_appendAll(NAME *b, const TYPE *s, size_t len) \
{ \
while (len--) NAME##_append(b, *s++); \
} \
\
extern inline TYPE *NAME##_buffer(NAME *b) \
{ \
return b->contents; \
}
#define DECLARE_STRING_BUFFER(TYPE, NAME) \
\
DECLARE_BUFFER(TYPE, NAME); \
\
extern inline TYPE *NAME##_appendString(NAME *b, TYPE *string) \
{ \
for (TYPE *ptr= string; *ptr; ++ptr) NAME##_append(b, *string++); \
return string; \
} \
\
extern inline TYPE *NAME##_contents(NAME *b) \
{ \
NAME##_append(b, 0); \
b->position--; \
return b->contents; \
}
#define buffer_do(T, V, B) \
for ( size_t index_of_##V= 0; \
index_of_##V < (B)->position; \
index_of_##V = (B)->position ) \
for ( T V; \
index_of_##V < (B)->position && (V= (B)->contents[index_of_##V], 1); \
++index_of_##V )
#endif // __buffer_h