Arena structv0.1.0

Source
An allocator that advances a pointer and reclaims everything at once.
pub struct Arena {
    // private fields
}

Move-only, because it owns its blocks and explicitly prohibits copying. Pass its Handle where a storable Allocator adapter is needed.

Constructors

Arena

pub func Arena(backing: Allocator, blockSize: uint) -> Arena

An arena that will take its storage from backing. backing is borrowed for the call and kept. blockSize is the payload of the first block; zero asks for the default. Cannot fail and allocates nothing: the first block is taken when the first request arrives, so an arena that is never used costs nothing.

NameTypeDescription
backingAllocatorwhere the arena's blocks come from
blockSizeuintthe first block's payload in bytes; zero asks for the default

Returns: the arena, holding no block yet

Source

Methods

Handle

pub func Handle(self: *var Arena) -> ArenaHandle

A copyable interface adapter pointing at this arena. self stays the caller's. Allocations through the handle update this arena rather than copied state. Cannot fail. Runs in constant time and allocates nothing. The handle borrows the arena and must not outlive it, nor survive the arena being moved. Nothing here tracks that: a handle held past its arena's life points at released storage.

Returns: a copyable adapter pointing at this arena

Source

Reset

pub func Reset(self: &var Arena)

Rewinds every allocation, keeping the largest block for the next round of work. self is borrowed mutably. Every pointer the arena ever handed out becomes invalid, including any still held by a caller — an arena reclaims in one operation, which is what makes it fast and what makes this the one dangerous call on it. The kept block is the current one, which is the largest, so a second round of the same work runs without asking the system for anything. Runs in time proportional to the number of blocks. Nothing may be read from or written to any earlier allocation afterwards.

Source

BytesUsed

pub func BytesUsed(self: &Arena) -> uint

How many payload bytes the arena has handed out, summed over every block it holds. self is borrowed. Alignment padding between allocations counts as used. The tail a block was left with when a request did not fit in it and the arena moved on to a new block is not counted: nothing was handed out of it, and nothing will be until a Reset. Runs in time proportional to the number of blocks and allocates nothing.

Returns: how many payload bytes the arena's blocks have handed out

Source

BlockCount

pub func BlockCount(self: &Arena) -> uint

How many blocks the arena holds. self is borrowed. Zero before the first request.

Returns: how many blocks the arena holds

Source

Destructor

func ~Arena(self: &var Arena)

Gives every block back to the backing allocator. Runs when the arena's life ends. Every pointer the arena handed out becomes invalid.

Source

DefaultArenaBlockSize

pub const DefaultArenaBlockSize: uint = 4096;

The default payload of an arena's first block. One page on every supported system. Each later block doubles, so an arena that keeps growing stops asking the system after a handful of requests.

Source

ArenaBlockAlignment

pub const ArenaBlockAlignment: uint = 16;

The alignment every arena block is taken at, and so the strictest alignment an arena can serve from one.

Source

ArenaBlock

pub struct ArenaBlock {
    // private fields
}

One block of arena storage, with the bookkeeping for what has been handed out of it. Never constructed by a caller. The payload follows the header immediately, and capacity counts only the payload.

Source

ArenaHandle

pub struct ArenaHandle {
    // private fields
}

A copyable interface adapter pointing at an arena. A handle is cheap to copy and may be stored wherever an allocator is wanted, but it does not own the arena.

Source

Implements Allocator

ArenaHandle conforms to Allocator.

Allocate

pub func Allocate(
    self: &ArenaHandle,
    layout: Layout
) -> (*var opaque) ! AllocError

Takes storage matching layout by advancing the arena's pointer. result receives the address when this reports None. A zero-sized layout gives the shared empty block and consumes none of the arena. Takes a new block when the current one cannot serve the request, which is the only path here that can fail. The storage lives until the arena is reset or destroyed, whichever comes first, and not one moment longer.

NameTypeDescription
layoutLayoutthe size and alignment wanted

Returns: the address of the storage, or why none was taken

Source

Deallocate

pub func Deallocate(
    self: &ArenaHandle,
    block: *var opaque,
    layout: Layout
) -> ! AllocError

Accepts a release and reclaims only what it can. An arena reclaims in one operation, so an ordinary release has nothing to give back and reports None having done nothing. The exception is the most recent allocation, whose space is rewound — which is what lets a growing collection in an arena not waste every earlier size it passed through. Accepting rather than refusing is deliberate: it lets an arena stand in for any allocator in generic code that releases what it takes.

NameTypeDescription
block*var opaquean address this allocator returned
layoutLayoutthe layout it was allocated with

Returns: nothing when the release was accepted, or why it was refused

Source

Reallocate

pub func Reallocate(
    self: &ArenaHandle,
    block: *var opaque,
    oldLayout: Layout,
    newLayout: Layout
) -> (*var opaque) ! AllocError

Grows or shrinks a block, extending the most recent allocation in place where it can. The two layouts must share an alignment. Growing the most recent allocation extends it without moving when the current block has room; anything else takes new storage and copies, leaving the old space behind for the next reset to reclaim. Shrinking to a zero-sized layout releases the block and reports the shared empty address rather than the one it rewound off of, so the result is releasable with the layout it was asked for.

NameTypeDescription
block*var opaquethe existing allocation's address
oldLayoutLayoutthe layout block was allocated with
newLayoutLayoutthe layout wanted, which must have the same alignment

Returns: the address the block is at afterwards, or why it was not resized

Source