Skip to content
volt
GitHub

std::mem

Allocators, box<T> (an owning pointer) and memory errors.

Source: std/mem.volt

Types

error std::mem::mem_error

error mem_error

an allocation that failed

Variant
OUT_OF_MEMORYmalloc or realloc returned null

trait std::mem::allocator

trait allocator

What everything in std that owns memory allocates through: box, vec, string, map, set, deque, heap, sorted_map, shared, channel, and the functions that return such values. A failed malloc or realloc returns OUT_OF_MEMORY. Like Zig's, the caller says how big a block is when it resizes or frees it, so an allocator needn't remember.

Required functions

<T: type> fn malloc(this, count: usize = 1) -> mem_error!(T*)

room for count T's, aligned for T

<T: type> fn realloc(this, ptr: T*, old: usize, count: usize) -> mem_error!(T*)

ptr's block, which holds old T's, resized to count T's (it may move; the first min(old, count) T's come along)

<T: type> fn free(this, ptr: T*, count: usize = 1) -> void

give back ptr's block, which holds count T's

struct std::mem::default_allocator

struct default_allocator

The C library's memory, with two layers on top. Release builds take blocks of up to SMALL_MAX bytes from per-thread free lists, one per 16-byte size class, cut from SMALL_CHUNK-byte chunks: a box costs a load and a store instead of a trip through malloc (the size class is known when the type is). Debug builds put each block's size in front of it and check every free and realloc against it, so a caller that gives back a different size (which would corrupt a free list) stops right there. On bare metal (no OS) it's the heap's allocator as is, since a chunk can be more memory than the board has. Empty, so a box using it is just a pointer. ponytail: freed small blocks stay on their free list (memory isn't handed back to the system, and a thread's lists outlive it); trim them if a long-running program needs that.

Implements allocator.

struct std::mem::fixed_buffer

struct fixed_buffer

Memory from a buffer the program owns (an array on the stack, a global, anything): no heap at all. Blocks are handed out front to back; freeing or resizing the last one gives its room back, other frees keep theirs until reset. Allocate through allocator(); the buffer has to outlive everything allocated from it.

Field
buf: u8[..]the memory
end: usize = 0bytes in use: the front of buf
last: usize = 0where the last block starts

Methods

attach fn allocator(this: std::mem::fixed_buffer&) -> std::mem::fixed_buffer_allocator

the allocator handing out the buffer's memory

attach fn used(this: std::mem::fixed_buffer&) -> usize

bytes in use (including any padding for alignment)

attach fn reset(this: std::mem::fixed_buffer&) -> void

forget every block: the whole buffer is free again (what was allocated must not be used after)

struct std::mem::fixed_buffer_allocator

struct fixed_buffer_allocator

the allocator for a fixed_buffer (a pointer to it, so every container using it shares its state)

Implements allocator.

Field
fb: fixed_buffer* = null

struct std::mem::arena

<B: allocator = default_allocator> struct arena

Memory that goes all at once: blocks come from chunks taken from backing, frees do nothing (except for the last block, whose room comes back), and deleting or resetting the arena gives every chunk back. Allocate through allocator(); the arena has to outlive what's allocated from it.

Field
backing: B = {}where the chunks come from
head: arena_chunk* = nullthe newest chunk
end: usize = 0bytes in use in head
last: usize = 0where the last block in head starts
total: usize = 0bytes handed out, all chunks

Methods

<B: std::mem::allocator> attach fn allocator(this: std::mem::arena<B>&) -> std::mem::arena_allocator<B>

the allocator handing out the arena's memory

<B: std::mem::allocator> attach fn used(this: std::mem::arena<B>&) -> usize

bytes handed out and not given back

<B: std::mem::allocator> attach fn reset(this: std::mem::arena<B>&) -> void

give every chunk back: what was allocated must not be used after

<B: std::mem::allocator> attach fn delete(this: std::mem::arena<B>&) -> void

struct std::mem::arena_allocator

<B: allocator = default_allocator> struct arena_allocator

the allocator for an arena (a pointer to it, so every container using it shares its state)

Implements allocator.

Field
a: arena<B>* = null

struct std::mem::failing

<B: allocator = default_allocator> struct failing

For testing what happens when memory runs out: the next left allocations (or resizes) come from backing, and every one after them fails. Allocate through allocator().

Field
left: i64 = 0allocations still allowed
backing: B = {}where those come from

Methods

<B: std::mem::allocator> attach fn allocator(this: std::mem::failing<B>&) -> std::mem::failing_allocator<B>

the allocator that counts down its allocations

struct std::mem::failing_allocator

<B: allocator = default_allocator> struct failing_allocator

the allocator for a failing (a pointer to it, so every container using it shares the count)

Implements allocator.

Field
f: failing<B>* = null

struct std::mem::box

<T: type, Allocator: allocator = default_allocator> struct box

the owned pointer. keeps its allocator, so it frees with the one that allocated. @owns("ptr"): box is used like a T&, and when it goes out of scope *ptr is deleted first, then box's own delete (below) frees the memory. Any library can make such a type

Field
ptr: T*raw: the memory the box owns
allocator: Allocatorwhat frees ptr

Methods

<T: type, Allocator: std::mem::allocator> attach fn delete(this: std::mem::box<T, Allocator>&) -> void

frees a box's memory; runs automatically after *ptr is deleted

<T: type, Allocator: std::mem::allocator> attach fn copy(this: std::mem::box<T, Allocator>&) -> std::mem::box<T, Allocator>

copy of a box: a new allocation from the same kind of allocator holding a copy of *ptr

Methods on other types

Attached to built-in types, or to every type (T).

<T: type, Allocator: std::mem::allocator = std::mem::default_allocator> attach fn new(static this: T, value: T, allocator: Allocator = {}) -> std::mem::mem_error!std::mem::box<T, Allocator>

T::new(value) / T::new(value, allocator): a box holding value