A bounded view over memory the span does not own, with a cursor and a flag that latches.
spat.from borrows whatever Locus carcerum: the region handed you. Byteio: bytes on a wire writes into that storage and reads back out of it; Verba scribo: the string builder and Cellularum laboro: bounded string work work against the same bytes.
| mmgr_span | mmgr_cspan | |
|---|---|---|
| for | filling | reading |
| buf | writable | const |
| extent | cap | len |
| the flag | overflow | err |
The extent is named differently in each deliberately. const alone would stop the write but let the two be confused wherever a name is read, and so the field names differ too, and a mix-up is a compile error and not a puzzle.
overflow is a build failure. What a writer emits and how big its buffer is are both settled before the build, and so the two are either compatible or the program is wrong. There is no runtime condition under which a correct writer overruns a correctly sized span. MMGR_ASSERT says so, nothing in a shipping build, an abort in checks. See How failure is reported.
The flag is what a shipping build does with a wrong program, not a path to design for. It latches so that the first bad append stores nothing and every append after it is a no-op, which keeps a wrong writer off the end of the buffer instead of walking down it. Read it to learn that something is broken, not to decide what to do next.
err is a runtime fact. A read span runs out because whatever sent the bytes sent fewer, and nothing was built wrong. For that reason every take answers embed_bool and no append returns anything: a short read is a case to handle, an overrun append is a bug to fix.
Either way the flag is sticky. A caller walks a span through several steps and tests once at the end and not after each:
A take that reaches past the end leaves the cursor where it was. A caller that keeps reading after a failure still knows where it is. spat.reset is the only call that clears a flag.
Two build one: from, cfrom. Two ask whether it is still usable: ok, cok. One asks whether it covers any bytes at all: has_storage. One rewinds: reset. Two narrow: after a count of bytes, and first so many. Two turn a filled span back into a readable one: produced for everything written, read for a named prefix of it.
There is no len and no room. The span is the caller's own value, and so s.pos and s.cap - s.pos are already in hand, and a call to fetch them would be a second way to write a member read.
A span travels inside the argument pack, not as a pointer to one. SpatiumCfg holds an mmgr_span in .span and an mmgr_cspan in .cspan. A walk reads a copy and cannot change the span you gave it. reset is the exception and takes .at, a pointer, because it is the single one entry that must change one.
from takes .buf and cfrom takes .cbuf. They are separate members deliberately: a const uint8_t * cannot reach the fill constructor. A buffer you may not write cannot be turned into a span you may write through.
.cap carries the extent for both constructors, and .count the byte count for after, first and read. One member per job and not one per entry.
after and first return a new span; they do not move the one you passed. Assign the result.
A .count of exactly cap is not a failure. It gives an empty span that has not failed: nothing is left, and nothing went wrong either. Past cap is the failure.
produced carries the fill span's overflow across as the read span's err. Reading back a span that overran does not launder the failure.
pos keeps counting past cap once a span has overrun. So the number left behind says how far past the end a wrong writer went, which is worth reading in a post-mortem. It is not a sizing pass: a length you have to measure by overrunning a buffer at run time is a length you already knew when you wrote the code, and the assert fires long before you get to read it.
A span does not know when its target dies. It holds a pointer the caller gave it. Returning a span over temporary-tier storage from a function that gives the cell back is a use-after-free, and no field in the span can tell you.
Spans are values. Copy them, pass them, return them. Nothing in the library holds a pointer to one.
Generated reference for spatium ยท Who owns what for the lifetime rules