Stack-allocated Arrays
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
⮳ 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
⮳ 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
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);
}