Four classes and a handful of free functions — that's the whole
surface. Every signature below is copied from rpp/core.ring and
rpp/idioms.ring, not a description that can drift from the code.
load "ringpp.ring" oBuf = new RppBuffer(1024) oBuf.PokeString(0, "hello") ? oBuf.Peek(0, 5) # --> hello
That's the whole install story —
clone the repository, then one load. Everything
below is what's on the other side of it.
The type pillar one is built
around. Build it with new RppBuffer(nBytes), the free function
RppBuffer(nBytes), or RppBufferFromString(cStr) to
wrap a string you already have.
Capacity(), Size() — the buffer's byte capacity (both return the same number; two names for two habits of thought).
Peek(nOffset, nLen) — an O(1) slice out. 0.09 µs where substr() costs 12.5 µs on a 500 KB string.
Byte(nOffset) — the single byte at nOffset, as a number.
Str() — the whole buffer as an ordinary Ring string. The one place a copy happens on purpose, named so it's visible at the call site.
Poke(nOffset, cBytes), PokeString(nOffset, cStr) — write bytes at an offset, bounds-checked. The two names are the same call.
Fill(nOffset, nLen, nByte) — repeat one byte nLen times, starting at nOffset.
PokeInt32(nOffset, n) / PeekInt32(nOffset), PokeDouble / PeekDouble, PokeFloat / PeekFloat — packed numeric fields, for binary record layouts.
View(nOffset, nLen) — a zero-copy RppView window onto part of the buffer. All() is View(0, Size()).
Grow(nNewBytes) — the only legal resize: allocates a new backing string, copies the old bytes in, returns the old capacity. Never resize any other way — the reasons are in the source comments, and they're not optional.
LoadFile(cPath), SaveFile(cPath, nLen) — read a file straight into the buffer (growing it if needed), or write nLen bytes of it back out.
AddressUnchecked(), PokeUnchecked(nOffset, cBytes) — the escape hatch, named so it stays visible: no bounds check, your bug becomes a crash with no line number instead of a raised error.
oBuf = RppBufferFromString("name=Mansour;role=maintainer") oBuf.PokeInt32(900, 42) ? oBuf.PeekInt32(900) # --> 42
Never constructed with new directly — get one from
oBuf.View(nOffset, nLen) or oBuf.All(). It holds a
live reference to its owner (ref() — plain assignment would copy
the buffer and freeze a snapshot), so writes made through the buffer afterwards
are visible through the view too.
Size(), Offset() — the view's length, and where it starts inside its owner.
Peek(nOffset, nCount), Byte(nOffset) — same shape as RppBuffer's, offsets relative to the view, not the owner.
Sub(nOffset, nCount) — a view of a view, no new copy.
Str() — the view's bytes as an ordinary Ring string.
Buffer() — the owning RppBuffer, if you need to step back out to it.
oView = oBuf.View(5, 7) ? oView.Str() # --> Mansour
Wraps ringvm_genarray() — worth roughly 95× on
permuted reads of an append-built list, and up to 16× worse when
mutations outnumber reads. So it's spelled as a phase you open and close, not a
setting you leave on.
RppIndexed(aList) / new RppIndexed(aList) — opens the phase. Below 64 items it declines on its own (the cursor walk is already cheaper) rather than pay for an index nobody needs.
Applied() — whether the index was actually built.
Why() — one sentence explaining Applied()'s answer.
Release(aList) — closes the phase. Returns TRUE when the index stayed valid the whole time.
Caveat() — what Release() cannot see: sort() and reverse() invalidate the index without changing len(), so re-open the phase after sorting, always.
oIdx = RppIndexed(aRows) # open, once, before the reads for i = 1 to 50000 x = aRows[ aKeys[i] ][3] # random access, many times next oIdx.Release(aRows) # same list object, not a copy
The list must be passed to both calls, every time — storing it in an attribute would copy it by value, and Ring++ would index the copy instead of your list.
0.35 ms to create. A Ring error inside does not kill the host process. It buys containment, not speed — the same work runs roughly 1.75× slower in a fresh sub-state than in the host.
RppSandbox() / new RppSandbox() — opens a fresh Ring interpreter state.
Run(cCode) — runs a string of Ring source inside it.
Quiet() — suppresses the sandbox's own error output.
Var(cName), Has(cName) — read a variable back, or check it exists. (Not Get — get is a Ring statement keyword and can never be a method name.)
SetVar(cName, vValue) — set a variable before running code that reads it.
Free(), IsOpen() — release the sub-state, or check whether it already has been.
oBox = RppSandbox() oBox.Run("nTotal = 2 + 2") ? oBox.Var("nTotal") # --> 4 oBox.Free()
RppRows(nRows, nCols) — a 2D list via list(rows, cols), roughly 6× faster to build than pushing sublists one at a time, with near-array random access as a side effect.
RppSyntaxOk(cCode), RppTokens(cCode) — Ring's own scanner, exposed as a service: TRUE/FALSE, or the actual token list, with no extension involved.
RppAdvise(), RppAdviseAdd(cWhere, cText), RppAdviceClear() — the log RppIndexed itself writes warnings to when a phase's list changed shape mid-flight. Call RppAdvise() to print what accumulated.
RppBuffer — a document, a file you're building, a
parse buffer. Below ~512 bytes, plain Ring wins; this is for the
big, repeatedly-touched case.
RppView — records inside one big read, fields inside
one big row. A window that stays live as the buffer changes.
RppIndexed — a lookup pass, a report, anything that
reads far more than it writes. Open the phase, read, close it.
RppSandbox — generated Ring, a plugin, anything
where one bad statement should not take the host process down.