std::memory::layout
Memory Layout
Describes the size and alignment requirements for memory allocation.
Overview
A Layout encapsulates two fundamental properties needed for memory
allocation:
- Size: The number of bytes required
- Alignment: The address boundary the allocation must satisfy
These properties are essential for:
- Allocating memory for types with specific alignment requirements
- Creating arrays of elements with proper spacing
- Interfacing with low-level allocators
Memory Layout Concepts
Size vs Alignment vs Stride
LAYOUT PROPERTIES FOR A TYPE
════════════════════════════════════════════════════════════════════════
Consider a struct with size=12, alignment=8:
┌─────────────────────────────────────────────────────────────────────┐
│ Single Element │
│ │
│ Address: 0 4 8 12 16 20 24 28 32 │
│ │ │ │ │ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ │
│ ┌─────────────────┐ │
│ │ Data (12B) │ │
│ └─────────────────┘ │
│ ◄─── size = 12 ───► │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ Array of Elements │
│ │
│ Address: 0 4 8 12 16 20 24 28 32 │
│ │ │ │ │ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ │
│ ┌─────────────────┬────┬─────────────────┬────┐ │
│ │ Element 0 │pad │ Element 1 │pad │ │
│ │ (12 bytes) │(4B)│ (12 bytes) │(4B)│ │
│ └─────────────────┴────┴─────────────────┴────┘ │
│ ◄──── stride = 16 ────►◄──── stride = 16 ────► │
│ │
│ stride = paddedSize() = (size + align - 1) & ~(align - 1) │
│ stride = (12 + 7) & ~7 = 19 & ~7 = 16 │
└─────────────────────────────────────────────────────────────────────┘
Why Padding is Needed
WITHOUT PADDING (WRONG):
┌─────────────────────────────────────────────────────────────────────┐
│ Address: 0 12 24 36 │
│ │ │ │ │ │
│ ┌───────────┬───────────┬───────────┐ │
│ │ Element 0 │ Element 1 │ Element 2 │ │
│ └───────────┴───────────┴───────────┘ │
│ ▲ │
│ │ │
│ Address 12 is NOT 8-byte aligned! │
│ 12 & 7 = 4 ✗ │
└─────────────────────────────────────────────────────────────────────┘
WITH PADDING (CORRECT):
┌─────────────────────────────────────────────────────────────────────┐
│ Address: 0 12 16 28 32 44 48 │
│ │ │ │ │ │ │ │ │
│ ┌───────────┬───┬───────────┬───┬───────────┬───┐ │
│ │ Element 0 │pad│ Element 1 │pad│ Element 2 │pad│ │
│ └───────────┴───┴───────────┴───┴───────────┴───┘ │
│ ▲ ▲ │
│ │ │ │
│ Address 16 IS 8-byte aligned! ✓ │
│ 16 & 7 = 0 │
└─────────────────────────────────────────────────────────────────────┘
Creating Layouts
LAYOUT CREATION METHODS
════════════════════════════════════════════════════════════════════════
Method 1: From type (recommended)
┌─────────────────────────────────────────────────────────────────────┐
│ let layout: Layout = Layout::new<MyStruct>(); │
│ │
│ Automatically uses @sizeOf<T>() and @alignOf<T>() │
└─────────────────────────────────────────────────────────────────────┘
Method 2: From explicit size and alignment
┌─────────────────────────────────────────────────────────────────────┐
│ let layout: Layout = Layout::new(1024, 16); │
│ │
│ Useful for custom allocations (e.g., SIMD-aligned buffers) │
└─────────────────────────────────────────────────────────────────────┘
Method 3: For arrays
┌─────────────────────────────────────────────────────────────────────┐
│ let layout: Layout = Layout::new<u64>(100); │
│ │
│ Creates layout for 100 contiguous u64 elements │
└─────────────────────────────────────────────────────────────────────┘
Safety
Layout functions enforce the following invariants:
- Alignment is always a power of two
- Alignment is never zero
- Size does not overflow when multiplied by count
Functions panic on invalid inputs rather than returning errors.
Records
record LayoutA memory layout descriptor containing size and alignment requirements.
Layout is the fundamental building block for type-aware memory allocation.
It describes how much memory is needed and what alignment constraints must
be satisfied.
Invariants
A valid Layout always satisfies:
alignment > 0alignmentis a power of twosizecan be zero (for zero-sized types)
Fields
size- The number of bytes required for the allocationalignment- The minimum alignment requirement (always a power of two)
Memory Representation
┌─────────────────────────────────────────────────────────────────────┐
│ Layout Record │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ size: u64 │ alignment: u64 │ │
│ │ (8 bytes) │ (8 bytes) │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ Total size of Layout: 16 bytes │
│ Alignment of Layout: 8 bytes │
└─────────────────────────────────────────────────────────────────────┘
Example
import { Layout } from "std/memory/layout";
// Create layout for a u64
let layout: Layout = Layout::new<u64>();
assert(layout.size() == 8);
assert(layout.align() == 8);
// The padded size equals size when size is a multiple of alignment
assert(layout.paddedSize() == 8);
size(&self): u64Returns the size requirement of this layout.
This is the minimum number of bytes needed for the allocation. The actual allocation may be larger due to alignment padding.
Returns
The size in bytes.
Example
let layout: Layout = Layout::new(100, 16);
assert(layout.size() == 100);
alignment: u64static array(elementLayout: Layout, count: u64): LayoutCreates an array layout from an element layout and element count.
The total size is elementLayout.stride() * count, so every element slot
begins at an address that satisfies the element alignment.
static init(size: u64, alignment: u64): LayoutCompatibility alias for Layout::new(size, alignment).
static init(size: u64, alignment: u64): LayoutCompatibility alias for Layout::new(size, alignment).
static init(size: u64, alignment: u64): LayoutCompatibility alias for Layout::new(size, alignment).
static new(size: u64, alignment: u64): LayoutCreates a Layout from explicit size and alignment values.
This is the primary constructor for creating layouts with custom requirements.
Arguments
size- The size in bytes (may be zero)alignment- The alignment in bytes (must be a power of two, > 0)
Returns
A new Layout with the specified size and alignment.
Panics
Aborts if:
alignmentis zeroalignmentis not a power of two
Validation
Layout::new(size, alignment)
════════════════════════════════════════════════════════════════════════
Step 1: Check alignment != 0
┌─────────────────────────────────────────────────────────────────────┐
│ if (alignment == 0) abort() │
│ │
│ Valid: 1, 2, 4, 8, 16, 32, ... │
│ Invalid: 0 │
└─────────────────────────────────────────────────────────────────────┘
Step 2: Check alignment is power of two
┌─────────────────────────────────────────────────────────────────────┐
│ if (!isPowerOfTwo(alignment)) abort() │
│ │
│ Valid: 1, 2, 4, 8, 16, 32, 64, 128, 256, ... │
│ Invalid: 3, 5, 6, 7, 9, 10, 12, 15, ... │
└─────────────────────────────────────────────────────────────────────┘
Example
import { Layout } from "std/memory/layout";
// Standard layout
let layout: Layout = Layout::new(1024, 8);
// SIMD-aligned buffer
let simd: Layout = Layout::new(256, 32);
// Cache-line aligned
let cacheLine: Layout = Layout::new(64, 64);
static new(size: u64, alignment: u64): LayoutCreates a Layout from explicit size and alignment values.
This is the primary constructor for creating layouts with custom requirements.
Arguments
size- The size in bytes (may be zero)alignment- The alignment in bytes (must be a power of two, > 0)
Returns
A new Layout with the specified size and alignment.
Panics
Aborts if:
alignmentis zeroalignmentis not a power of two
Validation
Layout::new(size, alignment)
════════════════════════════════════════════════════════════════════════
Step 1: Check alignment != 0
┌─────────────────────────────────────────────────────────────────────┐
│ if (alignment == 0) abort() │
│ │
│ Valid: 1, 2, 4, 8, 16, 32, ... │
│ Invalid: 0 │
└─────────────────────────────────────────────────────────────────────┘
Step 2: Check alignment is power of two
┌─────────────────────────────────────────────────────────────────────┐
│ if (!isPowerOfTwo(alignment)) abort() │
│ │
│ Valid: 1, 2, 4, 8, 16, 32, 64, 128, 256, ... │
│ Invalid: 3, 5, 6, 7, 9, 10, 12, 15, ... │
└─────────────────────────────────────────────────────────────────────┘
Example
import { Layout } from "std/memory/layout";
// Standard layout
let layout: Layout = Layout::new(1024, 8);
// SIMD-aligned buffer
let simd: Layout = Layout::new(256, 32);
// Cache-line aligned
let cacheLine: Layout = Layout::new(64, 64);
static new(size: u64, alignment: u64): LayoutCreates a Layout from explicit size and alignment values.
This is the primary constructor for creating layouts with custom requirements.
Arguments
size- The size in bytes (may be zero)alignment- The alignment in bytes (must be a power of two, > 0)
Returns
A new Layout with the specified size and alignment.
Panics
Aborts if:
alignmentis zeroalignmentis not a power of two
Validation
Layout::new(size, alignment)
════════════════════════════════════════════════════════════════════════
Step 1: Check alignment != 0
┌─────────────────────────────────────────────────────────────────────┐
│ if (alignment == 0) abort() │
│ │
│ Valid: 1, 2, 4, 8, 16, 32, ... │
│ Invalid: 0 │
└─────────────────────────────────────────────────────────────────────┘
Step 2: Check alignment is power of two
┌─────────────────────────────────────────────────────────────────────┐
│ if (!isPowerOfTwo(alignment)) abort() │
│ │
│ Valid: 1, 2, 4, 8, 16, 32, 64, 128, 256, ... │
│ Invalid: 3, 5, 6, 7, 9, 10, 12, 15, ... │
└─────────────────────────────────────────────────────────────────────┘
Example
import { Layout } from "std/memory/layout";
// Standard layout
let layout: Layout = Layout::new(1024, 8);
// SIMD-aligned buffer
let simd: Layout = Layout::new(256, 32);
// Cache-line aligned
let cacheLine: Layout = Layout::new(64, 64);
align(&self): u64Returns the alignment requirement of this layout.
The alignment is always a power of two and greater than zero.
Returns
The alignment in bytes.
Example
let layout: Layout = Layout::new(100, 16);
assert(layout.align() == 16);
paddedSize(&self): u64Returns the size padded up to the alignment boundary.
This is the stride between consecutive elements when storing multiple values of this layout in a contiguous array. It ensures each element starts at a properly aligned address.
Returns
The smallest value >= size that is a multiple of alignment.
Formula
paddedSize = (size + (alignment - 1)) & ~(alignment - 1)
Diagram
size = 12, alignment = 8
════════════════════════════════════════════════════════════════════════
┌────────────────────────────────────────────────────────────────────┐
│ Bytes: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 │
│ │ │ │ │ │
│ ├──────────────────────────┼──────────────┤ │ │
│ │ Data (12 bytes) │ Padding │ │ │
│ │ │ (4 bytes) │ │ │
│ └──────────────────────────┴──────────────┘ │ │
│ ◄───────────── size = 12 ─────────────────► │ │
│ ◄──────────── paddedSize = 16 ────────────────► │
│ │ │
│ Next element starts here ─┘ │
│ (aligned to 8 bytes) │
└────────────────────────────────────────────────────────────────────┘
Example
import { Layout } from "std/memory/layout";
// Size already aligned
let layout1: Layout = Layout::new(16, 8);
assert(layout1.paddedSize() == 16);
// Size needs padding
let layout2: Layout = Layout::new(12, 8);
assert(layout2.paddedSize() == 16);
// Larger alignment
let layout3: Layout = Layout::new(20, 16);
assert(layout3.paddedSize() == 32);
size(&self): u64Returns the size requirement of this layout.
This is the minimum number of bytes needed for the allocation. The actual allocation may be larger due to alignment padding.
Returns
The size in bytes.
Example
let layout: Layout = Layout::new(100, 16);
assert(layout.size() == 100);
stride(&self): u64Returns the byte stride for repeated values of this layout.
This is an alias for paddedSize() used to make array allocation
contracts explicit at the call site.