Derive-C
Loading...
Searching...
No Matches
template.h
Go to the documentation of this file.
1
3
5#if !defined(SKIP_INCLUDES)
6 #include "includes.h"
7#endif
8
9#if !defined _GNU_SOURCE
10 #error "the gnu source macro must be defined to use cookie io"
11#endif
12
15
16typedef struct {
17 FILE* stream;
18 char* buf;
20 size_t capacity;
21 NS(ALLOC, ref) alloc_ref;
22} SELF;
23
24static size_t const NS(SELF, additional_alloc_size) = 32;
25
26#define INVARIANT_CHECK(self) \
27 DC_ASSUME(self); \
28 DC_ASSUME(DC_WHEN((self)->buf, (self)->stream && (self)->capacity > 0)); \
29 DC_ASSUME(DC_WHEN((self)->capacity == 0, !(self)->buf)); \
30 DC_ASSUME(DC_WHEN((self)->buf, (self)->size_without_null + 1 <= (self)->capacity));
31
32static ssize_t PRIV(NS(SELF, read))(void* capture,
33 char* buf /*NOLINT(readability-non-const-parameter)*/,
34 size_t size) {
35 SELF* self = (SELF*)capture;
36 INVARIANT_CHECK(self);
37
38 (void)buf;
39 (void)size;
40
41 DC_PANIC("cookie set in write-only mode, but read was called.");
42}
43
44static ssize_t PRIV(NS(SELF, write))(void* capture, const char* data, size_t size) {
45 SELF* self = (SELF*)capture;
46 INVARIANT_CHECK(self);
47
48 // JUSTIFY: Unpoisoning passed data to write
49 // - glibc is not instrumented for msan, so sometimes the entire buffer can be deivered as
50 // uninitialised.
51 // - Hence we consider fopenccokie's write as a 'tainted source', and enforce correct memory
52 // capabilities
54
55 if (self->size_without_null + size + 1 > self->capacity) {
56 size_t new_capacity;
57 char* new_buf;
58 if (self->buf != NULL) {
59 size_t const growth_factor = 2;
60 new_capacity =
61 (self->capacity * growth_factor) + size + NS(SELF, additional_alloc_size);
62 new_buf = (char*)NS(ALLOC, reallocate)(self->alloc_ref, self->buf, self->capacity,
63 new_capacity);
64 } else {
65 DC_ASSUME(self->capacity == 0);
66 new_capacity = size + 1 + NS(SELF, additional_alloc_size);
67 new_buf = (char*)NS(ALLOC, allocate_uninit)(self->alloc_ref, new_capacity);
68 }
69
70 self->capacity = new_capacity;
71 self->buf = new_buf;
72 }
73
74 memcpy(self->buf + self->size_without_null, data, size);
75 self->size_without_null += size;
76 self->buf[self->size_without_null] = '\0';
77 return (ssize_t)size;
78}
79
80static int PRIV(NS(SELF, seek))(void* capture,
81 off_t* offset /*NOLINT(readability-non-const-parameter)*/,
82 int whence) {
83 SELF* self = (SELF*)capture;
84 INVARIANT_CHECK(self);
85 (void)offset;
86 (void)whence;
87
88 errno = EPERM; // NOLINT(misc-include-cleaner)
89 return -1;
90}
91
92static int PRIV(NS(SELF, close))(void* capture) {
93 SELF* self = (SELF*)capture;
94 INVARIANT_CHECK(self);
95 return 0;
96}
97
98DC_PUBLIC static SELF NS(SELF, new)(NS(ALLOC, ref) alloc_ref) {
99 return (SELF){
100 .stream = NULL,
101 .buf = NULL,
102 .size_without_null = 0,
103 .capacity = 0,
104 .alloc_ref = alloc_ref,
105 };
106}
107
108DC_PUBLIC static FILE* NS(SELF, stream)(SELF* self) {
109 INVARIANT_CHECK(self);
110
111 if (self->stream == NULL) {
112 cookie_io_functions_t /* NOLINT(misc-include-cleaner) */ const io = {
113 .read = PRIV(NS(SELF, read)),
114 .write = PRIV(NS(SELF, write)),
115 .seek = PRIV(NS(SELF, seek)),
116 .close = PRIV(NS(SELF, close)),
117 };
118 self->stream = fopencookie(self, "w", io);
119 DC_ASSERT(self->stream != NULL, "Failed to open stream for string builder, with error: %s",
120 strerror(errno));
121
122 // JUSTIFY: No buffering
123 // - No performance advantage to buffering writes - this already writes to an in memory
124 // buffer
125 // - No need to fflush
126 setvbuf(self->stream, NULL, _IONBF, 0);
127 }
128
129 return self->stream;
130}
131
133DC_PUBLIC static void NS(SELF, reset)(SELF* self) {
134 INVARIANT_CHECK(self);
135 self->size_without_null = 0;
136}
137
139DC_PUBLIC static char const* NS(SELF, string)(SELF const* self) {
140 INVARIANT_CHECK(self);
141 if (self->size_without_null == 0) {
142 return "";
143 }
144 return self->buf;
145}
146
150DC_PUBLIC static char* NS(SELF, release_string)(SELF* self) {
151 INVARIANT_CHECK(self);
152 char* buf = self->buf;
153 self->size_without_null = 0;
154 self->buf = NULL;
155 self->capacity = 0;
156
157 return buf;
158}
159
160DC_PUBLIC static size_t NS(SELF, string_size)(SELF* self) {
161 INVARIANT_CHECK(self);
162 return self->size_without_null;
163}
164
165DC_PUBLIC static void NS(SELF, delete)(SELF* self) {
166 INVARIANT_CHECK(self);
167 if (self->stream) {
168 fclose(self->stream);
169 }
170 if (self->buf) {
171 NS(ALLOC, deallocate)(self->alloc_ref, self->buf, self->capacity);
172 }
173}
174
175#undef INVARIANT_CHECK
176
static DC_PUBLIC void deallocate(SELF *self, void *ptr, size_t size)
Definition template.h:127
static DC_PUBLIC void reset(SELF *self)
Definition template.h:186
static DC_PUBLIC void * allocate_uninit(SELF *self, size_t size)
Definition template.h:92
static DC_PUBLIC void * reallocate(SELF *self, void *ptr, size_t old_size, size_t new_size)
Definition template.h:137
#define ALLOC
Definition template.h:31
#define INVARIANT_CHECK(self)
Definition template.h:90
static DC_PUBLIC VALUE const * read(SELF const *self, INDEX index)
Definition template.h:199
static DC_PUBLIC VALUE * write(SELF *self, INDEX index)
Definition template.h:209
static DC_PUBLIC size_t size(SELF const *self)
Definition template.h:252
static DC_PUBLIC ITEM * data(SELF *self)
Definition template.h:284
#define SELF
Definition def.h:52
static DC_PUBLIC void dc_memory_tracker_set(dc_memory_tracker_level level, dc_memory_tracker_capability cap, const volatile void *addr, size_t size)
@ DC_MEMORY_TRACKER_LVL_NONE
@ DC_MEMORY_TRACKER_CAP_READ_WRITE
#define DC_PUBLIC
Definition namespace.h:25
#define NS(pre, post)
Definition namespace.h:14
#define PRIV(name)
Definition namespace.h:20
#define DC_PANIC(str,...)
Definition panic.h:29
#define DC_ASSERT(expr,...)
Definition panic.h:37
#define DC_ASSUME(expr,...)
Definition panic.h:57
size_t capacity
Definition template.h:72
char * buf
Definition template.h:18
ref alloc_ref
Definition template.h:49
size_t size_without_null
Definition template.h:19
static size_t const additional_alloc_size
Definition template.h:24
static int PRIV close(void *capture)
Definition template.h:92
static DC_PUBLIC FILE * stream(SELF *self)
Definition template.h:108
static int PRIV seek(void *capture, off_t *offset, int whence)
Definition template.h:80
static DC_PUBLIC char * release_string(SELF *self)
Definition template.h:150
static DC_PUBLIC size_t string_size(SELF *self)
Definition template.h:160