lru_st/
lib.rs

1#![deny(unused_imports)]
2#![deny(missing_docs)]
3
4//! # lru-st
5//!
6//! This crate provides a Vec based doubly linked list implementation.
7//! It also aims at providing data structures built on top of
8//! doubly linked list such as LRU HashMap.
9//!
10//! # Features
11//! - `sync`: to enable when `collections` structures needs to be used in threads
12//!
13//! # Example: DoublyLinkedList
14//!
15//! ```
16//! use lru_st::{dll, Cursor};
17//!
18//! let mut dll = dll![1, 2, 3, 4];
19//! assert_eq!(dll.len(), 4);
20//!
21//! let c = dll.push_front(0);
22//! // even though the element has been pushed
23//! // at front (i.e. 0th position in the list)
24//! // its [Cursor] is 4. This is because the
25//! // Cursor is a reference to the item not
26//! // related to its position in the list.
27//! assert_eq!(c, Cursor(4));
28//!
29//! // first element is 0
30//! assert_eq!(dll.front(), Some(&0));
31//! assert_eq!(dll.get(Cursor(4)), Some(&0));
32//!
33//! // we move item with value 4 at front of
34//! // the list
35//! dll.move_front(Cursor(3)).unwrap();
36//! assert_eq!(dll.get_nth(0), Some(&4));
37//! assert_eq!(dll.get_nth(1), Some(&0));
38//! // even if order of list items changed cursors
39//! // are never affected by those changes
40//! assert_eq!(dll.get(Cursor(4)), Some(&0));
41//! ```
42//!
43//! # Example: LRU HashMap
44//!
45//! ```
46//! use lru_st::collections::LruHashMap;
47//!
48//! let mut lru_map = LruHashMap::with_max_entries(10);
49//! lru_map.insert(42, "test");
50//!
51//! assert_eq!(lru_map.get(&42), Some("test").as_ref());
52//! assert_eq!(lru_map.len(), 1);
53//!
54//! // we fill the map entirely
55//! for i in 0..lru_map.cap(){
56//!     lru_map.insert(i, "fill");
57//! }
58//!
59//! assert_eq!(lru_map.len(), 10);
60//!
61//! // this element disapeared from the map as we filled
62//! // all the map without fetching it
63//! assert_eq!(lru_map.get(&42), None);
64//! ```
65//!
66//! # Example: LRU HashSet
67//!
68//! ```
69//! use lru_st::collections::LruHashSet;
70//!
71//! let mut lru_set = LruHashSet::with_max_entries(10);
72//!
73//! assert_eq!(lru_set.insert("test"), true);
74//! assert_eq!(lru_set.insert("test"), false);
75//!
76//! assert_eq!(lru_set.contains(&"test"), true);
77//!
78//! // we remove one element
79//! assert_eq!(lru_set.remove(&"test"), true);
80//! assert_eq!(lru_set.remove(&"test"), false);
81//!
82//! assert!(lru_set.is_empty());
83//!
84//! let mut lru_set = LruHashSet::with_max_entries(10);
85//!
86//! assert_eq!(lru_set.insert(String::from("will_be_erased")), true);
87//!
88//! for i in 0..10{
89//!     assert_eq!(lru_set.insert(format!("erase_{i}")), true);
90//! }
91//!
92//! // the item vanished as the LRU got full
93//! assert_eq!(lru_set.contains(&String::from("will_be_erased")), false);
94//! assert!(lru_set.is_full());
95//! ```
96
97use std::{
98    fmt::{Debug, Display},
99    hash::Hash,
100};
101use thiserror::Error;
102
103/// Module exposing structures implemented
104/// on top of [DoublyLinkList]
105pub mod collections;
106
107/// Structure representing a **reference** of an element
108/// within a [DoublyLinkedList]. It is important to
109/// remember that a [Cursor] does not represent the
110/// position of an element.
111#[derive(Debug, Clone, Hash, Copy, Eq, PartialEq)]
112pub struct Cursor(pub usize);
113
114/// A node of the doubly linked list
115struct Node<T> {
116    prev: Option<Cursor>,
117    next: Option<Cursor>,
118    value: Option<T>,
119    free: bool,
120}
121
122impl<T> Node<T> {
123    fn free(&mut self) {
124        self.prev = None;
125        self.next = None;
126        self.value = None;
127        self.free = true;
128    }
129}
130
131impl<T> Debug for Node<T> {
132    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133        write!(
134            f,
135            "prev={:?} next={:?} free={:?}",
136            self.prev, self.next, self.free
137        )
138    }
139}
140
141/// [Vec] based doubly linked list implementation
142///
143/// # Example
144///
145/// ```
146/// use lru_st::DoublyLinkedList;
147///
148/// let mut dll = DoublyLinkedList::new();
149/// dll.push_front(42);
150/// dll.push_front(43);
151///
152/// assert_eq!(dll.back(), Some(&42));
153/// assert_eq!(dll.front(), Some(&43));
154///
155/// dll.push_back(44);
156/// assert_eq!(dll.front(), Some(&43));
157/// assert_eq!(dll.back(), Some(&44));
158/// ```
159pub struct DoublyLinkedList<T> {
160    // the head of the list
161    head: Option<Cursor>,
162    // the tail of the list
163    tail: Option<Cursor>,
164    // list of nodes
165    list: Vec<Node<T>>,
166    // free list to use for new node insertion
167    free: Vec<Cursor>,
168}
169
170impl<T> Default for DoublyLinkedList<T> {
171    fn default() -> Self {
172        DoublyLinkedList {
173            head: None,
174            tail: None,
175            list: Vec::new(),
176            free: Vec::new(),
177        }
178    }
179}
180
181impl<T> Debug for DoublyLinkedList<T>
182where
183    T: Debug,
184{
185    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186        write!(f, "[")?;
187        let mut first = true;
188        for v in self.iter() {
189            if !first {
190                write!(f, ", ")?;
191            }
192            write!(f, "{:?}", v)?;
193            first = false;
194        }
195        write!(f, "]")
196    }
197}
198
199impl<T> Display for DoublyLinkedList<T>
200where
201    T: Display,
202{
203    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204        write!(f, "[")?;
205        let mut first = true;
206        for v in self.iter() {
207            if !first {
208                write!(f, ", ")?;
209            }
210            write!(f, "{}", v)?;
211            first = false;
212        }
213        write!(f, "]")
214    }
215}
216
217/// Enum of the possible [Error] encountered while using
218/// a [DoublyLinkedList]
219#[derive(Debug, Error, PartialEq, PartialOrd, Ord, Eq)]
220pub enum Error {
221    /// Error returned when trying to access
222    /// an out of bound index
223    #[error("out of bound index: {0}")]
224    OutOfBound(usize),
225
226    /// Error raised when trying to use a
227    /// node alread freed.
228    #[error("trying to use a freed node")]
229    Uaf,
230}
231
232impl<T> PartialEq for DoublyLinkedList<T>
233where
234    T: PartialEq,
235{
236    fn eq(&self, other: &Self) -> bool {
237        if self.len() != other.len() {
238            return false;
239        }
240
241        let mut other_it = other.iter();
242
243        for v in self.iter() {
244            match other_it.next() {
245                Some(ov) => {
246                    if v != ov {
247                        return false;
248                    }
249                }
250                None => return false,
251            }
252        }
253
254        true
255    }
256}
257
258impl<T> DoublyLinkedList<T> {
259    /// Creates a new empty [DoublyLinkedList]
260    pub fn new() -> Self {
261        Self::default()
262    }
263
264    /// Creates a new empty [DoublyLinkedList] with a given capacity
265    pub fn with_capacity(capacity: usize) -> Self {
266        DoublyLinkedList {
267            list: Vec::with_capacity(capacity),
268            ..Default::default()
269        }
270    }
271
272    /// Creates a new [DoublyLinkedList] from a [Vec]
273    pub fn from_vec(v: Vec<T>) -> Self {
274        let mut d = Self::new();
275        for e in v {
276            d.push_back(e);
277        }
278        d
279    }
280
281    /// Returns true if the list is empty
282    #[inline(always)]
283    pub fn is_empty(&self) -> bool {
284        self.len() == 0
285    }
286
287    #[inline]
288    fn next_available_cursor(&mut self) -> Cursor {
289        self.free.pop().unwrap_or(Cursor(self.list.len()))
290    }
291
292    #[inline]
293    fn put(&mut self, e: Node<T>, at: Cursor) {
294        if at.0 == self.list.len() {
295            self.list.push(e);
296            return;
297        }
298        self.list[at.0] = e;
299    }
300
301    /// Get the cursor of nth element
302    #[inline(always)]
303    fn get_nth_cursor(&self, n: usize) -> Option<Cursor> {
304        let mut n = n;
305        let mut next = self.head;
306        while let Some(cursor) = next {
307            next = self.list[cursor.0].next;
308            if n == 0 {
309                return Some(cursor);
310            }
311            n -= 1;
312        }
313        None
314    }
315
316    #[inline]
317    /// Pushes an element to the front of the list
318    pub fn push_front(&mut self, v: T) -> Cursor {
319        let cursor = self.next_available_cursor();
320        let node = Node {
321            prev: None,
322            next: self.head,
323            value: Some(v),
324            free: false,
325        };
326
327        // if there is no tail
328        if self.tail.is_none() {
329            self.tail = Some(cursor);
330        }
331
332        // we link the old head (if existing) to the new one
333        self.new_prev(self.head, Some(cursor));
334
335        // we insert element at position
336        self.put(node, cursor);
337        // new head
338        self.head = Some(cursor);
339        cursor
340    }
341
342    #[inline]
343    /// Pushes an element to the back of the list and returning
344    /// the [Cursor] pointing to this element. The [Cursor] can
345    /// then be used to directly access/move/pop element.
346    pub fn push_back(&mut self, v: T) -> Cursor {
347        let cursor = self.next_available_cursor();
348        // element to be inserted at the end
349        let e = Node {
350            prev: self.tail,
351            next: None,
352            value: Some(v),
353            free: false,
354        };
355
356        // if there is no head we set it
357        if self.head.is_none() {
358            self.head = Some(cursor);
359        }
360
361        // we link the old tail (if existing) to the new one
362        self.new_next(self.tail, Some(cursor));
363
364        // we insert element at position
365        self.put(e, cursor);
366        // new tail
367        self.tail = Some(cursor);
368        cursor
369    }
370
371    /// Get the element in the list at a given [Cursor] or None
372    /// if there is no element. If wanting to get an element at
373    /// a given position see [DoublyLinkedList::get_nth].
374    #[inline(always)]
375    pub fn get(&self, c: Cursor) -> Option<&T> {
376        if let Some(e) = self.list.get(c.0) {
377            // we return None if node is freed
378            if e.free {
379                return None;
380            }
381            return e.value.as_ref();
382        }
383        None
384    }
385
386    /// Get an element given its position in the list
387    #[inline(always)]
388    pub fn get_nth(&self, n: usize) -> Option<&T> {
389        self.get(self.get_nth_cursor(n)?)
390    }
391
392    /// Get a mutable element at a given position in the list or None
393    /// if there is no element.
394    #[inline(always)]
395    pub fn get_mut(&mut self, c: Cursor) -> Option<&mut T> {
396        if let Some(e) = self.list.get_mut(c.0) {
397            // we return None if node is freed
398            if e.free {
399                return None;
400            }
401            return e.value.as_mut();
402        }
403        None
404    }
405
406    /// Get an element given its position in the list
407    #[inline(always)]
408    pub fn get_mut_nth(&mut self, n: usize) -> Option<&mut T> {
409        self.get_mut(self.get_nth_cursor(n)?)
410    }
411
412    /// Get the element at the front of the list
413    #[inline(always)]
414    pub fn front(&self) -> Option<&T> {
415        if let Some(c) = self.head {
416            return self.get(c);
417        }
418        None
419    }
420
421    /// Get a mutable reference to the element at the front of the list
422    #[inline(always)]
423    pub fn front_mut(&mut self) -> Option<&mut T> {
424        if let Some(c) = self.head {
425            return self.get_mut(c);
426        }
427        None
428    }
429
430    /// Get the element a the back of the list
431    #[inline(always)]
432    pub fn back(&self) -> Option<&T> {
433        if let Some(c) = self.tail {
434            return self.get(c);
435        }
436        None
437    }
438
439    /// Get a mutable reference to the element at the back of the list
440    #[inline(always)]
441    pub fn back_mut(&mut self) -> Option<&mut T> {
442        if let Some(c) = self.tail {
443            return self.get_mut(c);
444        }
445        None
446    }
447
448    /// Returns the number of elements in the list
449    #[inline(always)]
450    pub fn len(&self) -> usize {
451        self.list.len() - self.free.len()
452    }
453
454    #[inline]
455    fn node(&self, at: Cursor) -> Option<&Node<T>> {
456        self.list.get(at.0)
457    }
458
459    /// Pops the element a the back of the list
460    #[inline]
461    pub fn pop_back(&mut self) -> Option<T> {
462        if let Some(tail_curs) = self.tail {
463            return self._pop(tail_curs);
464        }
465        None
466    }
467
468    #[inline]
469    fn new_prev(&mut self, at: Option<Cursor>, prev: Option<Cursor>) {
470        // if there is something at pos
471        if let Some(at) = at {
472            // we modify element at pos
473            self.list[at.0].prev = prev
474        }
475    }
476
477    #[inline]
478    fn new_next(&mut self, at: Option<Cursor>, next: Option<Cursor>) {
479        // if there is something at pos
480        if let Some(at) = at {
481            // we modify element at pos
482            self.list[at.0].next = next;
483        }
484    }
485
486    /// Provides an iterator (i.e. [DoublyLinkedListIter]) over the elements of the list
487    #[inline]
488    pub fn iter(&self) -> DoublyLinkedListIter<T> {
489        DoublyLinkedListIter {
490            dll: self,
491            front_cursor: self.head,
492            back_cursor: self.tail,
493            cross: false,
494        }
495    }
496
497    /// Move item at cursor to the head of list
498    #[inline]
499    pub fn move_front(&mut self, at: Cursor) -> Result<(), Error> {
500        if at.0 >= self.list.len() {
501            return Err(Error::OutOfBound(at.0));
502        }
503
504        // we are trying to move a freed node to the top of the list
505        if self.list[at.0].free {
506            return Err(Error::Uaf);
507        }
508
509        // if we are not processing head
510        if self.list[at.0].prev.is_some() {
511            // we link next to prev
512            self.new_prev(self.list[at.0].next, self.list[at.0].prev);
513            // we link prev to next
514            self.new_next(self.list[at.0].prev, self.list[at.0].next);
515
516            // we are processing the tail so we have to assign a new
517            // self.tail
518            if self.list[at.0].next.is_none() {
519                self.tail = self.list[at.0].prev
520            }
521
522            // linking old head to the new head
523            self.new_prev(self.head, Some(at));
524
525            // we make item the new head
526            self.list[at.0].next = self.head;
527            self.list[at.0].prev = None;
528            self.head = Some(at);
529        }
530
531        Ok(())
532    }
533
534    /// Pops the item at front of the doubly linked list
535    #[inline]
536    pub fn pop_front(&mut self) -> Option<T> {
537        match self.head {
538            Some(head) => self._pop(head),
539            None => None,
540        }
541    }
542
543    /// Pops the item located at `at` [Cursor] in the doubly linked list.
544    /// This API pops an element according to its [Cursor] which is
545    /// not corresponding to its position within the linked list.
546    /// To pop an item according to its position in the linked list
547    /// use `pop_nth`.
548    #[inline]
549    pub fn pop(&mut self, at: Cursor) -> Option<T> {
550        if !self.list[at.0].free {
551            return self._pop(at);
552        }
553        None
554    }
555
556    /// Pops the nth element of linked list
557    #[inline]
558    pub fn pop_nth(&mut self, n: usize) -> Option<T> {
559        let mut n = n;
560        let mut next = self.head;
561        while let Some(cursor) = next {
562            next = self.list[cursor.0].next;
563            if n == 0 {
564                return self.pop(cursor);
565            }
566            n -= 1;
567        }
568        None
569    }
570
571    #[inline(always)]
572    fn _pop(&mut self, at: Cursor) -> Option<T> {
573        debug_assert!(!self.list[at.0].free);
574
575        // if we want to remove head
576        if Some(at) == self.head {
577            let new_head = self.list[at.0].next;
578            self.head = new_head;
579        }
580
581        // if we want to remove tail
582        if Some(at) == self.tail {
583            let new_tail = self.list[at.0].prev;
584            self.tail = new_tail;
585        }
586
587        // actually unlinking the at Cursor
588        self.new_prev(self.list[at.0].next, self.list[at.0].prev);
589        self.new_next(self.list[at.0].prev, self.list[at.0].next);
590
591        let out = self.list[at.0].value.take();
592        // mark node at Cursor as free
593        self.list[at.0].free();
594        self.free.push(at);
595        out
596    }
597
598    #[inline]
599    #[allow(dead_code)]
600    fn verify(&self) {
601        let mut prev = None;
602        let mut oc = self.head;
603        while let Some(c) = oc {
604            let node = self.list.get(c.0).unwrap();
605            // we check back link
606            assert_eq!(node.prev, prev);
607            prev = Some(c);
608            oc = node.next;
609        }
610    }
611}
612
613/// [DoublyLinkedList] iterator
614pub struct DoublyLinkedListIter<'a, T> {
615    dll: &'a DoublyLinkedList<T>,
616    front_cursor: Option<Cursor>,
617    back_cursor: Option<Cursor>,
618    cross: bool,
619}
620
621impl<'a, T> Iterator for DoublyLinkedListIter<'a, T> {
622    type Item = &'a T;
623    fn next(&mut self) -> Option<Self::Item> {
624        if self.cross {
625            return None;
626        }
627
628        if self.front_cursor == self.back_cursor {
629            self.cross = true
630        }
631
632        let cursor = self.front_cursor?;
633        let node = self.dll.node(cursor).expect("node must be found at cursor");
634        self.front_cursor = node.next;
635        node.value.as_ref()
636    }
637}
638
639impl<'a, T> DoubleEndedIterator for DoublyLinkedListIter<'a, T> {
640    fn next_back(&mut self) -> Option<Self::Item> {
641        if self.cross {
642            return None;
643        }
644
645        if self.front_cursor == self.back_cursor {
646            self.cross = true
647        }
648
649        let cursor = self.back_cursor?;
650        // nodes pointed by others should always be valid
651        let node = self.dll.node(cursor).expect("node must be found at cursor");
652        self.back_cursor = node.prev;
653        node.value.as_ref()
654    }
655}
656
657/// Macro used to create a [DoublyLinkedList]
658///
659/// # Example
660///
661/// ```
662/// use lru_st::dll;
663///
664/// let d = dll![1,2,3];
665/// assert_eq!(d, dll![1,2,3]);
666/// assert_ne!(d, dll![3,2,1]);
667/// ```
668#[macro_export]
669macro_rules! dll {
670    [$($item:literal),*] => {
671        {
672            let mut dll=$crate::DoublyLinkedList::new();
673            $(dll.push_back($item);)*
674            dll
675        }
676    };
677}
678
679#[cfg(test)]
680mod tests {
681    use rand::prelude::*;
682
683    use super::*;
684
685    #[test]
686    fn dll_from_vec_test() {
687        let len = 100;
688        let d = DoublyLinkedList::from_vec((0..len).collect());
689        println!("{}", d);
690        let mut i = 0;
691
692        // from_vec must insert values in the same order they appear in the vector
693        #[allow(clippy::explicit_counter_loop)]
694        for v in d.iter() {
695            assert_eq!(v, &i);
696            i += 1;
697        }
698    }
699
700    #[test]
701    fn dll_rev_iter_test() {
702        let d = DoublyLinkedList::from_vec(vec![1, 2, 3, 4, 5]);
703        println!("{}", d);
704        let mut iter = d.iter();
705        assert_eq!(iter.next(), Some(&1));
706        assert_eq!(iter.next_back(), Some(&5));
707        assert_eq!(iter.next_back(), Some(&4));
708        assert_eq!(iter.next(), Some(&2));
709        assert_eq!(iter.next_back(), Some(&3));
710        assert_eq!(iter.next(), None);
711        assert_eq!(iter.next_back(), None);
712    }
713
714    #[test]
715    fn dll_iter_test() {
716        let len = 100;
717        let d = DoublyLinkedList::from_vec((0..len).collect());
718
719        let mut i = len - 1;
720        for v in d.iter().rev() {
721            assert_eq!(v, &i);
722            i -= 1;
723        }
724
725        assert_eq!(i, -1);
726    }
727
728    #[test]
729    fn dll_push_back_test() {
730        let len = 100;
731        let mut d = DoublyLinkedList::new();
732
733        for i in 0..len {
734            d.push_back(i);
735        }
736
737        assert_eq!(d.len(), len);
738
739        for i in (0..len).rev() {
740            let back = d.pop_back();
741            assert!(back.is_some(), "iteration {i}");
742            assert_eq!(back.unwrap(), i, "iteration {i}");
743            assert!(d.node(Cursor(i)).unwrap().free);
744            d.free
745                .iter()
746                .for_each(|i| assert!(d.node(*i).unwrap().free));
747        }
748
749        assert!(d.is_empty());
750        assert_eq!(d.head, None);
751        assert_eq!(d.tail, None);
752        assert_eq!(d.free.len(), len);
753        d.list.iter().for_each(|n| assert!(n.free));
754    }
755
756    #[test]
757    fn dll_push_front_test() {
758        let len = 100;
759
760        let mut d = DoublyLinkedList::new();
761
762        for i in (0..len).rev() {
763            d.push_front(i);
764        }
765
766        assert_eq!(d.len(), len);
767
768        for i in (0..len).rev() {
769            assert_eq!(d.pop_back().unwrap(), i);
770            assert!(d.node(Cursor(len - i - 1)).unwrap().free);
771            d.free
772                .iter()
773                .for_each(|i| assert!(d.node(*i).unwrap().free));
774        }
775
776        assert!(d.is_empty());
777        assert_eq!(d.head, None);
778        assert_eq!(d.tail, None);
779        assert_eq!(d.free.len(), len);
780        d.list.iter().for_each(|n| assert!(n.free));
781    }
782
783    #[test]
784    fn dll_move_front_test() {
785        let len = 100;
786
787        let mut d = DoublyLinkedList::new();
788
789        for i in 0..len {
790            d.push_front(i);
791        }
792
793        for i in (0..len).rev() {
794            println!("moving {} to front", d.get(Cursor(i)).unwrap());
795            d.move_front(Cursor(i)).unwrap();
796            assert_eq!(d.front().unwrap(), &i);
797        }
798    }
799
800    #[test]
801    fn dll_pop_front_test() {
802        let len = 100;
803
804        let mut d = DoublyLinkedList::new();
805
806        for i in 0..len {
807            d.push_front(i);
808        }
809
810        for i in (0..len).rev() {
811            d.verify();
812            assert_eq!(d.pop_front(), Some(i));
813        }
814
815        assert_eq!(d.len(), 0);
816    }
817
818    #[test]
819    fn dll_pop_test_simple() {
820        let mut dll = dll![1, 2, 3, 4, 5];
821        assert_eq!(dll.pop(Cursor(2)), Some(3));
822        assert_eq!(dll.pop(Cursor(3)), Some(4));
823        // two values got popped in the middle so pop_front
824        // should not return them
825        assert_eq!(dll.pop_front(), Some(1));
826        assert_eq!(dll.pop_front(), Some(2));
827        assert_eq!(dll.pop_back(), Some(5));
828        assert!(dll.is_empty());
829    }
830
831    #[test]
832    fn dll_pop_nth() {
833        let mut dll = dll![1, 2, 3, 4, 5];
834        dll.move_front(Cursor(2)).unwrap();
835        assert_eq!(dll.pop_nth(2), Some(2));
836    }
837
838    #[test]
839    fn dll_pop_test() {
840        let mut rng = thread_rng();
841        let len = 100;
842
843        let mut d = DoublyLinkedList::new();
844
845        for i in 0..len {
846            d.push_front(i);
847        }
848
849        let mut cursors: Vec<usize> = (0..len).collect();
850        cursors.shuffle(&mut rng);
851
852        for i in cursors {
853            d.verify();
854            assert_eq!(d.pop(Cursor(i)), Some(i));
855            assert_eq!(d.pop(Cursor(i)), None);
856        }
857
858        assert_eq!(d.len(), 0);
859    }
860
861    #[test]
862    fn dll_eq_test() {
863        assert_eq!(dll![1, 2, 3], dll![1, 2, 3]);
864        assert_ne!(dll![1, 2, 3], dll![1, 2]);
865    }
866}