MMgr v1.0.0
Zero-heap memory manager in C11. One borrowed buffer, carved by asserted offset.
Loading...
Searching...
No Matches
spatium.h
Go to the documentation of this file.
1/* MMgr - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2 * SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Commercial OR LicenseRef-Educational
3 *
4 * Every use falls under AGPL-3.0-or-later unless you hold explicit permission, which is either a
5 * negotiated commercial licensing contract or an educator's license issued to you personally.
6 */
7/**
8 * @file spatium.h
9 * @brief Spans over a caller's buffer, the two span types, and the spat dispatch table.
10 * @author dstroy0 (Douglas Quigg) <dquigg123@gmail.com>
11 * @date 2026-08-29
12 *
13 * @note A span is a region and a cursor into it, with a sticky flag that latches once a walk has run
14 * past the end. It carries no storage of its own.
15 * @note The entries take an argument pack, as every other module's do. A span still travels by value
16 * inside that pack. SpatiumCfg holds one instead of pointing at one. A walk cannot change
17 * the span it was given.
18 * @note There are two span types and not one. mmgr_span is written through and latches overflow.
19 * mmgr_cspan is read from and latches err. Their extents are named cap and len, and so handing one
20 * where the other belongs is a compile error.
21 * @note The sticky flag makes a span worth passing. A caller may walk one through several
22 * steps and test once at the end and not after each.
23 * @note overflow and err do not mean the same kind of thing. A fill span overruns only when what a
24 * writer emits was sized wrong against its buffer, and both of those are settled before the
25 * build, and so overflow marks a wrong program. A read span runs out because whatever sent the
26 * bytes sent fewer, which is a runtime fact and nothing built wrong.
27 */
28#ifndef MMGR_SPATIUM_H
29#define MMGR_SPATIUM_H
30
31#include "mmgr.h"
32
33EMBED_BEGIN_DECLS
34
35/**
36 * @brief A buffer being filled: its bytes, how far the writer has gone, and whether it ran out.
37 *
38 * @note Returned by value. This module keeps no span of its own.
39 * @note overflow is sticky. Once a write has run past cap it stays set, and only mmgr_spat_reset
40 * clears it.
41 * @note Reaching it at all is a build failure, and so it is read to find out that something is wrong
42 * and not to decide what to do next. It latches so that a wrong program stops writing
43 * instead of walking off the end, and so that one test after a run of appends catches it.
44 * @warning buf points at the caller's storage, which must outlive every use of the span [BORROWS].
45 */
46typedef struct
47{
48 uint8_t *buf; /**< The buffer the span covers [BORROWS]. */
49 size_t cap; /**< Bytes in buf. */
50 size_t pos; /**< Bytes written so far, which mmgr_spat_from sets to 0. */
51 embed_bool overflow; /**< Set once a write has run past cap, and cleared only by mmgr_spat_reset. */
52} mmgr_span;
53
54/**
55 * @brief A buffer being read: its bytes, how far the reader has gone, and whether it ran out.
56 *
57 * @note The read-only counterpart of mmgr_span. buf is const here. A span handed out for reading
58 * cannot be written through it.
59 * @note err is sticky, for the same reason overflow is.
60 * @warning buf points at storage that must outlive every use of the span [BORROWS].
61 */
62typedef struct
63{
64 const uint8_t *buf; /**< First byte, or NULL when there is nothing to read [BORROWS]. */
65 size_t len; /**< Readable bytes at buf. */
66 size_t pos; /**< Bytes read so far. */
67 embed_bool err; /**< Set once a read has run past len, and never cleared after. */
69
70/**
71 * @brief Arguments for every spat call, where each call reads only the members it needs.
72 *
73 * @note Members left unset are zero, and the calls that ignore them never read them.
74 * @note span and cspan hold a span instead of pointing at one. A walk reads the caller's span and
75 * cannot change it. reset is the single one entry that must change one, and it takes at.
76 * @note cap carries the extent for both constructors: bytes at buf for from, bytes at cbuf for cfrom.
77 * @note count carries the byte count for after, first and read.
78 */
79typedef struct
80{
81 const mmgr_span span; /**< Fill span the walks read. */
82 const mmgr_cspan cspan; /**< Read span cok tests. */
83 mmgr_span *const at; /**< Fill span reset rewinds [BORROWS]. */
84 uint8_t *const buf; /**< Buffer from builds over [BORROWS]. */
85 const uint8_t *const cbuf; /**< Buffer cfrom builds over [BORROWS]. */
86 const size_t cap; /**< Bytes at buf, or at cbuf. */
87 const size_t count; /**< Byte count after, first and read take. */
89
90/**
91 * @brief Type of the spat dispatch table.
92 *
93 * @note EMBED_TABLE_LAYOUT asserts the ten members sit at consecutive EMBED_FUNCTION_POINTER_BYTES offsets, with
94 * nothing else.
95 * @note There is no len or room entry. mmgr_span is the caller's own value, and so span.pos and
96 * span.cap - span.pos are already in hand, and a call to fetch them would duplicate what
97 * reading the member already gives.
98 */
99typedef struct
100{
101 mmgr_span (*from)(const SpatiumCfg *args); /**< Builds a fill span over a buffer. */
102 mmgr_cspan (*cfrom)(const SpatiumCfg *args); /**< Builds a read span over a buffer. */
103 embed_bool (*ok)(const SpatiumCfg *args); /**< Whether a fill span is still usable. */
104 embed_bool (*cok)(const SpatiumCfg *args); /**< Whether a read span is still usable. */
105 embed_bool (*has_storage)(const SpatiumCfg *args); /**< Whether the span covers any bytes at all. */
106 void (*reset)(const SpatiumCfg *args); /**< Returns pos to 0 and clears overflow. */
107 mmgr_span (*after)(const SpatiumCfg *args); /**< The span beginning count bytes in. */
108 mmgr_span (*first)(const SpatiumCfg *args); /**< The span covering only the first count bytes. */
109 mmgr_cspan (*produced)(const SpatiumCfg *args); /**< A read span over everything written. */
110 mmgr_cspan (*read)(const SpatiumCfg *args); /**< A read span over the first count written. */
111} SpatiumNs;
112EMBED_TABLE_LAYOUT(SpatiumNs, from, cfrom, ok, cok, has_storage, reset, after, first, produced, read);
113
114/**
115 * @brief Builds a fill span over args->buf, with pos at 0 and overflow clear.
116 *
117 * @param[in] args Buffer buf and its extent cap [BORROWS].
118 * @return The span, by value.
119 * @note Asserts args->buf is not NULL and args->cap is not 0. The default MMGR_ASSERT leaves both
120 * unevaluated.
121 * @warning The span carries args->buf away, so that buffer must outlive every use of the span [BORROWS].
122 */
124
125/**
126 * @brief Builds a read span over args->cbuf, with pos at 0 and err clear.
127 *
128 * @param[in] args Buffer cbuf and its extent cap [BORROWS].
129 * @return The span, by value.
130 * @note cbuf and not buf. A buffer that may not be written cannot reach the fill constructor.
131 * @note Takes cbuf and cap as handed over, with none of the asserts mmgr_spat_from makes. A null cbuf
132 * or a zero cap still builds, and mmgr_spat_cok is what reports the span unusable.
133 * @warning The span carries args->cbuf away, so that buffer must outlive every use of the span [BORROWS].
134 */
136
137/**
138 * @brief Returns whether args->span has storage and has not overflowed.
139 *
140 * @param[in] args Span to test, as args->span [BORROWS].
141 * @return EMBED_TRUE when the span is still usable.
142 */
143embed_bool mmgr_spat_ok(const SpatiumCfg *args);
144
145/**
146 * @brief Returns whether args->cspan has storage and has recorded no error.
147 *
148 * @param[in] args Read span to test, as args->cspan [BORROWS].
149 * @return EMBED_TRUE when the span is still usable.
150 */
151embed_bool mmgr_spat_cok(const SpatiumCfg *args);
152
153/**
154 * @brief Returns whether args->span covers any bytes at all.
155 *
156 * @param[in] args Span to test, as args->span [BORROWS].
157 * @return EMBED_TRUE when buf is not NULL and cap is not 0.
158 */
159embed_bool mmgr_spat_has_storage(const SpatiumCfg *args);
160
161/**
162 * @brief Returns the span at args->at to its start and clears its overflow.
163 *
164 * @param[in,out] args Span to rewind, as args->at [BORROWS].
165 * @note The one entry that takes a span by pointer, because it is the single one that changes one.
166 * @note The one call that clears overflow, which is otherwise sticky for the span's whole life.
167 * @warning args->at is written through with no check of its own, and so it must point at a live span. The
168 * const on the pack covers the pack, not the span at the far end of at.
169 */
170void mmgr_spat_reset(const SpatiumCfg *args);
171
172/**
173 * @brief Returns the span beginning args->count bytes into args->span.
174 *
175 * @param[in] args Span to walk, as args->span, and the bytes to skip as args->count [BORROWS].
176 * @return A span over what is left, or a failed span when args->count is past cap.
177 * @note The span that comes back covers the same buffer args->span does [BORROWS]: a second view of
178 * those bytes and not a copy. A write through either is seen by both.
179 * @note An args->count of exactly cap gives an empty span that has not failed: nothing is left, but
180 * nothing went wrong either.
181 */
183
184/**
185 * @brief Returns the span covering only the first args->count bytes of args->span.
186 *
187 * @param[in] args Span to narrow, as args->span, and the bytes to keep as args->count [BORROWS].
188 * @return A span over those bytes, or a failed span when args->count is past cap.
189 * @note The span that comes back starts on the same byte args->span starts on [BORROWS], holding a
190 * shorter cap over the same storage. A fill through one is read by the other.
191 */
193
194/**
195 * @brief Returns a read span over everything written into args->span.
196 *
197 * @param[in] args Span to read back, as args->span [BORROWS].
198 * @return A read span over its first pos bytes, carrying span's overflow as its err.
199 * @note The same step as mmgr_spat_read against span's own pos, the case that cannot ask for
200 * more than was written and so cannot fail on its own account.
201 */
203
204/**
205 * @brief Returns a read span over the first args->count bytes written into args->span.
206 *
207 * @param[in] args Span to read back, as args->span, and the bytes to cover as args->count [BORROWS].
208 * @return A read span over them, marked err when args->count is past what was written.
209 * @warning The read span points at the fill span's own bytes [BORROWS], and the const on it binds this
210 * view and not the storage. Filling args->span again moves what the reader sees, and so read it back
211 * before the next fill or copy the bytes out.
212 */
214
215/**
216 * @brief Dispatch table instance named spat, with each member set to its mmgr_spat_ function.
217 */
218EMBED_TABLE_STORAGE SpatiumNs spat EMBED_UNUSED = {
219 .from = mmgr_spat_from,
220 .cfrom = mmgr_spat_cfrom,
221 .ok = mmgr_spat_ok,
222 .cok = mmgr_spat_cok,
223 .has_storage = mmgr_spat_has_storage,
224 .reset = mmgr_spat_reset,
225 .after = mmgr_spat_after,
226 .first = mmgr_spat_first,
227 .produced = mmgr_spat_produced,
228 .read = mmgr_spat_read,
229};
230
231EMBED_END_DECLS
232
233#endif
The embedded_types headers every module builds on.
mmgr_cspan mmgr_spat_produced(const SpatiumCfg *args)
Returns a read span over everything written into args->span.
mmgr_span mmgr_spat_after(const SpatiumCfg *args)
Returns the span beginning args->count bytes into args->span.
mmgr_cspan mmgr_spat_cfrom(const SpatiumCfg *args)
Builds a read span over args->cbuf, with pos at 0 and err clear.
embed_bool mmgr_spat_cok(const SpatiumCfg *args)
Returns whether args->cspan has storage and has recorded no error.
static const SpatiumNs spat
Dispatch table instance named spat, with each member set to its mmgr_spat_ function.
Definition spatium.h:218
void mmgr_spat_reset(const SpatiumCfg *args)
Returns the span at args->at to its start and clears its overflow.
mmgr_span mmgr_spat_first(const SpatiumCfg *args)
Returns the span covering only the first args->count bytes of args->span.
embed_bool mmgr_spat_ok(const SpatiumCfg *args)
Returns whether args->span has storage and has not overflowed.
embed_bool mmgr_spat_has_storage(const SpatiumCfg *args)
Returns whether args->span covers any bytes at all.
mmgr_cspan mmgr_spat_read(const SpatiumCfg *args)
Returns a read span over the first args->count bytes written into args->span.
mmgr_span mmgr_spat_from(const SpatiumCfg *args)
Builds a fill span over args->buf, with pos at 0 and overflow clear.
Arguments for every spat call, where each call reads only the members it needs.
Definition spatium.h:80
const uint8_t *const cbuf
Definition spatium.h:85
const size_t cap
Definition spatium.h:86
const mmgr_cspan cspan
Definition spatium.h:82
mmgr_span *const at
Definition spatium.h:83
uint8_t *const buf
Definition spatium.h:84
const mmgr_span span
Definition spatium.h:81
const size_t count
Definition spatium.h:87
Type of the spat dispatch table.
Definition spatium.h:100
mmgr_cspan(*) read(const SpatiumCfg *args)
Definition spatium.h:110
mmgr_span(*) from(const SpatiumCfg *args)
Definition spatium.h:101
mmgr_span(*) first(const SpatiumCfg *args)
Definition spatium.h:108
mmgr_cspan(*) cfrom(const SpatiumCfg *args)
Definition spatium.h:102
embed_bool(*) has_storage(const SpatiumCfg *args)
Definition spatium.h:105
embed_bool(*) ok(const SpatiumCfg *args)
Definition spatium.h:103
mmgr_cspan(*) produced(const SpatiumCfg *args)
Definition spatium.h:109
void(*) reset(const SpatiumCfg *args)
Definition spatium.h:106
mmgr_span(*) after(const SpatiumCfg *args)
Definition spatium.h:107
embed_bool(*) cok(const SpatiumCfg *args)
Definition spatium.h:104
A buffer being read: its bytes, how far the reader has gone, and whether it ran out.
Definition spatium.h:63
embed_bool err
Definition spatium.h:67
size_t len
Definition spatium.h:65
size_t pos
Definition spatium.h:66
const uint8_t * buf
Definition spatium.h:64
A buffer being filled: its bytes, how far the writer has gone, and whether it ran out.
Definition spatium.h:47
size_t pos
Definition spatium.h:50
uint8_t * buf
Definition spatium.h:48
size_t cap
Definition spatium.h:49
embed_bool overflow
Definition spatium.h:51