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 "_GNU_SOURCE must be defined (is in the src/derive-c CMakeLists.txt) to use cookie_io"
11#endif
12
15
16typedef struct {
17 FILE* stream;
18 char* buf;
20 size_t capacity;
21 ALLOC* alloc;
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((self)->alloc); \
29 DC_ASSUME(DC_WHEN((self)->buf, (self)->stream && (self)->capacity > 0)); \
30 DC_ASSUME(DC_WHEN((self)->capacity == 0, !(self)->buf)); \
31 DC_ASSUME(DC_WHEN((self)->buf, (self)->size_without_null + 1 <= (self)->capacity));
32
33static ssize_t PRIV(NS(SELF, read))(void* capture,
34 char* buf /*NOLINT(readability-non-const-parameter)*/,
35 size_t size) {
36 SELF* self = (SELF*)capture;
37 INVARIANT_CHECK(self);
38
39 (void)buf;
40 (void)size;
41
42 DC_PANIC("cookie set in write-only mode, but read was called.");
43}
44
45static ssize_t PRIV(NS(SELF, write))(void* capture, const char* data, size_t size) {
46 SELF* self = (SELF*)capture;
47 INVARIANT_CHECK(self);
48
49 if (self->size_without_null + size + 1 > self->capacity) {
50 size_t new_capacity;
51 char* new_buf;
52 if (self->buf != NULL) {
53 size_t const growth_factor = 2;
54 new_capacity =
55 (self->capacity * growth_factor) + size + NS(SELF, additional_alloc_size);
56 new_buf = (char*)NS(ALLOC, realloc)(self->alloc, self->buf, new_capacity);
57 } else {
58 DC_ASSUME(self->capacity == 0);
59 new_capacity = size + 1 + NS(SELF, additional_alloc_size);
60 new_buf = (char*)NS(ALLOC, malloc)(self->alloc, new_capacity);
61 }
62
63 if (!new_buf) {
64 errno = ENOMEM; // NOLINT(misc-include-cleaner)
65 return -1;
66 }
67
68 self->capacity = new_capacity;
69 self->buf = new_buf;
70 }
71
72 memcpy(self->buf + self->size_without_null, data, size);
73 self->size_without_null += size;
74 self->buf[self->size_without_null] = '\0';
75 return (ssize_t)size;
76}
77
78static int PRIV(NS(SELF, seek))(void* capture,
79 off_t* offset /*NOLINT(readability-non-const-parameter)*/,
80 int whence) {
81 SELF* self = (SELF*)capture;
82 INVARIANT_CHECK(self);
83 (void)offset;
84 (void)whence;
85
86 errno = EPERM; // NOLINT(misc-include-cleaner)
87 return -1;
88}
89
90static int PRIV(NS(SELF, close))(void* capture) {
91 SELF* self = (SELF*)capture;
92 INVARIANT_CHECK(self);
93 return 0;
94}
95
96static SELF NS(SELF, new)(ALLOC* alloc) {
97 return (SELF){
98 .stream = NULL,
99 .buf = NULL,
100 .size_without_null = 0,
101 .capacity = 0,
102 .alloc = alloc,
103 };
104}
105
107static FILE* NS(SELF, stream)(SELF* self) {
108 INVARIANT_CHECK(self);
109
110 if (self->stream == NULL) {
111 cookie_io_functions_t /* NOLINT(misc-include-cleaner) */ const io = {
112 .read = PRIV(NS(SELF, read)),
113 .write = PRIV(NS(SELF, write)),
114 .seek = PRIV(NS(SELF, seek)),
115 .close = PRIV(NS(SELF, close)),
116 };
117 self->stream = fopencookie(self, "w", io);
118 DC_ASSERT(self->stream != NULL, "Failed to open stream for string builder, with error: %s",
119 strerror(errno));
120
121 // JUSTIFY: No buffering
122 // - No performance advantage to buffering writes - this already writes to an in memory
123 // buffer
124 // - No need to fflush
125 setvbuf(self->stream, NULL, _IONBF, 0);
126 }
127
128 return self->stream;
129}
130
132static void NS(SELF, reset)(SELF* self) {
133 INVARIANT_CHECK(self);
134 self->size_without_null = 0;
135}
136
138static char const* NS(SELF, string)(SELF const* self) {
139 INVARIANT_CHECK(self);
140 if (self->size_without_null == 0) {
141 return "";
142 }
143 return self->buf;
144}
145
147static char* NS(SELF, release_string)(SELF* self) {
148 INVARIANT_CHECK(self);
149 char* buf = self->buf;
150 self->size_without_null = 0;
151 self->buf = NULL;
152 self->capacity = 0;
153
154 return buf;
155}
156
157static size_t NS(SELF, string_size)(SELF* self) {
158 INVARIANT_CHECK(self);
159 return self->size_without_null;
160}
161
162static void NS(SELF, delete)(SELF* self) {
163 INVARIANT_CHECK(self);
164 if (self->stream) {
165 fclose(self->stream);
166 }
167 if (self->buf) {
168 NS(ALLOC, free)(self->alloc, self->buf);
169 }
170}
171
172#undef INVARIANT_CHECK
173
static void free(SELF *self, void *ptr)
Definition template.h:56
static void * realloc(SELF *self, void *ptr, size_t size)
Definition template.h:45
static void * malloc(SELF *self, size_t size)
Definition template.h:23
#define ALLOC
Definition template.h:64
static INDEX_TYPE size(SELF const *self)
Definition template.h:252
#define INVARIANT_CHECK(self)
Definition template.h:88
SLOT PRIV(block)[DC_ARENA_CHUNKED_BLOCK_SIZE(BLOCK_INDEX_BITS)]
Definition template.h:73
static VALUE const * read(SELF const *self, INDEX index)
Definition template.h:199
static VALUE * write(SELF *self, INDEX index)
Definition template.h:209
static ITEM * data(SELF *self)
Definition template.h:261
#define NS(pre, post)
Definition namespace.h:4
#define DC_PANIC(...)
Definition panic.h:28
#define DC_ASSERT(expr,...)
Definition panic.h:36
#define DC_ASSUME(expr,...)
Definition panic.h:56
#define SELF
Definition def.h:52
size_t capacity
Definition template.h:72
char * buf
Definition template.h:18
FILE * stream
Definition template.h:17
ALLOC * alloc
Definition template.h:71
size_t size_without_null
Definition template.h:19
static char * release_string(SELF *self)
Disowns the current string, free/management with chosen allocator determined by user.
Definition template.h:147
static size_t const additional_alloc_size
Definition template.h:24
static int PRIV close(void *capture)
Definition template.h:90
static size_t string_size(SELF *self)
Definition template.h:157
static FILE * stream(SELF *self)
Opens a file for.
Definition template.h:107
static int PRIV seek(void *capture, off_t *offset, int whence)
Definition template.h:78
static void reset(SELF *self)
Resets the string, but keps the same stream pointer alive.
Definition template.h:132