core: Buffer<Item> as the heap storage primitive #54
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Buffer<Item>joinsArrayinstd/core: a growable heap sequence with an in-place promise andswapRemove. ECS columns (#92), the rebuilt collections (#55) and tensors stand on it. This issue is commit 2 of 2: thestd/coretype, its prelude export, its conformance programs and its docs. The compiler side is #299 (commit 1) and has to be merged and in a published seed first.Source
Buffer<Item>" (promises 1 and 3; promise 2, the windows, isstd/parallel'sWindow, already built overArrayListand out of scope here)Decisions (made in refinement; the design record stays the specification)
std/core/src/buffer.trb, re-exported fromstd/core/src/lib.trbandstd/preludelikeArray(public use Array, ... from "std/core").std/corecannot depend onstd/collections, soBufferimplements only what core owns:Iterate<Item>,Length,MutableIndex<Int, Item>,MutableSlice, plusEquals,Show,Hashasextends (items in brackets, ordered hash withcombineHashes), written like the ones at the end ofarray.trb. Joining theList/Collectionfamily andBytesbecomingBuffer<UInt8>is the follow-up #300, not this issue.public native type Buffer<Item>over the same runtime list asArrayList(RuntimeKind.ListStorage; #299 registers it). No new C, no newtorb_symbol, nothing in the VM beyond the shared table.buffer[i] = x,set,append,insert,removeAt,swapRemove,replace,reverse,clearchange the storage in place whenever it has one owner; they copy once (copy on write) only when theBuffervalue has been copied (const b = a, passed or captured by value) and is then written. The doc comment states exactly this and nothing stronger.slicecopies.ArrayList.sliceshares storage, so a live slice silently turns the next write into a copy - the trap a frame budget cannot have.Buffer.sliceis TorbScript (withCapacity, thenget/appendover the checked range) and the result owns its own storage. Hence nosliceBetweennative forBuffer. Borrowed views areWindow's job.swapRemoveis TorbScript over the natives, O(1), no new native.API (exact; doc comments with
# ExampleslikeArray)static fn withCapacity(capacity: Int): SelfArrayList)static fn from(items: Iterate<Item>): Selfwith From<Iterate<Item>>; soBuffer.of-style construction needs nothing elsefn length(): Intfn get(index: Int): Item?Noneout of range, negative includedfn at(index: Int): ItemArrayList.atmessage (index <i> is out of bounds for a length of <n>)var fn set(index: Int, value: Item)ArrayList.setvar fn update(index: Int, change: (var element: Item) => Void)change self[index], same line asArrayList.updatevar fn append(value: Item)var fn insert(index: Int, value: Item)var fn removeAt(index: Int): Item?Noneout of rangevar fn swapRemove(index: Int): Item?index, moves the last item into its slot, shrinks by one; order is not kept;None(and no change) out of range; on the last index it isremoveAt(last). Never shifts.fn slice(range: Bounds<Int>): SelfArrayList.slicefor a bad rangevar fn replace(range: Bounds<Int>, values: Self)replaceBetweenArrayList.replacevar fn reverse(),var fn clear()fn iterate(): Iterator<Item>,fn keys(): Iterate<Int>BufferIteratorholds the buffer by value (asArrayIterator);keysis0..length()Not on
Bufferin this issue:compact(moves toCollection, COLLECTIONS 3.2), list-literal adaptation (const b: Buffer<Int> = [1, 2]),windows(stays onArrayListuntil #55),capacity()/reserve.Acceptance criteria
std/core/src/buffer.trbdeclaresBuffer<Item>with exactly the API above; natives are only those of the "native" rows; exported fromstd/coreandstd/prelude;torb checkonstdclean.swapRemoveremoves in O(1): on[10, 20, 30, 40],swapRemove(1)answersSome(20)and leaves[10, 40, 30];swapRemove(3)on that three-item buffer answersNoneand changes nothing; the last index just drops the last item.var a: Buffer<Int> = ...; const b = a; a[0] = 9leavesbunchanged; the same through a field, avarparameter and a closure capture.buffer[i]for 200 000 indices of a 200 000-itemBuffer<Int>and a loop ofswapRemove/appendover the same size, and finishes within the suite's per-program time; the PR states the measured time and the time of the same program withconst keep = bufferheld (every write copying) so the margin is on record. Plus a micro-benchmark underbenchmarks/(same shape,ArrayListbeside it) with the numbers in the PR description.Buffer<String>and aBuffer<Buffer<String>>throughappend,set,removeAt,swapRemove,replace,clearand going out of scope pass the zero-live-blocks gate..expected.tests/conformance/(each with.expected,.exit):buffer-basics(append/get/at/set/insert/removeAt/length/iterate/keys, out-of-rangeget/removeAt/swapRemoveanswerNone),buffer-swap-remove,buffer-value-semantics,buffer-slice-copies(a slice taken, the original then written, neither sees the other),buffer-equality-show-hash,buffer-index-panics(.exit101 style asarray-index-bounds, with.stderr),buffer-in-place-scale,buffer-strings-leaks.std/corelistsBuffer; thenbuild/release/torb.exe docs skill docs skillsrun and both committed (--checkis a tier A gate).ArrayList,Bytes,std/parallelor the compiler (that is #299).Dependencies
Buffer, commit 1 of 2), merged and its commit in a published seed (seeds.txton theseedsrelease lists a seed at or after the #299 merge commit; the forge's Actions ->seed-> Run workflow publishes one at once). Without it CI cannot bootstrapstd/core.Notes
Not
readyuntil the seed condition above holds. Commit 2 of the two-commit rule (CLAUDE.md"Seed and breaking changes"): after #299, no further compiler change is needed.Moved from the planning lists of the docs; the design record stays the specification.
ArrayList, the hash tables and the tries onBuffer#55std/tensoron the CPU #82Bufferand parallel systems (ECS slices 6 and 9) #92Windowandwindows(CONCURRENCY slice F, gap 6) #4Windowandwindows(CONCURRENCY slice F, gap 6) #4Windowandwindows(CONCURRENCY slice F, gap 6) #4Windowandwindows(CONCURRENCY slice F, gap 6) #4[loop:torbscript] intake: in scope (author orion, label loop), not a duplicate, no collision with a design record (COLLECTIONS.md gap 6 is the source). Likely adds a native, so it follows the two-commit rule; refine decides. next: waiting (ready buffer full: #4, #49, #163, #164, #223 are ready) until 2026-10-09T10:00:00Z
ArrayList, the hash tables and the tries onBuffer#55std/tensoron the CPU #82Bufferand parallel systems (ECS slices 6 and 9) #92Windowandwindows(CONCURRENCY slice F, gap 6) #4[loop:torbscript] claim refine by session:loop-torbscript-20261010 until 2026-10-10T03:48Z
Buffernatives (commit 1 of 2 for #54) #299Buffer<Item>joins theListfamily andBytesbecomesBuffer<UInt8>#300[loop:torbscript] refine: split into #299 (compiler natives for
Buffer, commit 1 of 2,ready) and this issue (thestd/coretype with exact API, swapRemove in TorbScript,slicecopies, conformance programs; commit 2), plus follow-up #300 (Listfamily andBytes), next: waiting (needs a published seed containing the #299 merge; notreadyuntil then; #299 goes first)Buffernatives (commit 1 of 2 for #54) #299Buffernatives (commit 1 of 2 for #54) #299[loop:torbscript] refine: unblocked, the published seed torb-seed-1724b82c2d87 (seeds release) contains the #299 merge;
ready, next: implement[loop:torbscript] claim implement by session:loop-torbscript-20261010 until 2026-10-10T19:50Z
[loop:torbscript] release implement: the claim of session:loop-torbscript-20261010 expired without a result (no branch, no PR, no live worker).
[loop:torbscript] claim implement by session:loop-torbscript-20261012 until 2026-10-12T12:53Z
[loop:torbscript] release: the worker on anthropic:theorben died on its weekly limit before its first reply; respawning on the next profile.
[loop:torbscript] claim implement by session:loop-torbscript-20261012 until 2026-10-12T12:58Z
[loop:torbscript] implement:
Buffer<Item>in std/core (natives plus TorbScriptfrom/at/update/swapRemove/slicecopy/replace/iterate/keys, Equals/Show/Hash), 10 conformance programs with allocation budgets, ArrayList benchmark twins, docs and skill regenerated. CI run 865 green one65fc831(tier A, gates, bootstrap, same-C; tier B skipped by path filter, the buffer programs pass native + VM locally against nightly-20261011). PR #310, next: review (merge gate argus). Tokens: ~230k.[loop:torbscript] implement: a second worker was driving the same branch; both pushes landed on loop/54-buffer-std-core (mine: the format fixes, native markers in the std/core page, the swapRemove Panics section, pdisc stamps), CI green on
e65fc831(run 865), PR #310, next: review (merge gate argus). The benchmark margin numbers for the PR are still open (benchmarks are not a gate). Tokens: ~330k.Buffer<Item>joins theListfamily andBytesbecomesBuffer<UInt8>#300ArrayList, the hash tables and the tries onBuffer(step 1 of #55) #413ArrayList, the hash tables and the tries onBuffer#55std/tensoron the CPU (step 1 of #82) #438std/tensoron the CPU #82std/tensoron the CPU (step 1 of #82) #438std/tensor,Tensor<Scalar>over aBuffer(step 2 of #82) #691