persist_o_vec/
lib.rs

1//! The purpose of "persist-o-vec" is to:
2//!
3//! - prevent reallocation
4//! - remove items without shifting right to left
5//! - re-use freed slots, pop, push, and remove, fast
6//! - iterate over used slots only
7//!
8//! As such, you must allocate what you need before use up to the maximum determined
9//! by the chosen indexer feature. In future there will be an option to increase
10//! the capacity if required.
11//!
12//! Use should be similar to `Vec`.
13//!
14//! **WIP!**
15
16use std::marker::PhantomData;
17use std::ptr;
18
19#[derive(Debug)]
20struct Entry<T> {
21    index: usize,
22    data: Option<T>,
23    // The pointer must always be created from mutable
24    next: *mut Entry<T>,
25    prev: *mut Entry<T>,
26    _pin: std::marker::PhantomPinned,
27}
28
29/// Iteration will not always be in order
30#[derive(Debug)]
31pub struct Persist<T> {
32    entries: Vec<Entry<T>>,
33    /// contains the indexes to `None` slots
34    // The pointer must always be created from mutable
35    free: Option<*mut Entry<T>>,
36    /// contains the indexes to used slots
37    // The pointer must always be created from mutable
38    used: Option<*mut Entry<T>>,
39    length: usize,
40}
41
42impl<T> Persist<T> {
43    /// Ensure that the current and previous Entry are linked
44    #[inline(always)]
45    fn link_to_prev(i: usize, entries: &mut Vec<Entry<T>>) {
46        entries[i - 1].next = &mut entries[i];
47        entries[i].prev = &mut entries[i - 1];
48    }
49
50    /// Allocate with capacity.
51    ///
52    /// This is the only way to create a new persistent vec.
53    ///
54    /// # Panics
55    ///
56    /// Will panic if the selected capacity is larger than the ability for
57    /// `Persist` to internally index in to
58    #[inline]
59    pub fn with_capacity(capacity: usize) -> Persist<T> {
60        let mut entries = Vec::with_capacity(capacity);
61        for i in 0..capacity {
62            entries.push(Entry {
63                index: i,
64                data: None,
65                next: ptr::null_mut(),
66                prev: ptr::null_mut(),
67                _pin: std::marker::PhantomPinned,
68            });
69            if i > 0 {
70                Persist::link_to_prev(i, &mut entries);
71            }
72        }
73        let first = &mut entries[0] as *mut Entry<T>;
74        Persist {
75            entries,
76            free: Some(first),
77            used: None,
78            length: 0,
79        }
80    }
81
82    /// Allocate with capacity and fill with values produced by a closure
83    ///
84    /// This is a secondary way to create a new persistent vec and is a good way
85    /// to do so if you know the storage needs to be filled.
86    ///
87    /// # Panics
88    ///
89    /// Will panic if the selected capacity is larger than the ability for
90    /// `Persist` to internally index in to
91    #[inline]
92    pub fn with_capacity_filled_by<F>(capacity: usize, func: F) -> Persist<T>
93    where
94        F: Fn() -> T,
95    {
96        let mut entries = Vec::with_capacity(capacity);
97        for i in 0..capacity {
98            entries.push(Entry {
99                index: i,
100                data: Some(func()),
101                next: ptr::null_mut(),
102                prev: ptr::null_mut(),
103                _pin: std::marker::PhantomPinned,
104            });
105            if i > 0 {
106                Persist::link_to_prev(i, &mut entries);
107            }
108        }
109        let first = &mut entries[0] as *mut Entry<T>;
110        Persist {
111            entries,
112            free: None,
113            used: Some(first),
114            length: capacity,
115        }
116    }
117
118    #[inline]
119    pub fn from(slice: &[T]) -> Persist<T>
120    where
121        T: Clone,
122    {
123        let mut entries = Vec::with_capacity(slice.len());
124        for (i, obj) in slice.iter().enumerate() {
125            entries.push(Entry {
126                index: i,
127                data: Some(obj.clone()),
128                next: ptr::null_mut(),
129                prev: ptr::null_mut(),
130                _pin: std::marker::PhantomPinned,
131            });
132            if i > 0 {
133                Persist::link_to_prev(i, &mut entries);
134            }
135        }
136        let first = &mut entries[0] as *mut Entry<T>;
137        Persist {
138            entries,
139            free: None,
140            used: Some(first),
141            length: slice.len(),
142        }
143    }
144
145    // TODO: need to rebuilt the linked list after to ensure that
146    //  it is still valid
147    //
148    //    /// Reserve extra capacity. This may move the allocations and invalidate any
149    //    /// pointers that are held to stored data.
150    //    #[inline]
151    //    pub fn reserve(&mut self, additional: usize) {
152    //        let old_cap = self.entries.len();
153    //        let new_cap = self.entries.len() + additional;
154    //        self.entries.reserve_exact(additional);
155    //        for i in old_cap..new_cap {
156    //            self.entries.push(Entry {
157    //                data: None,
158    //                next: ptr::null_mut(),
159    //                prev: ptr::null_mut(),
160    //            });
161    //            if i > old_cap {
162    //                Persist::link_to_prev(i, &mut self.entries);
163    //            }
164    //        }
165    //        // If there is a free, append it to the end of the new alloc
166    //        unsafe {
167    //            if let Some(mut free) = self.free.as_mut() {
168    //                free.prev = &mut self.entries[new_cap - 1];
169    //                self.entries[new_cap - 1].next = free;
170    //            }
171    //        }
172    //        self.free = &mut self.entries[old_cap];
173    //    }
174
175    /// Returns the actual used length regardless of capacity
176    #[inline]
177    pub fn len(&self) -> usize {
178        self.length
179    }
180
181    #[inline]
182    pub fn is_empty(&self) -> bool {
183        self.length == 0
184    }
185
186    /// Returns the storage capacity
187    #[inline]
188    pub fn capacity(&self) -> usize {
189        self.entries.capacity()
190    }
191
192    /// Clear the storage out while keeping allocated memory
193    ///
194    /// Should not ever panic
195    #[inline]
196    pub fn clear(&mut self) {
197        for i in 0..self.entries.len() {
198            self.entries[i].data = None;
199            if i > 0 {
200                self.entries[i - 1].next = &mut self.entries[i];
201                self.entries[i].prev = &mut self.entries[i - 1];
202            }
203            // make sure head and tail are reset
204            if i == 0 {
205                self.entries[i].prev = ptr::null_mut();
206            }
207            if i == self.entries.len() - 1 {
208                self.entries[i].next = ptr::null_mut();
209            }
210        }
211        self.free = Some(&mut self.entries[0]);
212        self.used = None;
213        self.length = 0;
214    }
215
216    #[inline]
217    pub fn get(&self, index: usize) -> Option<&T> {
218        if let Some(entry) = self.entries.get(index) {
219            return entry.data.as_ref();
220        }
221        None
222    }
223
224    #[inline]
225    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
226        if let Some(entry) = self.entries.get_mut(index) {
227            return entry.data.as_mut();
228        }
229        None
230    }
231
232    /// Check if there is a value at this index
233    #[inline]
234    pub fn is_index_live(&self, index: usize) -> bool {
235        if let Some(entry) = self.entries.get(index) {
236            if entry.data.is_some() {
237                return true;
238            }
239        }
240        false
241    }
242
243    // TODO: Push top, push bottom
244    /// Push `T` on to storage.
245    ///
246    /// A push is not guaranteed to push in any
247    /// particular order if the internal storage has empty locations (typical after
248    /// many `remove`). For this reason it will return the index pushed to.
249    ///
250    /// Returns `None` if there are no free slots left
251    #[inline]
252    pub fn push(&mut self, value: T) -> Option<usize> {
253        unsafe {
254            if let Some(into_used) = self.free.as_ref() {
255                if let Some(mut into_used) = into_used.as_mut() {
256                    into_used.data = Some(value);
257                    // move next free to head
258                    let next_free = into_used.next;
259                    Persist::disassociate_entry(into_used);
260                    self.free = Some(next_free);
261                    // make it head
262                    if let Some(head_free) = self.free {
263                        if let Some(head_free) = head_free.as_mut() {
264                            head_free.prev = ptr::null_mut();
265                        }
266                    }
267
268                    if let Some(used) = self.used {
269                        into_used.next = used;
270                        (*used).prev = into_used;
271                    }
272                    self.used = Some(into_used);
273                    self.length += 1;
274                    return Some(into_used.index);
275                }
276            }
277        }
278        None
279    }
280
281    /// Pulls the entry out of the linked list it is in and nulls its next/prev
282    #[inline(always)]
283    fn disassociate_entry(slot: &mut Entry<T>) {
284        unsafe {
285            if let Some(mut prev) = slot.prev.as_mut() {
286                if let Some(mut next) = slot.next.as_mut() {
287                    prev.next = next;
288                    next.prev = prev;
289                } else {
290                    // only prev?
291                    prev.next = ptr::null_mut();
292                }
293            } else if let Some(mut next) = slot.next.as_mut() {
294                // only next?
295                next.prev = ptr::null_mut();
296            }
297        }
298        slot.next = ptr::null_mut();
299        slot.prev = ptr::null_mut();
300    }
301
302    /// Insert `T` at location. Returns existing value in that location or `None`.
303    ///
304    /// # Panics
305    ///
306    /// Will panic is the index is out of range
307    #[inline]
308    pub fn insert(&mut self, index: usize, value: T) -> Option<T> {
309        // check if used first
310        if self.entries[index].data.is_none() {
311            let mut slot = &mut self.entries[index];
312            // remove it out of links
313            Persist::disassociate_entry(slot);
314            // make it the head
315            slot.prev = ptr::null_mut();
316            // add it to used
317            unsafe {
318                if let Some(first_used) = self.used {
319                    slot.next = first_used;
320                    (*first_used).prev = slot
321                }
322            }
323
324            self.used = Some(&mut self.entries[index]);
325        }
326
327        let mut data: Option<T> = Some(value);
328        std::mem::swap(&mut self.entries[index].data, &mut data);
329        self.length += 1;
330        data
331    }
332
333    // TODO: pop top, pop bottom
334    /// Pop the last value in the `Persist`
335    #[inline]
336    pub fn pop(&mut self) -> Option<T> {
337        unsafe {
338            if let Some(slot) = self.used {
339                // Shift next to head
340                if let Some(mut next) = (*slot).next.as_mut() {
341                    next.prev = ptr::null_mut();
342                    self.used = Some(next);
343                }
344                self.length -= 1;
345                // Yeet!
346                return std::mem::take(&mut (*slot).data);
347            }
348        }
349        None
350    }
351
352    /// Remove the item at this index and return it if it exists. Does not shift
353    /// elements after it to the left.
354    #[inline]
355    pub fn remove(&mut self, index: usize) -> Option<T> {
356        let mut slot = &mut self.entries[index];
357        // remove it out of links
358        Persist::disassociate_entry(slot);
359        // make it the head
360        slot.prev = ptr::null_mut();
361        // add it to used
362        unsafe {
363            if let Some(first_free) = self.free {
364                if let Some(first_free) = first_free.as_mut() {
365                    slot.next = first_free;
366                    (*first_free).prev = slot;
367                }
368            }
369        }
370
371        self.length -= 1;
372        self.free = Some(&mut self.entries[index]);
373        // Yeet!
374        std::mem::take(&mut self.entries[index].data)
375    }
376
377    #[inline]
378    pub fn iter(&self) -> Iter<T> {
379        if let Some(entry) = self.used {
380            return Iter {
381                entry,
382                n_entries: self.length,
383                phantom: PhantomData,
384            };
385        };
386
387        Iter {
388            entry: &self.entries[0],
389            n_entries: self.length,
390            phantom: PhantomData,
391        }
392    }
393
394    #[inline]
395    pub fn iter_mut(&mut self) -> IterMut<T> {
396        if let Some(entry) = self.used {
397            return IterMut {
398                entry,
399                n_entries: self.length,
400                phantom: PhantomData,
401            };
402        };
403        IterMut {
404            entry: &mut self.entries[0],
405            n_entries: self.length,
406            phantom: PhantomData,
407        }
408    }
409}
410
411#[derive(Debug)]
412pub struct Iter<'a, T> {
413    entry: *const Entry<T>,
414    n_entries: usize,
415    phantom: PhantomData<&'a T>,
416}
417
418impl<'a, T> Iterator for Iter<'a, T> {
419    type Item = &'a T;
420
421    #[inline]
422    fn next(&mut self) -> Option<&'a T> {
423        if self.n_entries == 0 {
424            return None;
425        }
426
427        unsafe {
428            let data: Option<&'a T> = (*self.entry).data.as_ref();
429            self.entry = (*self.entry).next;
430            self.n_entries -= 1;
431            data
432        }
433    }
434}
435
436#[derive(Debug)]
437pub struct IterMut<'a, T> {
438    entry: *mut Entry<T>,
439    n_entries: usize,
440    phantom: PhantomData<&'a mut T>,
441}
442
443impl<'a, T> Iterator for IterMut<'a, T> {
444    type Item = &'a mut T;
445
446    #[inline]
447    fn next(&mut self) -> Option<&'a mut T> {
448        if self.n_entries == 0 {
449            return None;
450        }
451
452        unsafe {
453            let data: Option<&'a mut T> = (*self.entry).data.as_mut();
454            self.entry = (*self.entry).next;
455            self.n_entries -= 1;
456            data
457        }
458    }
459}
460
461/// Total capacity will be set from the length of the slice
462impl<T: Clone> From<&[T]> for Persist<T> {
463    fn from(s: &[T]) -> Persist<T> {
464        Persist::from(s)
465    }
466}
467
468/// Total capacity will be set from the length of the slice
469impl<T: Clone> From<&mut [T]> for Persist<T> {
470    fn from(s: &mut [T]) -> Persist<T> {
471        Persist::from(s)
472    }
473}
474
475#[cfg(test)]
476mod tests {
477    use crate::{Entry, Persist};
478
479    #[test]
480    fn with_capacity() {
481        let p: Persist<u32> = Persist::with_capacity(10);
482        assert_eq!(p.entries.capacity(), 10);
483    }
484
485    #[test]
486    fn get() {
487        let mut p: Persist<u32> = Persist::with_capacity(10);
488
489        p.push(13);
490        p.push(14);
491        p.push(15);
492
493        let two = p.get(1).unwrap();
494        assert_eq!(*two, 14);
495    }
496
497    #[test]
498    fn get_mut() {
499        let mut p: Persist<u32> = Persist::with_capacity(10);
500
501        p.push(13);
502        p.push(14);
503        p.push(15);
504
505        {
506            let two = p.get_mut(1).unwrap();
507            *two *= 2;
508        }
509        let two = p.get(1).unwrap();
510        assert_eq!(*two, 28);
511    }
512
513    #[test]
514    fn index_validation() {
515        let mut p: Persist<u32> = Persist::with_capacity(10);
516
517        p.push(13);
518        p.push(14);
519
520        assert!(p.is_index_live(0));
521        assert!(p.is_index_live(1));
522        assert!(!p.is_index_live(3));
523    }
524
525    //    #[test]
526    //    fn reserve() {
527    //        let mut p: Persist<u32> = Persist::with_capacity(10);
528    //
529    //        p.push(13);
530    //        p.push(14);
531    //        p.push(15);
532    //
533    //        assert_eq!(p.entries.len(), 10);
534    //        p.reserve(10);
535    //        assert_eq!(p.entries.len(), 20);
536    //    }
537
538    #[test]
539    fn clear() {
540        let _p: Persist<u32> = Persist::with_capacity(10);
541    }
542
543    #[test]
544    fn pop() {
545        let mut p: Persist<u32> = Persist::with_capacity(10);
546
547        p.push(13);
548        p.push(14);
549        p.push(15);
550
551        p.pop();
552    }
553
554    #[test]
555    fn push_to_full_then_pop_all() {
556        #[derive(Debug, PartialOrd, PartialEq)]
557        struct Heading {
558            x: u32,
559        }
560
561        let mut p: Persist<Heading> = Persist::with_capacity(50_000);
562
563        for i in 0..50_000 {
564            p.push(Heading { x: i });
565        }
566
567        for i in (0..50_000).rev() {
568            assert_eq!(p.pop().unwrap().x, i);
569        }
570    }
571
572    #[test]
573    fn remove() {
574        #[derive(Debug, PartialOrd, PartialEq)]
575        struct Heading {
576            x: u32,
577        }
578
579        let mut p: Persist<Heading> = Persist::with_capacity(50);
580
581        for i in 0..50 {
582            p.push(Heading { x: i });
583        }
584
585        let r = p.remove(10);
586        assert_eq!(r, Some(Heading { x: 10 }));
587
588        let r = p.remove(20);
589        assert_eq!(r, Some(Heading { x: 20 }));
590
591        let r = p.remove(30);
592        assert_eq!(r, Some(Heading { x: 30 }));
593
594        let r = p.remove(22);
595        assert_eq!(r, Some(Heading { x: 22 }));
596    }
597
598    #[test]
599    fn insert() {
600        let mut p: Persist<u32> = Persist::with_capacity(10);
601
602        p.push(13);
603        p.push(14);
604        p.push(15);
605
606        let previous = p.insert(0, 16).unwrap();
607        assert_eq!(previous, 13);
608        assert_eq!(p.get(0), Some(&16));
609
610        assert!(p.insert(5, 17).is_none());
611        assert_eq!(p.get(5), Some(&17));
612    }
613
614    #[test]
615    fn iter() {
616        #[derive(Debug)]
617        struct Heading {
618            x: usize,
619        }
620
621        dbg!(std::mem::size_of::<Heading>());
622        dbg!(std::mem::size_of::<Option<Heading>>());
623        dbg!(std::mem::size_of::<usize>());
624        dbg!(std::mem::size_of::<Entry<Heading>>());
625
626        let mut p: Persist<Heading> = Persist::with_capacity(10);
627
628        p.push(Heading { x: 13 });
629        p.push(Heading { x: 14 });
630        p.push(Heading { x: 15 });
631
632        let mut accum = 0;
633        for x in p.iter() {
634            accum += x.x;
635        }
636        assert_eq!(accum, 42);
637    }
638
639    #[test]
640    fn iter_mut() {
641        #[derive(Debug)]
642        struct Heading {
643            x: u32,
644        }
645
646        let mut p: Persist<Heading> = Persist::with_capacity(10);
647
648        p.push(Heading { x: 6 });
649        p.push(Heading { x: 6 });
650        p.push(Heading { x: 6 });
651        p.push(Heading { x: 6 });
652
653        for x in p.iter_mut() {
654            x.x += 1;
655        }
656
657        for x in p.iter() {
658            assert_eq!(x.x, 7);
659        }
660    }
661
662    #[test]
663    fn iter_over_removed() {
664        #[derive(Debug, PartialOrd, PartialEq)]
665        struct Heading {
666            x: u32,
667        }
668
669        let mut p: Persist<Heading> = Persist::with_capacity(50);
670
671        for i in 0..50 {
672            p.push(Heading { x: i });
673        }
674
675        let r = p.remove(10);
676        assert_eq!(r, Some(Heading { x: 10 }));
677
678        let r = p.remove(20);
679        assert_eq!(r, Some(Heading { x: 20 }));
680
681        let r = p.remove(30);
682        assert_eq!(r, Some(Heading { x: 30 }));
683
684        for head in p.iter() {
685            assert_ne!(head.x, 10);
686            assert_ne!(head.x, 20);
687            assert_ne!(head.x, 30);
688        }
689    }
690
691    #[test]
692    fn pst_remove_and_push() {
693        const LIMIT: usize = 100_000; //65025;
694
695        struct Velocity(u32);
696
697        let mut persist = Persist::with_capacity(LIMIT);
698
699        for _ in 0..LIMIT {
700            persist.push(Velocity(1));
701        }
702
703        let mut accum = 0;
704        for x in persist.iter() {
705            accum += x.0;
706        }
707        assert_eq!(accum, LIMIT as u32);
708    }
709
710    #[test]
711    fn from_slice_reserve() {
712        let ar = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
713        let persist = Persist::from(&ar[..]);
714        //persist.reserve(10);
715        assert_eq!(persist.entries.len(), 10);
716    }
717
718    #[test]
719    #[should_panic]
720    fn panic_out_of_bounds() {
721        let ar = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
722        let mut persist = Persist::from(&ar[..]);
723        persist.insert(10, 10);
724    }
725
726    #[test]
727    fn insert_at_end() {
728        let mut p: Persist<u32> = Persist::with_capacity(10);
729
730        p.insert(9, 15);
731
732        let x = p.get(9).unwrap();
733        assert_eq!(*x, 15);
734
735        let mut accum = 0;
736        for (i, v) in p.iter().enumerate() {
737            assert_eq!(i, 0);
738            assert_eq!(*v, 15);
739            accum += 1;
740        }
741        assert_eq!(accum, 1);
742
743        let mut accum = 0;
744        for (i, v) in p.iter_mut().enumerate() {
745            assert_eq!(i, 0);
746            assert_eq!(*v, 15);
747            accum += 1;
748        }
749        assert_eq!(accum, 1);
750    }
751}