Stack-allocated Arrays

RecipeCratesCategories
arrayvecarrayveccat-data-structures
smallvecsmallveccat-data-structures
tinyvectinyveccat-data-structures

Stack-allocated arrays are arrays that are stored on the stack, as opposed to the heap. The stack is a region of memory that is used for storing local variables and function call information. Stack allocation has several important characteristics:

  • The size of stack-allocated arrays must be known at compile time. This means you cannot resize these arrays dynamically as you can with heap-allocated arrays.
  • Allocating and deallocating memory on the stack is very fast, because it simply involves adjusting the stack pointer. There is no need for complex memory management as with heap allocation.
  • The stack is typically much smaller than the heap, so stack-allocated arrays are suitable for small to moderately sized arrays.
  • Stack-allocated arrays are automatically deallocated when they go out of scope.

arrayvec

arrayvec arrayvec-crates.io arrayvec-github arrayvec-lib.rs cat-data-structures cat-no-std

arrayvec provides the types ArrayVec and ArrayString, which are stack-allocated, fixed size array-backed vector and string types.

ArrayVec is a vector-like collection with a fixed capacity that is determined at compile time. ArrayVec allocates its storage on the stack rather than on the heap, which can lead to better performance. It offers a simple API but also dereferences to a slice, so that the full slice API is available.

use arrayvec::ArrayVec;

// ArrayVec is a vector backed by a fixed size array.
// The capacity is of type usize but is range limited to u32::MAX
// It offers a simple API but also dereferences to a slice, so that the full
// slice API is available.
fn main() {
    let mut array = ArrayVec::<_, 2>::new();
    assert_eq!(array.capacity(), 2);
    // Push some elements into the ArrayVec
    array.push(1);
    array.push(2);
    assert!(array.is_full());
    // Trying to push beyond the capacity will result in a panic
    // ERROR: array.push(3);
    let overflow = array.try_push(3);
    assert!(overflow.is_err());
    // Access elements
    for i in 0..array.len() {
        println!("Element at index {}: {}", i, array[i]);
    }
    assert_eq!(&array[..], &[1, 2]);

    let mut array2: ArrayVec<i32, 3> = ArrayVec::from([1, 2, 3]);
    // Pop an element from the ArrayVec
    if let Some(value) = array2.pop() {
        println!("Popped value: {}", value);
    }
    assert_eq!(array2.len(), 2);
    assert!(!array2.is_empty());
}

smallvec

smallvec smallvec-crates.io smallvec-github smallvec-lib.rs cat-data-structures

smallvec provides a vector that can store a small number of elements on the stack. Arrays that are stack-allocated will fallback to the heap if the fixed stack capacity is exceeded.

use smallvec::SmallVec;
use smallvec::smallvec;

fn main() {
    // Create a SmallVec with a small inline capacity of 4
    let mut small_vec: SmallVec<i32, 4> = SmallVec::new();
    // Push some elements into the SmallVec
    small_vec.push(1);
    small_vec.push(2);
    small_vec.push(3);
    small_vec.push(4);

    // You can also initialize it via a macro:
    let mut small_vec: SmallVec<i32, 4> = smallvec![1, 2, 3, 4];

    // Print the current state of the SmallVec
    println!("SmallVec (inline): {:?}", small_vec);

    // Push beyond the inline capacity, causing a heap allocation
    small_vec.push(5);

    // Print the state of the SmallVec after pushing beyond capacity
    println!("SmallVec (heap-allocated): {:?}", small_vec);

    // Access elements
    for i in 0..small_vec.len() {
        println!("Element at index {}: {}", i, small_vec[i]);
    }

    // Pop an element from the SmallVec
    if let Some(value) = small_vec.pop() {
        println!("Popped value: {}", value);
    }

    // Print the state of the SmallVec after popping
    println!("SmallVec after popping: {:?}", small_vec);

    // Split off the SmallVec
    let mut small_vec2 = small_vec.split_off(1);
    assert_eq!(small_vec, [1]);
    assert_eq!(small_vec2, [2, 3, 4]);

    // SmallVec points to a slice, so you can use normal slice
    // indexing and other methods to access its contents:
    small_vec2[0] = small_vec2[1] + small_vec2[2];
    small_vec2.sort();
}

tinyvec

tinyvec tinyvec-crates.io tinyvec-github tinyvec-lib.rs cat-data-structures cat-no-std

The tinyvec crate provides a way to work with vectors that can store a small number of elements inline, without heap allocation, and dynamically grow to the heap if necessary. It is in 100% safe Rust code. It is similar to smallvec but with a smaller feature set and no dependencies. tinyvec requires items to implement the Default trait.

use tinyvec::TinyVec;

fn main() {
    // Create a TinyVec with an inline capacity of 4 elements
    let mut tiny_vec: TinyVec<[i32; 4]> = TinyVec::new();

    // Push some elements into the TinyVec
    tiny_vec.push(1);
    tiny_vec.push(2);
    tiny_vec.push(3);
    tiny_vec.push(4);

    // Print the current state of the TinyVec
    println!("TinyVec (inline): {:?}", tiny_vec);

    // Push beyond the inline capacity, causing a heap allocation
    tiny_vec.push(5);

    // Print the state of the TinyVec after pushing beyond capacity
    println!("TinyVec (heap-allocated): {:?}", tiny_vec);

    // Access elements
    for i in 0..tiny_vec.len() {
        println!("Element at index {}: {}", i, tiny_vec[i]);
    }

    // Pop an element from the TinyVec
    if let Some(value) = tiny_vec.pop() {
        println!("Popped value: {}", value);
    }

    // Print the state of the TinyVec after popping
    println!("TinyVec after popping: {:?}", tiny_vec);
}