LexLeo 0.0.0-dev+f8e5087-dirty
Technical documentation
Loading...
Searching...
No Matches
dynamic_buffer_stream.c
Go to the documentation of this file.
1/* SPDX-License-Identifier: GPL-3.0-or-later
2 * Copyright (C) 2026 Sylvain Labopin
3 */
4
17
19
21#include "osal/mem/osal_mem.h"
22
24
26 void *backend,
27 void *buf,
28 size_t n,
30{
31 if (st) {
32 *st = STREAM_STATUS_OK;
33 }
34
35 if (!backend || (!buf && n)) {
36 if (st) {
38 }
39 return (size_t)0;
40 }
41
42 if (n == 0) {
43 return (size_t)0;
44 }
45
47
48 LEXLEO_ASSERT(dbs->mem);
49
50 dynamic_buffer_t *dbuf = &dbs->state.dbuf;
51 LEXLEO_ASSERT(dbuf->read_pos <= dbuf->len);
52
53 if (dbuf->read_pos >= dbuf->len) {
54 if (st) {
56 }
57 return (size_t)0;
58 }
59
60 size_t avail = dbuf->len - dbuf->read_pos;
61 size_t ret = (avail < n) ? avail : n;
62
63 osal_memcpy(buf, dbuf->buf + dbuf->read_pos, ret);
64 dbuf->read_pos += ret;
65
66 return ret;
67}
68
71 size_t cap)
72{
73 if (!dbs || !dbs->mem || !dbs->mem->realloc) {
75 }
76
77 dynamic_buffer_t *dbuf = &dbs->state.dbuf;
78
79 if (dbuf->cap >= cap) {
80 return STREAM_STATUS_OK;
81 }
82
83 void *new_buf = dbs->mem->realloc(dbuf->buf, cap);
84 if (!new_buf) {
85 return STREAM_STATUS_OOM;
86 }
87
88 dbuf->cap = cap;
89 dbuf->buf = new_buf;
90
91 return STREAM_STATUS_OK;
92}
93
94static size_t dynamic_buffer_stream_next_cap(size_t cap)
95{
96 if (cap > SIZE_MAX / 2) {
97 return (size_t)0;
98 }
99 return (size_t)(2 * cap);
100}
101
103 void *backend,
104 const void *buf,
105 size_t n,
106 stream_status_t *st)
107{
108 if (st) {
109 *st = STREAM_STATUS_OK;
110 }
111
112 if (!backend || (!buf && n)) {
113 if (st) {
115 }
116 return (size_t)0;
117 }
118
119 if (n == 0) {
120 return (size_t)0;
121 }
122
124 dynamic_buffer_t *dbuf = &dbs->state.dbuf;
125
126 LEXLEO_ASSERT(dbs->mem && dbuf->cap > 0);
127
128 if (n > SIZE_MAX - dbuf->len) {
129 if (st) {
131 }
132 return (size_t)0;
133 }
134
135 size_t need = dbuf->len + n;
136 size_t new_cap = dbuf->cap;
137
138 if (new_cap == 0) {
139 if (st) {
141 }
142 return (size_t)0;
143 }
144
145 while (need > new_cap) {
146 size_t grown = dynamic_buffer_stream_next_cap(new_cap);
147 if (grown == 0 || grown <= new_cap) {
148 if (st) {
149 *st = STREAM_STATUS_OOM;
150 }
151 return (size_t)0;
152 }
153 new_cap = grown;
154 }
155
156 stream_status_t rst =
158 if (rst != STREAM_STATUS_OK) {
159 if (st) {
160 *st = rst;
161 }
162 return (size_t)0;
163 }
164
165 osal_memcpy(dbuf->buf + dbuf->len, buf, n);
166 dbuf->len += n;
167
168 return n;
169}
170
172{
173 (void)backend;
174 return STREAM_STATUS_OK;
175}
176
178{
179 if (!backend) {
180 return STREAM_STATUS_OK;
181 }
182
184 dynamic_buffer_t *dbuf = &dbs->state.dbuf;
185
186 LEXLEO_ASSERT(dbs->mem && dbs->mem->free);
187
188 if (dbuf->autoclose && dbuf->buf) {
189 dbs->mem->free(dbuf->buf);
190 dbuf->buf = NULL;
191 }
192
193 dbs->mem->free(dbs);
194 return STREAM_STATUS_OK;
195}
196
203
208{
209 if (out) {
210 *out = NULL;
211 }
212
213 if (!out
214 || !cfg
215 || !cfg->default_cap
216 || !env
217 || !env->mem
218 || !env->mem->calloc
219 || !env->mem->realloc
220 || !env->mem->free) {
222 }
223
224 dynamic_buffer_stream_t *backend =
225 (dynamic_buffer_stream_t *)env->mem->calloc(1, sizeof(*backend));
226 if (!backend) {
227 return STREAM_STATUS_OOM;
228 }
229
230 backend->mem = env->mem;
231 backend->state.dbuf.cap = cfg->default_cap;
232 backend->state.dbuf.buf =
233 (char *)env->mem->calloc(backend->state.dbuf.cap, sizeof(char));
234
235 if (!backend->state.dbuf.buf) {
236 env->mem->free(backend);
237 return STREAM_STATUS_OOM;
238 }
239
240 backend->state.dbuf.len = 0;
241 backend->state.dbuf.read_pos = 0;
242 backend->state.dbuf.autoclose = true;
243
244 *out = backend;
245 return STREAM_STATUS_OK;
246}
247
249 const void *ud,
250 const osal_mem_ops_t *mem)
251{
252 if (!ud) {
253 return;
254 }
255
256 LEXLEO_ASSERT(mem && mem->free);
257 mem->free((void *)ud);
258}
259
261 stream_t **out,
264{
265 if (!out || !env || !cfg) {
267 }
268
269 dynamic_buffer_stream_t *backend = NULL;
270 stream_status_t st =
271 dynamic_buffer_stream_create_backend(&backend, cfg, env);
272 if (st != STREAM_STATUS_OK) {
273 return st;
274 }
275
276 stream_t *tmp = NULL;
277 st = stream_create(&tmp, &VTBL, backend, &env->port_env);
278 if (st != STREAM_STATUS_OK) {
280 return st;
281 }
282
283 *out = tmp;
284 return STREAM_STATUS_OK;
285}
286
288 const void *ud,
289 const void *args,
290 stream_t **out)
291{
292 const dynamic_buffer_stream_ctor_ud_t *ctor_ud =
294
295 if (args || !out || !ctor_ud) {
297 }
298
299 stream_t *tmp = NULL;
301 &tmp,
302 &ctor_ud->cfg,
303 &ctor_ud->env);
304
305 if (st != STREAM_STATUS_OK) {
306 return st;
307 }
308
309 *out = tmp;
310 return STREAM_STATUS_OK;
311}
312
315 stream_key_t key,
318 const osal_mem_ops_t *mem)
319{
320 if (out) {
321 *out = (stream_adapter_desc_t){0};
322 }
323
324 stream_adapter_desc_t tmp = {0};
325
326 if (!out
327 || !key
328 || *key == '\0'
329 || !cfg
330 || !cfg->default_cap
331 || !env
332 || !mem
333 || !mem->calloc
334 || !mem->free) {
336 }
337
338 tmp.key = key;
340
342 (dynamic_buffer_stream_ctor_ud_t *)mem->calloc(1, sizeof(*ud));
343 if (!ud) {
344 return STREAM_STATUS_OOM;
345 }
346
347 tmp.ud = ud;
348 osal_memcpy(&ud->cfg, cfg, sizeof(*cfg));
349 osal_memcpy(&ud->env, env, sizeof(*env));
351
352 *out = tmp;
353 return STREAM_STATUS_OK;
354}
355
362
364 const osal_mem_ops_t *mem,
365 const stream_env_t *port_env)
366{
367 LEXLEO_ASSERT(port_env);
368
370 .mem = mem ? mem : osal_mem_default_ops(),
371 .port_env = *port_env
372 };
373}
static stream_status_t dynamic_buffer_stream_flush(void *backend)
static size_t dynamic_buffer_stream_write(void *backend, const void *buf, size_t n, stream_status_t *st)
stream_status_t dynamic_buffer_stream_create_desc(stream_adapter_desc_t *out, stream_key_t key, const dynamic_buffer_stream_cfg_t *cfg, const dynamic_buffer_stream_env_t *env, const osal_mem_ops_t *mem)
Build a stream adapter descriptor for the dynamic_buffer_stream adapter.
static size_t dynamic_buffer_stream_next_cap(size_t cap)
static stream_status_t dynamic_buffer_stream_buffer_reserve(dynamic_buffer_stream_t *dbs, size_t cap)
static stream_status_t dynamic_buffer_stream_close(void *backend)
static void dynamic_buffer_stream_destroy_ud_ctor(const void *ud, const osal_mem_ops_t *mem)
stream_status_t dynamic_buffer_stream_create_stream(stream_t **out, const dynamic_buffer_stream_cfg_t *cfg, const dynamic_buffer_stream_env_t *env)
Create a dynamic_buffer_stream instance directly.
dynamic_buffer_stream_cfg_t dynamic_buffer_stream_default_cfg(void)
Return the default configuration for the dynamic_buffer_stream adapter.
dynamic_buffer_stream_env_t dynamic_buffer_stream_default_env(const osal_mem_ops_t *mem, const stream_env_t *port_env)
Return the default injected environment for the dynamic_buffer_stream adapter.
static size_t dynamic_buffer_stream_read(void *backend, void *buf, size_t n, stream_status_t *st)
stream_status_t dynamic_buffer_stream_ctor(const void *ud, const void *args, stream_t **out)
Factory-compatible constructor callback for the dynamic_buffer_stream adapter.
static stream_status_t dynamic_buffer_stream_create_backend(dynamic_buffer_stream_t **out, const dynamic_buffer_stream_cfg_t *cfg, const dynamic_buffer_stream_env_t *env)
static const stream_vtbl_t VTBL
Composition Root API for the dynamic_buffer_stream adapter.
Private constructor user-data stored in dynamic_buffer_stream factory descriptors.
Private backend handle definition for the dynamic_buffer_stream adapter.
Private runtime state definition for the dynamic_buffer_stream backend.
#define DYNAMIC_BUFFER_STREAM_DEFAULT_CAPACITY
#define LEXLEO_ASSERT(expr)
void * osal_memcpy(void *dest, const void *src, size_t n)
Definition osal_mem.c:25
const osal_mem_ops_t * osal_mem_default_ops(void)
stream_status_t stream_create(stream_t **out, const stream_vtbl_t *vtbl, void *backend, const stream_env_t *env)
Create a generic stream handle from adapter-provided backend bindings.
Definition stream.c:69
const char * stream_key_t
Public identifier type for a registered stream adapter.
stream_status_t
Public status codes used by the stream port.
@ STREAM_STATUS_INVALID
@ STREAM_STATUS_EOF
@ STREAM_STATUS_OK
@ STREAM_STATUS_OOM
Configuration type for the dynamic_buffer_stream adapter.
size_t default_cap
Default initial capacity of the internal dynamic buffer.
Private constructor user-data for dynamic_buffer_stream factory registration.
Injected dependencies for the dynamic_buffer_stream adapter.
const osal_mem_ops_t * mem
Borrowed memory operations table for adapter-owned allocations.
stream_env_t port_env
Borrowed stream port environment.
Private backend handle for the dynamic_buffer_stream adapter.
dynamic_buffer_stream_state_t state
Private dynamic buffer state used by the dynamic_buffer_stream backend.
void *(* calloc)(size_t nmemb, size_t size)
void *(* realloc)(void *ptr, size_t size)
void(* free)(void *ptr)
Public descriptor used to register a concrete stream adapter.
stream_key_t key
Public key used to identify the adapter.
const void * ud
Optional opaque user data bound to the constructor.
ud_dtor_fn_t ud_dtor
Optional destructor for ud.
stream_ctor_fn_t ctor
Adapter constructor used to create a stream_t.
Runtime environment for the stream port.
Definition stream_env.h:35
Private handle structure for a stream_t.
Adapter dispatch table bound to a stream_t instance.
stream_read_fn_t read