Expand description
Structures providing guarantees on byte sequence alignment.
For some crucial data it might be beneficial to align them to page boundaries
for better cache performance. This crate uses the page_size
crate to get the page size.
§Examples
assert_eq!(page_size::get(), alignment::Page::size());
let possibly_unaligned = [1, 2, 3];
let aligned = AlignedBytes::<alignment::Page>::from(possibly_unaligned);
let ptr = aligned.as_ptr();
assert_eq!(ptr.align_offset(page_size::get()), 0);
assert_eq!(aligned, possibly_unaligned);
To create a new aligned block of bytes it’s easiest to use new_zeroed
.
let aligned = AlignedBytes::<alignment::Page>::new_zeroed(1024);
let ptr = aligned.as_ptr();
assert_eq!(ptr.align_offset(page_size::get()), 0);
assert!(aligned.iter().all(|&x| x == 0));
You can also use new
to possibly skip initialization.
This is unsafe
, since the underlying memory might be uninitialized, but may be useful
if you immediately want to initialize the memory afterwards.
let mut aligned = unsafe { AlignedBytes::<alignment::Page>::new(1024) };
let ptr = aligned.as_ptr();
assert_eq!(ptr.align_offset(page_size::get()), 0);
// We cannot assert anything else, `aligned` can contain arbitrary bytes.
// To be able to read anything, we must first initialize.
for i in 0..1024 {
aligned[i] = 1;
}
let ones = std::iter::repeat(1).take(1024).collect::<Vec<u8>>();
assert_eq!(ones, aligned);
If you want a safe way to initialize the bytes, there is new_initialize
that initializes all bytes with a function of their index.
let aligned = AlignedBytes::<alignment::Page>::new_initialize(8, |i| { i as u8 });
let ptr = aligned.as_ptr();
assert_eq!(ptr.align_offset(page_size::get()), 0);
assert_eq!(aligned, [0, 1, 2, 3, 4, 5, 6, 7]);
§SIMD
Loading block-aligned bytes into SIMD is generally preferred over unaligned.
The SIMD alignment constructs are enabled with the simd
default feature.
let possibly_unaligned = [1, 2, 3];
let aligned = AlignedBytes::<alignment::SimdBlock>::from(possibly_unaligned);
let ptr = aligned.as_ptr();
assert_eq!(ptr.align_offset(alignment::SimdBlock::size()), 0);
assert_eq!(aligned, possibly_unaligned);
§Note on alignment checking
Checking alignment is hard.
pointer::align_offset
can return usize::MAX
without any reason and it explicitly says that it should not be relied on for correctness.
The above examples ignore that for assertion purposes, because there is no better way.
In reality, the check in
align_offset
just checks the remainder
of the pointer’s integer representation, plus some additional bounds checking, so it is
fine for testing purposes on most platforms.
This is an additional benefit of using aligners
, as it is a strong guarantee on alignment.
If you disagree with this assessment, feel free to contribute to this StackOverflow question.
Modules§
- Types of possible alignment type arguments for
AlignedBytes
.
Structs§
- Thin wrapper that represents an
AlignedSlice
of size at most the alignment size. - Iterator over
AlignedBlocks
of a given aligned bytes span. - Bytes aligned to a boundary represented by
A
. - Slice of bytes aligned to a boundary represented by
A
.
Traits§
- Common trait for
AlignedBytes
for all different alignments.