Module

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 Layout

A 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 > 0
  • alignment is a power of two
  • size can be zero (for zero-sized types)

Fields

  • size - The number of bytes required for the allocation
  • alignment - 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);
Members
size(&self): u64

Returns 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: u64
static array(elementLayout: Layout, count: u64): Layout

Creates 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): Layout

Compatibility alias for Layout::new(size, alignment).

static init(size: u64, alignment: u64): Layout

Compatibility alias for Layout::new(size, alignment).

static init(size: u64, alignment: u64): Layout

Compatibility alias for Layout::new(size, alignment).

static new(size: u64, alignment: u64): Layout

Creates 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:

  • alignment is zero
  • alignment is 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): Layout

Creates 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:

  • alignment is zero
  • alignment is 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): Layout

Creates 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:

  • alignment is zero
  • alignment is 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): u64

Returns 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): u64

Returns 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): u64

Returns 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): u64

Returns 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.