Skip to main content

tl/inline/
vec.rs

1use core::fmt::{Debug, Formatter};
2use core::mem::MaybeUninit;
3use core::ops::Index;
4use core::ptr;
5
6use crate::ParseError;
7
8/// A wrapper around a `Vec<T>` that lives on the stack if it is small enough.
9#[derive(Debug, Clone)]
10pub struct InlineVec<T, const N: usize>(InlineVecInner<T, N>);
11
12impl<T, const N: usize> InlineVec<T, N> {
13    /// Creates a new InlineVec
14    #[inline]
15    pub(crate) fn new() -> Self {
16        Self(InlineVecInner::new())
17    }
18
19    /// Returns the number of elements in the vector
20    #[inline]
21    pub fn len(&self) -> usize {
22        self.0.len()
23    }
24
25    /// Returns true if the vector contains no elements
26    #[inline]
27    pub fn is_empty(&self) -> bool {
28        self.len() == 0
29    }
30
31    /// Checks whether this vector is allocated on the heap
32    #[inline]
33    pub fn is_heap_allocated(&self) -> bool {
34        self.0.is_heap_allocated()
35    }
36
37    /// If `self` is inlined, this returns the underlying raw parts that make up this `InlineVec`.
38    ///
39    /// Only the first `.1` elements are initialized.
40    #[inline]
41    pub fn inline_parts_mut(&mut self) -> Option<(&mut [MaybeUninit<T>; N], usize)> {
42        self.0.inline_parts_mut()
43    }
44
45    /// Copies `self` into a new `Vec<T>`
46    #[inline]
47    #[cfg(feature = "std")]
48    pub fn to_vec(&self) -> Vec<T>
49    where
50        T: Clone,
51    {
52        self.0.to_vec()
53    }
54
55    /// Inserts a new element into the vector
56    #[inline]
57    pub fn push(&mut self, value: T) -> Result<(), ParseError> {
58        self.0.push(value)
59    }
60
61    /// Returns a reference to the value at the given index
62    #[inline]
63    pub fn get(&self, index: usize) -> Option<&T> {
64        self.0.get(index)
65    }
66
67    /// Returns a mutable reference to the value at the given index
68    #[inline]
69    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
70        self.0.get_mut(index)
71    }
72
73    /// Returns the last element in the vector.
74    #[inline]
75    pub fn last(&self) -> Option<&T> {
76        self.as_slice().last()
77    }
78
79    /// Removes the last element and returns it, or `None` if it is empty.
80    #[inline]
81    pub fn pop(&mut self) -> Option<T> {
82        if self.is_empty() {
83            None
84        } else {
85            Some(self.remove(self.len() - 1))
86        }
87    }
88
89    /// Removes an element at a given index
90    ///
91    /// # Panics
92    /// Just like `Vec::remove`, this method will panic if the index is out of bounds.
93    #[inline]
94    pub fn remove(&mut self, index: usize) -> T {
95        self.0.remove(index)
96    }
97
98    /// Returns an iterator over the elements of this vector
99    #[inline]
100    pub fn iter(&self) -> InlineVecIter<'_, T, N> {
101        self.0.iter()
102    }
103
104    /// Returns a slice to the contents of this vector
105    #[inline]
106    pub fn as_slice(&self) -> &[T] {
107        self.0.as_slice()
108    }
109
110    /// Returns a mutable slice to the contents of this vector.
111    #[inline]
112    pub fn as_mut_slice(&mut self) -> &mut [T] {
113        self.0.as_mut_slice()
114    }
115}
116
117enum InlineVecInner<T, const N: usize> {
118    Inline {
119        len: usize,
120        data: [MaybeUninit<T>; N],
121    },
122    #[cfg(feature = "std")]
123    Heap(Vec<T>),
124}
125
126impl<T, const N: usize> Debug for InlineVecInner<T, N>
127where
128    T: Debug,
129{
130    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
131        write!(f, "InlineVec<{} items>", self.len())
132    }
133}
134
135impl<T, const N: usize> Clone for InlineVecInner<T, N>
136where
137    T: Clone,
138{
139    fn clone(&self) -> Self {
140        match self {
141            #[cfg(feature = "std")]
142            Self::Heap(m) => Self::Heap(m.clone()),
143            Self::Inline { len, data } => {
144                let mut new_data = super::uninit_array();
145
146                let iter = data.iter().take(*len).enumerate();
147
148                for (idx, element) in iter {
149                    let element = unsafe { &*element.as_ptr() };
150                    new_data[idx] = MaybeUninit::new(T::clone(element));
151                }
152
153                Self::Inline {
154                    len: *len,
155                    data: new_data,
156                }
157            }
158        }
159    }
160}
161
162impl<T, const N: usize> InlineVecInner<T, N> {
163    #[inline]
164    pub(crate) fn new() -> Self {
165        Self::Inline {
166            len: 0,
167            data: super::uninit_array(),
168        }
169    }
170
171    pub fn as_slice(&self) -> &[T] {
172        match self {
173            Self::Inline { len, data } => unsafe {
174                core::slice::from_raw_parts(data.as_ptr() as *const T, *len)
175            },
176            #[cfg(feature = "std")]
177            Self::Heap(v) => v.as_slice(),
178        }
179    }
180
181    pub fn as_mut_slice(&mut self) -> &mut [T] {
182        match self {
183            Self::Inline { len, data } => unsafe {
184                core::slice::from_raw_parts_mut(data.as_mut_ptr() as *mut T, *len)
185            },
186            #[cfg(feature = "std")]
187            Self::Heap(v) => v.as_mut_slice(),
188        }
189    }
190
191    #[inline]
192    pub fn inline_parts_mut(&mut self) -> Option<(&mut [MaybeUninit<T>; N], usize)> {
193        match self {
194            #[cfg(feature = "std")]
195            Self::Heap(_) => None,
196            Self::Inline { len, data } => Some((data, *len)),
197        }
198    }
199
200    #[cfg(feature = "std")]
201    pub fn to_vec(&self) -> Vec<T>
202    where
203        T: Clone,
204    {
205        match &self {
206            InlineVecInner::Heap(m) => m.to_vec(),
207            InlineVecInner::Inline { len, data } => {
208                let mut new_data = Vec::with_capacity(*len);
209
210                let iter = data.iter().take(*len);
211
212                for element in iter {
213                    new_data.push(unsafe { T::clone(&*element.as_ptr()) });
214                }
215
216                new_data
217            }
218        }
219    }
220
221    #[inline]
222    pub fn iter(&self) -> InlineVecIter<'_, T, N> {
223        InlineVecIter { idx: 0, vec: self }
224    }
225
226    #[inline]
227    pub fn len(&self) -> usize {
228        match self {
229            Self::Inline { len, .. } => *len,
230            #[cfg(feature = "std")]
231            Self::Heap(vec) => vec.len(),
232        }
233    }
234
235    pub fn get(&self, idx: usize) -> Option<&T> {
236        match self {
237            Self::Inline { data, len } => {
238                if idx < *len {
239                    Some(unsafe { &*data.get_unchecked(idx).as_ptr() })
240                } else {
241                    None
242                }
243            }
244            #[cfg(feature = "std")]
245            Self::Heap(vec) => vec.get(idx),
246        }
247    }
248
249    pub fn get_mut(&mut self, idx: usize) -> Option<&mut T> {
250        match self {
251            Self::Inline { data, len } => {
252                if idx < *len {
253                    Some(unsafe { &mut *data.get_unchecked_mut(idx).as_mut_ptr() })
254                } else {
255                    None
256                }
257            }
258            #[cfg(feature = "std")]
259            Self::Heap(vec) => vec.get_mut(idx),
260        }
261    }
262
263    pub fn remove(&mut self, idx: usize) -> T {
264        match self {
265            Self::Inline { data, len } => {
266                assert!(idx < *len);
267
268                // at this point we know idx is in bounds
269                // carefully replace the value with MaybeUninit::uninit(), so it can be returned
270                let element = unsafe {
271                    core::mem::replace(data.get_unchecked_mut(idx), MaybeUninit::uninit())
272                };
273
274                for i in idx + 1..*len {
275                    // TODO(y21): data.swap_unchecked() worth it?
276                    data.swap(i, i - 1);
277                }
278
279                *len -= 1;
280
281                // we've made sure that idx is in bounds and if idx is in bounds, then `T` must be initialized
282                unsafe { element.assume_init() }
283            }
284            #[cfg(feature = "std")]
285            Self::Heap(h) => h.remove(idx),
286        }
287    }
288
289    pub fn push(&mut self, value: T) -> Result<(), ParseError> {
290        let (array, len) = match self {
291            Self::Inline { data, len } => (data, len),
292            #[cfg(feature = "std")]
293            Self::Heap(vec) => {
294                vec.push(value);
295                return Ok(());
296            }
297        };
298
299        if *len >= N {
300            #[cfg(not(feature = "std"))]
301            {
302                return Err(ParseError::ChildCapacityExceeded);
303            }
304
305            #[cfg(feature = "std")]
306            {
307                let mut vec = Vec::with_capacity(*len + 1);
308
309                // move old elements to heap
310                for element in array.iter_mut().take(*len) {
311                    let element = core::mem::replace(element, MaybeUninit::uninit());
312
313                    vec.push(unsafe { element.assume_init() });
314                }
315
316                // push the new element
317                vec.push(value);
318                let new_heap = InlineVecInner::Heap(vec);
319
320                // do not call the destructor!
321                unsafe { ptr::write(self, new_heap) };
322            }
323        } else {
324            array[*len].write(value);
325            *len += 1;
326        }
327
328        Ok(())
329    }
330
331    #[inline]
332    pub fn is_heap_allocated(&self) -> bool {
333        #[cfg(feature = "std")]
334        {
335            matches!(self, Self::Heap(_))
336        }
337        #[cfg(not(feature = "std"))]
338        {
339            false
340        }
341    }
342}
343
344impl<T, const N: usize> Index<usize> for InlineVec<T, N> {
345    type Output = T;
346
347    fn index(&self, idx: usize) -> &Self::Output {
348        self.0.get(idx).expect("index out of bounds")
349    }
350}
351
352/// An iterator over the elements stored in an [`InlineVec`]
353pub struct InlineVecIter<'a, T, const N: usize> {
354    vec: &'a InlineVecInner<T, N>,
355    idx: usize,
356}
357
358impl<'a, T, const N: usize> Iterator for InlineVecIter<'a, T, N> {
359    type Item = &'a T;
360
361    fn next(&mut self) -> Option<Self::Item> {
362        self.idx += 1;
363        self.vec.get(self.idx - 1)
364    }
365}
366
367impl<T, const N: usize> Drop for InlineVecInner<T, N> {
368    fn drop(&mut self) {
369        if let Some((data, len)) = self.inline_parts_mut() {
370            for element in data.iter_mut().take(len) {
371                unsafe { ptr::drop_in_place(element.as_mut_ptr()) };
372            }
373        }
374    }
375}
376
377#[cfg(all(test, feature = "std"))]
378mod tests {
379    #![allow(unused_must_use)]
380
381    use super::*;
382
383    #[test]
384    fn inlinevec_to_vec_stack() {
385        let mut x = InlineVec::<usize, 4>::new();
386
387        for i in 0..4 {
388            x.push(i * 2);
389        }
390
391        assert!(!x.is_heap_allocated());
392        assert_eq!(x.len(), 4);
393
394        let xx = x.to_vec();
395        assert_eq!(xx.as_slice(), &[0, 2, 4, 6]);
396
397        x.push(42);
398        assert!(x.is_heap_allocated());
399        assert_eq!(x.as_slice(), &[0, 2, 4, 6, 42]);
400        assert_eq!(x.get(4), Some(&42));
401
402        let xx = x.to_vec();
403        assert_eq!(xx.as_slice(), &[0, 2, 4, 6, 42]);
404    }
405
406    #[test]
407    fn inlinevec_to_vec_heap() {
408        let mut x = InlineVec::<String, 4>::new();
409
410        for i in 0..4u8 {
411            x.push(i.to_string());
412        }
413
414        assert!(!x.is_heap_allocated());
415        assert_eq!(x.len(), 4);
416
417        let xx = x.to_vec();
418        assert_eq!(xx.as_slice(), &["0", "1", "2", "3"]);
419
420        x.push("1337".into());
421        assert!(x.is_heap_allocated());
422        assert_eq!(x.as_slice(), &["0", "1", "2", "3", "1337"]);
423        assert_eq!(x.get(4).map(|x| &**x), Some("1337"));
424
425        let xx = x.to_vec();
426        assert_eq!(xx.as_slice(), &["0", "1", "2", "3", "1337"]);
427    }
428
429    #[test]
430    fn inlinevec_drop_stack() {
431        let mut x = InlineVec::<String, 4>::new();
432
433        for i in 0..3u8 {
434            x.push(i.to_string());
435        }
436
437        assert_eq!(x.as_slice(), &["0", "1", "2"]);
438        assert!(!x.is_heap_allocated());
439    }
440
441    #[test]
442    fn inlinehashmap_drop_heap() {
443        let mut x = InlineVec::<String, 4>::new();
444
445        for i in 0..8u8 {
446            x.push(i.to_string());
447        }
448
449        assert_eq!(x.as_slice(), &["0", "1", "2", "3", "4", "5", "6", "7"]);
450        assert!(x.is_heap_allocated());
451    }
452
453    #[test]
454    fn inlinevec_iter() {
455        let mut x = InlineVecInner::<usize, 2>::new();
456        x.push(13);
457        x.push(42);
458        x.push(17);
459        x.push(19);
460        let mut iter = x.iter();
461        assert_eq!(iter.next(), Some(&13));
462        assert_eq!(iter.next(), Some(&42));
463        assert_eq!(iter.next(), Some(&17));
464        assert_eq!(iter.next(), Some(&19));
465        assert_eq!(iter.next(), None);
466    }
467
468    #[test]
469    fn inlinevec_remove() {
470        let mut x = InlineVecInner::<usize, 4>::new();
471        x.push(789);
472        assert_eq!(x.len(), 1);
473        assert_eq!(x.get(0), Some(&789));
474        assert_eq!(x.remove(0), 789);
475        assert_eq!(x.len(), 0);
476
477        {
478            let mut xc = x.clone();
479            // out of bounds index must panic
480            assert!(std::panic::catch_unwind(move || xc.remove(0)).is_err());
481        }
482
483        for i in 0..4 {
484            x.push(i * 2);
485        }
486
487        assert!(!x.is_heap_allocated());
488        assert_eq!(x.as_slice(), &[0, 2, 4, 6]);
489
490        assert_eq!(x.remove(2), 4);
491        assert_eq!(x.as_slice(), &[0, 2, 6]);
492
493        assert_eq!(x.remove(2), 6);
494        assert_eq!(x.as_slice(), &[0, 2]);
495
496        assert_eq!(x.remove(1), 2);
497        assert_eq!(x.as_slice(), &[0]);
498
499        assert_eq!(x.remove(0), 0);
500        assert_eq!(x.as_slice(), &[]);
501        assert!(!x.is_heap_allocated());
502
503        // trigger heap allocation
504        for i in 0..8 {
505            x.push(i * 2);
506        }
507        assert!(x.is_heap_allocated());
508        assert_eq!(x.as_slice(), &[0, 2, 4, 6, 8, 10, 12, 14]);
509
510        assert_eq!(x.remove(7), 14);
511        assert_eq!(x.remove(0), 0);
512    }
513
514    #[test]
515    fn inlinevec_remove_heap() {
516        let mut x = InlineVecInner::<String, 4>::new();
517        x.push("test".into());
518        assert_eq!(x.len(), 1);
519        assert_eq!(x.remove(0), "test");
520        assert_eq!(x.len(), 0);
521    }
522
523    #[test]
524    fn inlinevec() {
525        let mut x = InlineVecInner::<usize, 4>::new();
526        assert_eq!(x.len(), 0);
527        assert_eq!(x.get(0), None);
528        assert!(!x.is_heap_allocated());
529
530        x.push(1337);
531        assert_eq!(x.len(), 1);
532        assert_eq!(x.get(0), Some(&1337));
533        assert!(!x.is_heap_allocated());
534
535        for v in 0..3 {
536            x.push(v);
537        }
538
539        assert_eq!(x.len(), 4);
540
541        // this call should move the vector to the heap
542        x.push(42);
543        assert_eq!(x.len(), 5);
544        assert!(x.is_heap_allocated());
545
546        // check that the old vector is still valid
547        assert_eq!(x.get(0), Some(&1337));
548
549        for v in 0..500 {
550            x.push(v);
551        }
552
553        assert_eq!(x.len(), 505);
554        assert!(x.is_heap_allocated());
555
556        assert_eq!(x.get(1337), None);
557
558        *x.get_mut(0).unwrap() = 444;
559        assert_eq!(x.get(0), Some(&444));
560        assert_eq!(x.get_mut(99999 /* out of bounds */), None);
561    }
562
563    #[test]
564    fn inlinevec_as_slice() {
565        let mut x = InlineVecInner::<usize, 4>::new();
566        x.push(1337);
567        x.push(42);
568        x.push(17);
569        assert_eq!(x.as_slice(), &[1337, 42, 17]);
570        x.push(19);
571        x.push(34);
572        assert_eq!(x.as_slice(), &[1337, 42, 17, 19, 34]);
573    }
574}