bucket_vec/lib.rs
1//! # Bucket Vector
2//!
3//! 100% `unsafe` Rust free!
4//!
5//! ## Description
6//!
7//! A vector-like data structure that organizes its elements into a set of buckets
8//! of fixed-capacity in order to guarantee that mutations to the bucket vector
9//! never moves elements and thus invalidates references to them.
10//!
11//! This is comparable to a `Vec<Box<T>>` but a lot more efficient.
12//!
13//! ## Under the Hood
14//!
15//! The `BucketVec` is really just a vector of `Bucket` instances.
16//! Whenever an element is pushed to the `BucketVec` the element is pushed onto
17//! the last `Bucket` if it isn't filled, yet.
18//! If the last `Bucket` is filled a new `Bucket` is pushed onto the `BucketVec`
19//! with a new capacity determined by the used bucket vector configuration.
20//!
21//! This way the `BucketVec` never moves elements around upon inserting new elements
22//! in order to preserve references. When a normal `Vec` is modified it can potentially
23//! invalidate references because of reallocation of the internal buffer which
24//! might cause severe bugs if references to the internal elements are stored
25//! outside the `Vec`. Note that normally Rust prevents such situations so the
26//! `BucketVec` is mainly used in the area of `unsafe` Rust where a developer
27//! actively decides that they want or need pinned references into another data
28//! structure.
29//!
30//! For the same reasons as stated above the `BucketVec` does not allow to remove
31//! or swap elements.
32//!
33//! ## Example
34//!
35//! Looking at an example `BucketVec<i32>` with the following configuration:
36//!
37//! - `start_capacity := 1`
38//! - `growth_rate := 2`
39//!
40//! We have already pushed the elements `A`,.., `K` onto it.
41//!
42//! ```no_compile
43//! [ [A], [B, C], [D, E, F, G], [H, I, J, K, _, _, _, _] ]
44//! ```
45//!
46//! Where `_` refers to a vacant bucket entry.
47//!
48//! Pushing another `L`,.., `O` onto the same `BucketVec` results in:
49//!
50//! ```no_compile
51//! [ [A], [B, C], [D, E, F, G], [H, I, J, K, L, M, N, O] ]
52//! ```
53//!
54//! So we are full on capacity for all buckets.
55//! The next time we push another element onto the `BucketVec` it will create a new `Bucket` with a capacity of `16` since `growth_rate == 2` and our current latest bucket already has a capacity of `8`.
56//!
57//! ```no_compile
58//! [ [A], [B, C], [D, E, F, G], [H, I, J, K, L, M, N, O], [P, 15 x _] ]
59//! ```
60//!
61//! Where `15 x _` denotes 15 consecutive vacant entries.
62
63#![cfg_attr(not(feature = "std"), no_std)]
64
65#[cfg(not(feature = "std"))]
66extern crate alloc;
67
68#[cfg(not(feature = "std"))]
69use alloc::vec::Vec;
70
71mod bucket;
72mod config;
73mod iter;
74mod math;
75mod scale;
76
77#[cfg(test)]
78mod tests;
79
80use self::bucket::Bucket;
81use self::math::FloatExt;
82pub use self::{
83 config::{BucketVecConfig, DefaultConfig},
84 iter::{IntoIter, Iter, IterMut},
85};
86use core::marker::PhantomData;
87
88/// A vector-like data structure that never moves its contained elements.
89///
90/// This is solved by using internal fixed-capacity buckets instead of boxing
91/// all elements in isolation.
92///
93/// # Formulas
94///
95/// ## Definitions
96///
97/// In the following we define
98///
99/// - `N := START_CAPACITY` and
100/// - `a := GROWTH_RATE`
101///
102/// ## Bucket Capacity
103///
104/// ### For `a != 1`:
105///
106/// The total capacity of all buckets until bucket `i` (not including `i`)
107/// is expressed as:
108///
109/// ```no_compile
110/// capacity_until(i) := N * (a^i - 1) / (a-1)
111/// ```
112///
113/// The capacity of the `i`th bucket is then calculated by:
114///
115/// ```no_compile
116/// capacity(i) := floor(capacity_until(i+1)) - floor(capacity_until(i))
117/// ```
118///
119/// Where `floor: f64 -> f64` rounds the `f64` down to the next even `f64`
120/// for positive `f64`.
121///
122/// Note that `capacity(i)` is approximately `capacity(i)' := N * a^i`.
123///
124/// ### For `a == 1`:
125///
126/// This case is trivial and all buckets are equally sized to have a
127/// capacity of `N`.
128///
129/// ## Accessing Elements by Index
130///
131/// Accessing the `i`th element of a `BucketVec` can be expressed by the
132/// following formulas:
133///
134/// ### For `a != 1`:
135///
136/// First we define the inverted capacity function for which
137/// `1 == capacity(i) * inv_capacity(i)` forall `i`.
138/// ```no_compile
139/// inv_capacity(i) = ceil(log(1 + (i + 1) * (a - 1) / N, a)) - 1
140/// ```
141/// Where `ceil: f64 -> f64` rounds the `f64` up to the next even `f64`
142/// for positive `f64`.
143///
144/// Having this the `bucket_index` and the `entry_index` inside the bucket
145/// indexed by `bucket_index` is expressed as:
146/// ```no_compile
147/// bucket_index(i) = inv_capacity(i)
148/// entry_index(i) = i - floor(capacity_until(bucket_index(i)))
149/// ```
150///
151/// ### For `a == 1`:
152///
153/// This case is very easy and we can simply calculate the `bucket_index` and
154/// `entry_index` by:
155///
156/// ```no_compile
157/// bucket_index(i) = i / N
158/// entry_index(i) = i % N
159/// ```
160#[derive(Debug)]
161pub struct BucketVec<T, C = DefaultConfig> {
162 /// The number of elements stored in the bucket vector.
163 len: usize,
164 /// The entry vector.
165 buckets: Vec<Bucket<T>>,
166 /// The config phantom data.
167 config: PhantomData<fn() -> C>,
168}
169
170impl<T, C> IntoIterator for BucketVec<T, C> {
171 type Item = T;
172 type IntoIter = IntoIter<T>;
173
174 fn into_iter(self) -> Self::IntoIter {
175 IntoIter::new(self)
176 }
177}
178
179impl<'a, T, C> IntoIterator for &'a BucketVec<T, C> {
180 type Item = &'a T;
181 type IntoIter = Iter<'a, T>;
182
183 fn into_iter(self) -> Self::IntoIter {
184 Iter::new(self)
185 }
186}
187
188impl<'a, T, C> IntoIterator for &'a mut BucketVec<T, C> {
189 type Item = &'a mut T;
190 type IntoIter = IterMut<'a, T>;
191
192 fn into_iter(self) -> Self::IntoIter {
193 IterMut::new(self)
194 }
195}
196
197impl<T, C> Clone for BucketVec<T, C>
198where
199 T: Clone,
200{
201 fn clone(&self) -> Self {
202 Self {
203 len: self.len(),
204 buckets: self.buckets.clone(),
205 config: Default::default(),
206 }
207 }
208}
209
210impl<T, C> PartialEq for BucketVec<T, C>
211where
212 T: PartialEq,
213{
214 fn eq(&self, other: &Self) -> bool {
215 self.iter().zip(other.iter()).all(|(lhs, rhs)| lhs == rhs)
216 }
217}
218
219impl<T, C> Eq for BucketVec<T, C> where T: Eq {}
220
221impl<T, C> core::cmp::PartialOrd for BucketVec<T, C>
222where
223 T: core::cmp::PartialOrd,
224{
225 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
226 for (lhs, rhs) in self.iter().zip(other.iter()) {
227 match lhs.partial_cmp(rhs) {
228 Some(core::cmp::Ordering::Equal) => (),
229 non_eq => return non_eq,
230 }
231 }
232 self.len().partial_cmp(&other.len())
233 }
234}
235
236impl<T, C> core::cmp::Ord for BucketVec<T, C>
237where
238 T: core::cmp::Ord,
239{
240 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
241 for (lhs, rhs) in self.iter().zip(other.iter()) {
242 match lhs.cmp(rhs) {
243 core::cmp::Ordering::Equal => (),
244 non_eq => return non_eq,
245 }
246 }
247 self.len().cmp(&other.len())
248 }
249}
250
251impl<T, C> core::hash::Hash for BucketVec<T, C>
252where
253 T: core::hash::Hash,
254{
255 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
256 self.len().hash(state);
257 for elem in self.iter() {
258 elem.hash(state);
259 }
260 }
261}
262
263/// Accessor into a recently pushed element.
264pub struct Access<'a, T> {
265 /// Access by index.
266 index: usize,
267 /// Access by exclusive reference.
268 reference: &'a mut T,
269}
270
271impl<'a, T> Access<'a, T> {
272 /// Creates a new accessor to the given index and reference.
273 pub(crate) fn new(index: usize, reference: &'a mut T) -> Self {
274 Self { index, reference }
275 }
276
277 /// Returns the index of the recently pushed element.
278 pub fn index(&self) -> usize {
279 self.index
280 }
281
282 /// Returns a shared reference to the recently pushed element.
283 pub fn into_ref(self) -> &'a T {
284 self.reference
285 }
286
287 /// Returns an exclusive reference to the recently pushed element.
288 pub fn into_mut(self) -> &'a mut T {
289 self.reference
290 }
291}
292
293impl<T> Default for BucketVec<T, DefaultConfig> {
294 fn default() -> Self {
295 Self::new()
296 }
297}
298
299impl<T, C> BucketVec<T, C> {
300 /// Creates a new empty bucket vector.
301 ///
302 /// # Note
303 ///
304 /// This does not allocate any heap memory.
305 pub fn new() -> Self {
306 Self {
307 len: 0,
308 buckets: Vec::new(),
309 config: Default::default(),
310 }
311 }
312
313 /// Returns the number of elements stored in the bucket vector.
314 pub fn len(&self) -> usize {
315 self.len
316 }
317
318 /// Returns `true` if the bucket vector is empty.
319 pub fn is_empty(&self) -> bool {
320 self.len() == 0
321 }
322
323 /// Returns an iterator that yields shared references to the elements of the bucket vector.
324 pub fn iter(&self) -> Iter<T> {
325 Iter::new(self)
326 }
327
328 /// Returns an iterator that yields exclusive reference to the elements of the bucket vector.
329 pub fn iter_mut(&mut self) -> IterMut<T> {
330 IterMut::new(self)
331 }
332
333 /// Returns a shared reference to the first element of the bucket vector.
334 pub fn first(&self) -> Option<&T> {
335 if self.is_empty() {
336 return None
337 }
338 Some(&self.buckets[0][0])
339 }
340
341 /// Returns an exclusive reference to the first element of the bucket vector.
342 pub fn first_mut(&mut self) -> Option<&mut T> {
343 if self.is_empty() {
344 return None
345 }
346 Some(&mut self.buckets[0][0])
347 }
348
349 /// Returns a shared reference to the last element of the bucket vector.
350 pub fn last(&self) -> Option<&T> {
351 if self.is_empty() {
352 return None
353 }
354 let len_buckets = self.buckets.len();
355 let len_entries = self.buckets[len_buckets - 1].len();
356 Some(&self.buckets[len_buckets - 1][len_entries - 1])
357 }
358
359 /// Returns an exclusive reference to the last element of the bucket vector.
360 pub fn last_mut(&mut self) -> Option<&mut T> {
361 if self.is_empty() {
362 return None
363 }
364 let len_buckets = self.buckets.len();
365 let len_entries = self.buckets[len_buckets - 1].len();
366 Some(&mut self.buckets[len_buckets - 1][len_entries - 1])
367 }
368}
369
370impl<T, C> BucketVec<T, C>
371where
372 C: BucketVecConfig,
373{
374 /// Returns the bucket index and its internal entry index for the given
375 /// bucket vector index into an element.
376 ///
377 /// Returns `None` if the index is out of bounds.
378 fn bucket_entry_indices(&self, index: usize) -> Option<(usize, usize)> {
379 if index >= self.len() {
380 return None;
381 }
382 Some(config::bucket_entry_indices::<C>(index))
383 }
384
385 /// Returns a shared reference to the element at the given index if any.
386 pub fn get(&self, index: usize) -> Option<&T> {
387 self.bucket_entry_indices(index)
388 .and_then(|(x, y)| self.buckets[x].get(y))
389 }
390
391 /// Returns an exclusive reference to the element at the given index if any.
392 pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
393 self.bucket_entry_indices(index)
394 .and_then(move |(x, y)| self.buckets[x].get_mut(y))
395 }
396
397 /// Pushes a new bucket containing the new value onto the bucket vector.
398 fn push_bucket(&mut self, new_value: T) {
399 let len_buckets = self.buckets.len();
400 let new_capacity = config::bucket_capacity::<C>(len_buckets);
401 let mut new_bucket = Bucket::new(new_capacity);
402 new_bucket.push(new_value);
403 self.buckets.push(new_bucket);
404 self.len += 1;
405 }
406
407 /// Pushes a new element onto the bucket vector.
408 ///
409 /// # Note
410 ///
411 /// This operation will never move other elements, reallocates or otherwise
412 /// invalidate pointers of elements contained by the bucket vector.
413 pub fn push(&mut self, new_value: T) {
414 if let Some(bucket) = self.buckets.last_mut() {
415 if bucket.len() < bucket.capacity() {
416 bucket.push(new_value);
417 self.len += 1;
418 return;
419 }
420 }
421 self.push_bucket(new_value);
422 }
423
424 /// Pushes a new element onto the bucket vector and returns access to it.
425 ///
426 /// # Note
427 ///
428 /// This operation will never move other elements, reallocates or otherwise
429 /// invalidate pointers of elements contained by the bucket vector.
430 pub fn push_get(&mut self, new_value: T) -> Access<T> {
431 let index = self.len();
432 self.push(new_value);
433 let len_buckets = self.buckets.len();
434 let len_entries = self.buckets[len_buckets - 1].len();
435 Access::new(index, &mut self.buckets[len_buckets - 1][len_entries - 1])
436 }
437}
438
439impl<T, C> core::iter::FromIterator<T> for BucketVec<T, C>
440where
441 C: BucketVecConfig,
442{
443 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
444 let mut vec = Self::new();
445 <Self as core::iter::Extend<T>>::extend(&mut vec, iter);
446 vec
447 }
448}
449
450impl<T, C> core::iter::Extend<T> for BucketVec<T, C>
451where
452 C: BucketVecConfig,
453{
454 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
455 for item in iter {
456 self.push(item)
457 }
458 }
459}