yatima_core/
dll.rs

1use core::{
2  marker::PhantomData,
3  ptr::NonNull,
4};
5
6use sp_std::{
7  boxed::Box,
8  fmt,
9};
10
11use alloc::string::{
12  String,
13  ToString,
14};
15
16/// A doubly-linked list (DLL) node
17/// Uses raw pointers in order to share mutable DAG references
18#[derive(Debug)]
19pub struct DLL<T> {
20  pub next: Option<NonNull<DLL<T>>>,
21  pub prev: Option<NonNull<DLL<T>>>,
22  pub elem: T,
23}
24
25/// An forwards iterator over the DLL
26/// Uses a PhantomData marker to simulate ownership of the DLL during its
27/// lifetime of `'a`
28pub struct Iter<'a, T> {
29  next: Option<NonNull<DLL<T>>>,
30  this: Option<NonNull<DLL<T>>>,
31  marker: PhantomData<&'a mut DLL<T>>,
32}
33
34impl<'a, T> Iter<'a, T> {
35  /// Checks if last element in the DLL
36  #[inline]
37  pub fn is_last(&self) -> bool { self.next.is_none() }
38
39  /// Returns the inner DLL node
40  #[inline]
41  pub fn this(&self) -> Option<NonNull<DLL<T>>> { self.this }
42}
43
44impl<'a, T> Iterator for Iter<'a, T> {
45  type Item = &'a mut T;
46
47  #[inline]
48  fn next(&mut self) -> Option<Self::Item> {
49    self.this = self.next;
50    self.next.map(|node| {
51      let deref = unsafe { &mut *node.as_ptr() };
52      self.next = deref.next;
53      &mut deref.elem
54    })
55  }
56}
57
58impl<T> DLL<T> {
59  /// Creates a DLL with only one node
60  #[inline]
61  pub fn singleton(elem: T) -> Self { DLL { next: None, prev: None, elem } }
62
63  /// Checks if the DLL has only one node
64  #[inline]
65  pub fn is_singleton(dll: Option<NonNull<Self>>) -> bool {
66    dll.map_or(false, |dll| unsafe {
67      let dll = &*dll.as_ptr();
68      dll.prev.is_none() && dll.next.is_none()
69    })
70  }
71
72  /// Inserts a new DLL node after the current node
73  pub fn add_after(&mut self, elem: T) {
74    let new_next = NonNull::new(Box::into_raw(Box::new(DLL {
75      next: self.next,
76      prev: NonNull::new(self),
77      elem,
78    })));
79    self.next.map_or((), |ptr| unsafe { (*ptr.as_ptr()).prev = new_next });
80    self.next = new_next;
81  }
82
83  /// Inserts a new DLL node before the current node
84  pub fn add_before(&mut self, elem: T) {
85    let new_prev = NonNull::new(Box::into_raw(Box::new(DLL {
86      next: NonNull::new(self),
87      prev: self.prev,
88      elem,
89    })));
90    self.prev.map_or((), |ptr| unsafe { (*ptr.as_ptr()).next = new_prev });
91    self.prev = new_prev;
92  }
93
94  /// Inserts a given node before the current node, dropping the former's
95  /// previous links
96  pub fn merge(&mut self, node: NonNull<Self>) {
97    unsafe {
98      (*node.as_ptr()).prev = self.prev;
99      (*node.as_ptr()).next = NonNull::new(self);
100      self.prev.map_or((), |ptr| (*ptr.as_ptr()).next = Some(node));
101      self.prev = Some(node);
102    }
103  }
104
105  /// Unlinks the given node and returns, if it exists, a neighboring node.
106  /// Leaves the node to be deallocated afterwards.
107  pub fn unlink_node(&self) -> Option<NonNull<Self>> {
108    unsafe {
109      let next = self.next;
110      let prev = self.prev;
111      if let Some(next) = next {
112        (*next.as_ptr()).prev = prev;
113      };
114      if let Some(prev) = prev {
115        (*prev.as_ptr()).next = next;
116      }
117      (prev).or(next)
118    }
119  }
120
121  /// Returns the first node in the DLL
122  pub fn first(mut node: NonNull<Self>) -> NonNull<Self> {
123    loop {
124      let prev = unsafe { (*node.as_ptr()).prev };
125      match prev {
126        None => break,
127        Some(ptr) => node = ptr,
128      }
129    }
130    node
131  }
132
133  /// Returns the last node in the DLL
134  pub fn last(mut node: NonNull<Self>) -> NonNull<Self> {
135    loop {
136      let next = unsafe { (*node.as_ptr()).next };
137      match next {
138        None => break,
139        Some(ptr) => node = ptr,
140      }
141    }
142    node
143  }
144
145  /// Joins two DLLs together at the ends
146  pub fn concat(dll: NonNull<Self>, rest: Option<NonNull<Self>>) {
147    let last = DLL::last(dll);
148    let first = rest.map(DLL::first);
149    unsafe {
150      (*last.as_ptr()).next = first;
151    }
152    first.map_or((), |first| unsafe {
153      (*first.as_ptr()).prev = Some(last);
154    });
155  }
156
157  /// Creates an iterator over the DLL if it exists
158  #[inline]
159  pub fn iter_option<'a>(dll: Option<NonNull<Self>>) -> Iter<'a, T> {
160    Iter { next: dll.map(DLL::first), this: None, marker: PhantomData }
161  }
162
163  /// Creates a mutable iterator over the DLL
164  #[inline]
165  pub fn iter_mut(&mut self) -> Iter<'_, T> {
166    let link: NonNull<Self> = NonNull::from(self);
167    Iter { next: Some(DLL::first(link)), this: None, marker: PhantomData }
168  }
169
170  /// Creates an iterator over the DLL
171  #[inline]
172  pub fn iter(&self) -> Iter<'_, T> {
173    let link: NonNull<Self> = NonNull::from(self);
174    Iter { next: Some(DLL::first(link)), this: None, marker: PhantomData }
175  }
176}
177
178impl<T: fmt::Display> fmt::Display for DLL<T> {
179  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180    let mut iter = self.iter();
181    let head = &iter.next().map_or(String::from(""), |head| head.to_string());
182    let mut msg = String::from("[ ") + head;
183    for val in iter {
184      msg = msg + " <-> " + &val.to_string();
185    }
186    write!(f, "{}", msg + " ]")
187  }
188}
189
190#[cfg(test)]
191mod tests {
192  use super::*;
193  use core::ptr::NonNull;
194
195  #[test]
196  pub fn dll() {
197    unsafe {
198      let dll = NonNull::new_unchecked(Box::leak(Box::new(DLL::singleton(3))));
199      // Populate list
200      let node = &mut *dll.as_ptr();
201      node.add_after(6);
202      node.add_after(5);
203      node.add_after(4);
204      node.add_before(0);
205      node.add_before(1);
206      node.add_before(2);
207      assert_eq!(node.to_string(), "[ 0 <-> 1 <-> 2 <-> 3 <-> 4 <-> 5 <-> 6 ]");
208      // Remove elements
209      let dll = match DLL::unlink_node(dll.as_ref()) {
210        Some(dll) => dll,
211        None => return (),
212      };
213      assert_eq!(
214        (*dll.as_ptr()).to_string(),
215        "[ 0 <-> 1 <-> 2 <-> 4 <-> 5 <-> 6 ]"
216      );
217      let dll = match DLL::unlink_node(dll.as_ref()) {
218        Some(dll) => dll,
219        None => return (),
220      };
221      assert_eq!((*dll.as_ptr()).to_string(), "[ 0 <-> 1 <-> 4 <-> 5 <-> 6 ]");
222      let dll = match DLL::unlink_node(dll.as_ref()) {
223        Some(dll) => dll,
224        None => return (),
225      };
226      let node = &mut *dll.as_ptr();
227      let mut iter = node.iter();
228      assert_eq!(iter.next(), Some(&mut 0));
229      assert_eq!(iter.next(), Some(&mut 4));
230      if let Some(dll) = iter.this() {
231        let node = &*dll.as_ptr();
232        assert_eq!(node.elem, 4);
233      }
234    }
235  }
236}