std::mem
Allocators, box<T> (an owning pointer) and memory errors.
Source: std/mem.volt
Types
error std::mem::mem_error
error mem_erroran allocation that failed
| Variant | |
|---|---|
OUT_OF_MEMORY | malloc or realloc returned null |
trait std::mem::allocator
trait allocatorWhat 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) -> voidgive back ptr's block, which holds count T's
struct std::mem::default_allocator
struct default_allocatorThe 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_bufferMemory 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 = 0 | bytes in use: the front of buf |
last: usize = 0 | where the last block starts |
Methods
attach fn allocator(this: std::mem::fixed_buffer&) -> std::mem::fixed_buffer_allocatorthe allocator handing out the buffer's memory
attach fn used(this: std::mem::fixed_buffer&) -> usizebytes in use (including any padding for alignment)
attach fn reset(this: std::mem::fixed_buffer&) -> voidforget 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_allocatorthe 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 arenaMemory 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* = null | the newest chunk |
end: usize = 0 | bytes in use in head |
last: usize = 0 | where the last block in head starts |
total: usize = 0 | bytes 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>&) -> usizebytes handed out and not given back
<B: std::mem::allocator> attach fn reset(this: std::mem::arena<B>&) -> voidgive every chunk back: what was allocated must not be used after
<B: std::mem::allocator> attach fn delete(this: std::mem::arena<B>&) -> voidstruct std::mem::arena_allocator
<B: allocator = default_allocator> struct arena_allocatorthe 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 failingFor 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 = 0 | allocations 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_allocatorthe 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 boxthe 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: Allocator | what frees ptr |
Methods
<T: type, Allocator: std::mem::allocator> attach fn delete(this: std::mem::box<T, Allocator>&) -> voidfrees 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