forked from NLnetLabs/nsd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
buffer.h
516 lines (448 loc) · 11.6 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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
/*
* buffer.h -- generic memory buffer.
*
* Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
*
* See LICENSE for the license.
*
*
* The buffer module implements a generic buffer. The API is based on
* the java.nio.Buffer interface.
*/
#ifndef BUFFER_H
#define BUFFER_H
#include <assert.h>
#include <stdarg.h>
#include <string.h>
#include "region-allocator.h"
#include "util.h"
typedef struct buffer buffer_type;
struct buffer
{
/*
* The current position used for reading/writing.
*/
size_t _position;
/*
* The read/write limit.
*/
size_t _limit;
/*
* The amount of data the buffer can contain.
*/
size_t _capacity;
/*
* The data contained in the buffer.
*/
uint8_t *_data;
/*
* If the buffer is fixed it cannot be resized.
*/
unsigned _fixed : 1;
};
#ifdef NDEBUG
static inline void
buffer_invariant(buffer_type *ATTR_UNUSED(buffer))
{
}
#else
static inline void
buffer_invariant(buffer_type *buffer)
{
assert(buffer);
assert(buffer->_position <= buffer->_limit);
assert(buffer->_limit <= buffer->_capacity);
assert(buffer->_data);
}
#endif
/*
* Create a new buffer with the specified capacity.
*/
buffer_type *buffer_create(region_type *region, size_t capacity);
/*
* Create a buffer with the specified data. The data is not copied
* and no memory allocations are done. The buffer is fixed and cannot
* be resized using buffer_reserve().
*/
void buffer_create_from(buffer_type *buffer, const void *data, size_t size);
/*
* Clear the buffer and make it ready for writing. The buffer's limit
* is set to the capacity and the position is set to 0.
*/
void buffer_clear(buffer_type *buffer);
/*
* Make the buffer ready for reading the data that has been written to
* the buffer. The buffer's limit is set to the current position and
* the position is set to 0.
*/
void buffer_flip(buffer_type *buffer);
/*
* Make the buffer ready for re-reading the data. The buffer's
* position is reset to 0.
*/
void buffer_rewind(buffer_type *buffer);
static inline size_t
buffer_position(buffer_type *buffer)
{
return buffer->_position;
}
/*
* Set the buffer's position to MARK. The position must be less than
* or equal to the buffer's limit.
*/
static inline void
buffer_set_position(buffer_type *buffer, size_t mark)
{
assert(mark <= buffer->_limit);
buffer->_position = mark;
}
/*
* Change the buffer's position by COUNT bytes. The position must not
* be moved behind the buffer's limit or before the beginning of the
* buffer.
*/
static inline void
buffer_skip(buffer_type *buffer, ssize_t count)
{
assert(buffer->_position + count <= buffer->_limit);
buffer->_position += count;
}
static inline size_t
buffer_limit(buffer_type *buffer)
{
return buffer->_limit;
}
/*
* Change the buffer's limit. If the buffer's position is greater
* than the new limit the position is set to the limit.
*/
static inline void
buffer_set_limit(buffer_type *buffer, size_t limit)
{
assert(limit <= buffer->_capacity);
buffer->_limit = limit;
if (buffer->_position > buffer->_limit)
buffer->_position = buffer->_limit;
}
static inline size_t
buffer_capacity(buffer_type *buffer)
{
return buffer->_capacity;
}
/*
* Change the buffer's capacity. The data is reallocated so any
* pointers to the data may become invalid. The buffer's limit is set
* to the buffer's new capacity.
*/
void buffer_set_capacity(buffer_type *buffer, size_t capacity);
/*
* Ensure BUFFER can contain at least AMOUNT more bytes. The buffer's
* capacity is increased if necessary using buffer_set_capacity().
*
* The buffer's limit is always set to the (possibly increased)
* capacity.
*/
void buffer_reserve(buffer_type *buffer, size_t amount);
/*
* Return a pointer to the data at the indicated position.
*/
static inline uint8_t *
buffer_at(buffer_type *buffer, size_t at)
{
assert(at <= buffer->_limit);
return buffer->_data + at;
}
/*
* Return a pointer to the beginning of the buffer (the data at
* position 0).
*/
static inline uint8_t *
buffer_begin(buffer_type *buffer)
{
return buffer_at(buffer, 0);
}
/*
* Return a pointer to the end of the buffer (the data at the buffer's
* limit).
*/
static inline uint8_t *
buffer_end(buffer_type *buffer)
{
return buffer_at(buffer, buffer->_limit);
}
/*
* Return a pointer to the data at the buffer's current position.
*/
static inline uint8_t *
buffer_current(buffer_type *buffer)
{
return buffer_at(buffer, buffer->_position);
}
/*
* The number of bytes remaining between the indicated position and
* the limit.
*/
static inline size_t
buffer_remaining_at(buffer_type *buffer, size_t at)
{
buffer_invariant(buffer);
assert(at <= buffer->_limit);
return buffer->_limit - at;
}
/*
* The number of bytes remaining between the buffer's position and
* limit.
*/
static inline size_t
buffer_remaining(buffer_type *buffer)
{
return buffer_remaining_at(buffer, buffer->_position);
}
/*
* Check if the buffer has at least COUNT more bytes available.
* Before reading or writing the caller needs to ensure enough space
* is available!
*/
static inline int
buffer_available_at(buffer_type *buffer, size_t at, size_t count)
{
return count <= buffer_remaining_at(buffer, at);
}
static inline int
buffer_available(buffer_type *buffer, size_t count)
{
return buffer_available_at(buffer, buffer->_position, count);
}
static inline void
buffer_write_at(buffer_type *buffer, size_t at, const void *data, size_t count)
{
assert(buffer_available_at(buffer, at, count));
memcpy(buffer->_data + at, data, count);
}
static inline void
buffer_write(buffer_type *buffer, const void *data, size_t count)
{
buffer_write_at(buffer, buffer->_position, data, count);
buffer->_position += count;
}
static inline int
try_buffer_write_at(buffer_type *buffer, size_t at, const void *data, size_t count)
{
if(!buffer_available_at(buffer, at, count))
return 0;
memcpy(buffer->_data + at, data, count);
return 1;
}
static inline int
try_buffer_write(buffer_type *buffer, const void *data, size_t count)
{
if(!try_buffer_write_at(buffer, buffer->_position, data, count))
return 0;
buffer->_position += count;
return 1;
}
static inline void
buffer_write_string_at(buffer_type *buffer, size_t at, const char *str)
{
buffer_write_at(buffer, at, str, strlen(str));
}
static inline void
buffer_write_string(buffer_type *buffer, const char *str)
{
buffer_write(buffer, str, strlen(str));
}
static inline int
try_buffer_write_string_at(buffer_type *buffer, size_t at, const char *str)
{
return try_buffer_write_at(buffer, at, str, strlen(str));
}
static inline int
try_buffer_write_string(buffer_type *buffer, const char *str)
{
return try_buffer_write(buffer, str, strlen(str));
}
static inline void
buffer_write_u8_at(buffer_type *buffer, size_t at, uint8_t data)
{
assert(buffer_available_at(buffer, at, sizeof(data)));
buffer->_data[at] = data;
}
static inline void
buffer_write_u8(buffer_type *buffer, uint8_t data)
{
buffer_write_u8_at(buffer, buffer->_position, data);
buffer->_position += sizeof(data);
}
static inline void
buffer_write_u16_at(buffer_type *buffer, size_t at, uint16_t data)
{
assert(buffer_available_at(buffer, at, sizeof(data)));
write_uint16(buffer->_data + at, data);
}
static inline void
buffer_write_u16(buffer_type *buffer, uint16_t data)
{
buffer_write_u16_at(buffer, buffer->_position, data);
buffer->_position += sizeof(data);
}
static inline void
buffer_write_u32_at(buffer_type *buffer, size_t at, uint32_t data)
{
assert(buffer_available_at(buffer, at, sizeof(data)));
write_uint32(buffer->_data + at, data);
}
static inline void
buffer_write_u32(buffer_type *buffer, uint32_t data)
{
buffer_write_u32_at(buffer, buffer->_position, data);
buffer->_position += sizeof(data);
}
static inline void
buffer_write_u64_at(buffer_type *buffer, size_t at, uint64_t data)
{
assert(buffer_available_at(buffer, at, sizeof(data)));
write_uint64(buffer->_data + at, data);
}
static inline void
buffer_write_u64(buffer_type *buffer, uint64_t data)
{
buffer_write_u64_at(buffer, buffer->_position, data);
buffer->_position += sizeof(data);
}
static inline int
try_buffer_write_u8_at(buffer_type *buffer, size_t at, uint8_t data)
{
if(!buffer_available_at(buffer, at, sizeof(data)))
return 0;
buffer->_data[at] = data;
return 1;
}
static inline int
try_buffer_write_u8(buffer_type *buffer, uint8_t data)
{
if(!try_buffer_write_u8_at(buffer, buffer->_position, data))
return 0;
buffer->_position += sizeof(data);
return 1;
}
static inline int
try_buffer_write_u16_at(buffer_type *buffer, size_t at, uint16_t data)
{
if(!buffer_available_at(buffer, at, sizeof(data)))
return 0;
write_uint16(buffer->_data + at, data);
return 1;
}
static inline int
try_buffer_write_u16(buffer_type *buffer, uint16_t data)
{
if(!try_buffer_write_u16_at(buffer, buffer->_position, data))
return 0;
buffer->_position += sizeof(data);
return 1;
}
static inline int
try_buffer_write_u32_at(buffer_type *buffer, size_t at, uint32_t data)
{
if(!buffer_available_at(buffer, at, sizeof(data)))
return 0;
write_uint32(buffer->_data + at, data);
return 1;
}
static inline int
try_buffer_write_u32(buffer_type *buffer, uint32_t data)
{
if(!try_buffer_write_u32_at(buffer, buffer->_position, data))
return 0;
buffer->_position += sizeof(data);
return 1;
}
static inline int
try_buffer_write_u64_at(buffer_type *buffer, size_t at, uint64_t data)
{
if(!buffer_available_at(buffer, at, sizeof(data)))
return 0;
write_uint64(buffer->_data + at, data);
return 1;
}
static inline int
try_buffer_write_u64(buffer_type *buffer, uint64_t data)
{
if(!try_buffer_write_u64_at(buffer, buffer->_position, data))
return 0;
buffer->_position += sizeof(data);
return 1;
}
static inline void
buffer_read_at(buffer_type *buffer, size_t at, void *data, size_t count)
{
assert(buffer_available_at(buffer, at, count));
memcpy(data, buffer->_data + at, count);
}
static inline void
buffer_read(buffer_type *buffer, void *data, size_t count)
{
buffer_read_at(buffer, buffer->_position, data, count);
buffer->_position += count;
}
static inline uint8_t
buffer_read_u8_at(buffer_type *buffer, size_t at)
{
assert(buffer_available_at(buffer, at, sizeof(uint8_t)));
return buffer->_data[at];
}
static inline uint8_t
buffer_read_u8(buffer_type *buffer)
{
uint8_t result = buffer_read_u8_at(buffer, buffer->_position);
buffer->_position += sizeof(uint8_t);
return result;
}
static inline uint16_t
buffer_read_u16_at(buffer_type *buffer, size_t at)
{
assert(buffer_available_at(buffer, at, sizeof(uint16_t)));
return read_uint16(buffer->_data + at);
}
static inline uint16_t
buffer_read_u16(buffer_type *buffer)
{
uint16_t result = buffer_read_u16_at(buffer, buffer->_position);
buffer->_position += sizeof(uint16_t);
return result;
}
static inline uint32_t
buffer_read_u32_at(buffer_type *buffer, size_t at)
{
assert(buffer_available_at(buffer, at, sizeof(uint32_t)));
return read_uint32(buffer->_data + at);
}
static inline uint32_t
buffer_read_u32(buffer_type *buffer)
{
uint32_t result = buffer_read_u32_at(buffer, buffer->_position);
buffer->_position += sizeof(uint32_t);
return result;
}
static inline uint64_t
buffer_read_u64_at(buffer_type *buffer, size_t at)
{
assert(buffer_available_at(buffer, at, sizeof(uint64_t)));
return read_uint64(buffer->_data + at);
}
static inline uint64_t
buffer_read_u64(buffer_type *buffer)
{
uint64_t result = buffer_read_u64_at(buffer, buffer->_position);
buffer->_position += sizeof(uint64_t);
return result;
}
/*
* Print to the buffer, increasing the capacity if required using
* buffer_reserve(). The buffer's position is set to the terminating
* '\0'. Returns the number of characters written (not including the
* terminating '\0').
*/
int buffer_printf(buffer_type *buffer, const char *format, ...)
ATTR_FORMAT(printf, 2, 3);
#endif /* BUFFER_H */