orx-fixed-vec
An efficient fixed capacity vector with pinned elements.
A. Motivation
There might be various situations where pinned elements are helpful.
- It is somehow required for async code, following blog could be useful for the interested.
- It is crucial in representing self-referential types with thin references.
This crate focuses more on the latter. Particularly, it aims to make it safe and convenient to build performant self-referential collections such as linked lists, trees or graphs. See PinnedVec
for complete documentation on the motivation.
FixedVec
is one of the pinned vec implementations which can be wrapped by an ImpVec
and allow building self referential collections.
B. Comparison with SplitVec
SplitVec
is another PinnedVec
implementation aiming the same goal but with different features. You may see the comparison in the table below.
FixedVec |
SplitVec |
---|---|
Implements PinnedVec => can be wrapped by an ImpVec . |
Implements PinnedVec => can be wrapped by an ImpVec . |
Requires exact capacity to be known while creating. | Can be created with any level of prior information about required capacity. |
Cannot grow beyond capacity; panics when push is called at capacity. |
Can grow dynamically. Further, it provides control on how it must grow. |
It is just a wrapper around std::vec::Vec ; hence, has equivalent performance. |
Performance-optimized built-in growth strategies also have std::vec::Vec equivalent performance. |
After the performance optimizations on the SplitVec
, it is now comparable to std::vec::Vec
in terms of performance. This might make SplitVec
a dominating choice over FixedVec
.
C. Examples
C.1. Usage similar to std::vec::Vec
Most common std::vec::Vec
operations are available in FixedVec
with the same signature.
use *;
// capacity is not optional
let mut vec = new;
assert_eq!;
vec.push;
assert!;
assert_eq!;
vec.extend_from_slice;
assert_eq!;
assert!;
// vec.push(42); // push would've panicked when vec.is_full()
vec = 10;
assert_eq!;
vec.remove;
vec.insert;
assert_eq!;
assert_eq!;
let stdvec: = vec.into;
assert_eq!;
C.2. Pinned Elements
Unless elements are removed from the vector, the memory location of an element priorly pushed to the FixedVec
never changes. This guarantee is utilized by ImpVec
in enabling immutable growth to build self referential collections.
use *;
let mut vec = new;
// push the first element
vec.push;
assert_eq!;
// let's get a pointer to the first element
let addr42 = &vec as *const usize;
// let's push 99 new elements
for i in 1..100
for i in 0..100
// the memory location of the first element remains intact
assert_eq!;
// we can safely dereference it and read the correct value
// the method is still unsafe for FixedVec
// but the undelrying guarantee will be used by ImpVec
assert_eq!;
// the next push when `vec.is_full()` panics!
// vec.push(0);
E. Benchmarks
Recall that the motivation of using a split vector is to get benefit of the pinned elements, rather than to be used in place of the standard vector which is highly efficient. The aim of the benchmarks is to make sure that the performance gap is kept within acceptable and constant limits.
Since FixedVec
is just a wrapper around the std::vec::Vec
with additional guarantees on pinned elements; it is expected to have equivalent performance. This is verified by the benchmarks which can be found at the at benches folder.
License
This library is licensed under MIT license. See LICENSE for details.