xarray.rs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. use std::{collections::VecDeque, marker::PhantomData};
  2. use crate::*;
  3. pub(crate) const BITS_PER_LAYER: usize = 6;
  4. pub(crate) const SLOT_SIZE: usize = 1 << BITS_PER_LAYER;
  5. pub(crate) const SLOT_MASK: usize = SLOT_SIZE - 1;
  6. /// The XArray is an abstract data type which behaves like a very large array of items.
  7. /// Items here must be a 8 bytes object, like `Arc<T>` and `Box<T>`.
  8. /// The alignment of the pointers stored by users must be at least 4.
  9. /// It allows you to sensibly go to the next or previous entry in a cache-efficient manner.
  10. /// It allows multiple concurrent reads of the XArray, but only permits one write operation on the XArray at any given time.
  11. ///
  12. /// # Features
  13. /// **Copy-on-write (COW).** If the item stored in `XArray` implemented `Clone` trait, the `XArray`
  14. /// can achieve Clone with a COW mechanism. When cloning an XArray, initially the new XArray shares a head with the original XArray
  15. /// without performing an actual clone. If either of the XArrays needs to perform a mutable operation, a substantive clone of the XNode to be modified is created before making the update.
  16. /// This ensures that operations on the two XArrays do not affect each other.
  17. /// **Reference.** All operations on XArray are performed through `Cursor` and `CursorMut`.
  18. /// Cursor requires an immutable reference to XArray, while CursorMut requires a mutable reference.
  19. /// Therefore, XArray can have multiple Cursors operating at the same time, whereas the operations of CursorMut are exclusive (similar to the relationship between & and &mut).
  20. /// **Mark.** `XArray` supports the ability to add marks to any stored item to assist users.
  21. /// By default, an item can be marked with up to three different marks, with each mark being independent of the others.
  22. /// Marks for an item are typically enumerations that must implement the ValidMark trait.
  23. /// Internal nodes can also be marked. When an intermediate node is marked, it signifies that it has child nodes that have been marked.
  24. ///
  25. /// # Example
  26. ///
  27. /// ```
  28. /// use std::sync::Arc;
  29. /// use xarray::*;
  30. ///
  31. /// let mut xarray_arc: XArray<Arc<i32>> = XArray::new();
  32. /// let value = Arc::new(10);
  33. /// xarray_arc.store(333, value);
  34. /// assert!(*xarray_arc.load(333).unwrap().as_ref() == 10);
  35. ///
  36. /// let mut xarray_clone = xarray_arc.clone();
  37. /// assert!(*xarray_clone.load(333).unwrap().as_ref() == 10);
  38. /// let value = Arc::new(100);
  39. /// xarray_clone.store(333, value);
  40. ///
  41. /// assert!(*xarray_arc.load(333).unwrap().as_ref() == 10);
  42. /// assert!(*xarray_clone.load(333).unwrap().as_ref() == 100);
  43. /// ```
  44. ///
  45. /// The concepts XArray are originally introduced by Linux, which keeps the data structure of Linux's radix tree
  46. /// [Linux Radix Trees](https://lwn.net/Articles/175432/).
  47. pub struct XArray<I, M = NoneMark>
  48. where
  49. I: ItemEntry,
  50. M: ValidMark,
  51. {
  52. head: XEntry<I>,
  53. _marker: PhantomData<(I, M)>,
  54. }
  55. impl<I: ItemEntry, M: ValidMark> XArray<I, M> {
  56. /// Make a new, empty XArray.
  57. pub const fn new() -> Self {
  58. Self {
  59. head: XEntry::EMPTY,
  60. _marker: PhantomData,
  61. }
  62. }
  63. /// Return a reference to the head entry, and later will not modify the XNode pointed to by the `head`.
  64. pub(crate) fn head(&self) -> &XEntry<I> {
  65. &self.head
  66. }
  67. /// Return a reference to the head entry, and later will modify the XNode pointed to by the `head`.
  68. pub(crate) fn head_mut(&mut self) -> &XEntry<I> {
  69. // When a modification to the head is needed, it first checks whether the head is shared with other XArrays.
  70. // If it is, then it performs COW by allocating a new head and using it,
  71. // to prevent the modification from affecting the read or write operations on other XArrays.
  72. if let Some(new_head) = self.copy_if_shared(&self.head) {
  73. self.set_head(new_head);
  74. }
  75. &self.head
  76. }
  77. pub(crate) fn max_index(&self) -> u64 {
  78. if let Some(node) = self.head.as_node() {
  79. node.layer().max_index()
  80. } else {
  81. 0
  82. }
  83. }
  84. /// Set the head of the `XArray` with the new `XEntry`, and return the old `head`.
  85. pub(crate) fn set_head(&mut self, head: XEntry<I>) -> XEntry<I> {
  86. let old_head = core::mem::replace(&mut self.head, head);
  87. old_head
  88. }
  89. /// Attempts to load the item at the target index within the `XArray`.
  90. /// If the target item exists, return it with `Some`, Otherwise, return `None`.
  91. pub fn load(&self, index: u64) -> Option<&I> {
  92. let mut cursor = self.cursor(index);
  93. let entry = cursor.load();
  94. if entry.is_some_and(|entry| entry.is_item()) {
  95. entry.map(|entry| unsafe { &*(entry as *const XEntry<I> as *const I) })
  96. } else {
  97. None
  98. }
  99. }
  100. /// Stores the provided item in the `XArray` at the target index,
  101. /// and return the old item if it was previously stored in target index.
  102. pub fn store(&mut self, index: u64, item: I) -> Option<I> {
  103. let stored_entry = XEntry::from_item(item);
  104. let old_entry = self.cursor_mut(index).store(stored_entry);
  105. XEntry::into_item(old_entry)
  106. }
  107. /// Attempts to load the item and its mark information about input `mark` at the target index within the `XArray`.
  108. /// If the target item exists, return it with `Some`, Otherwise, return `None`.
  109. pub fn load_with_mark(&self, index: u64, mark: M) -> Option<(&I, bool)> {
  110. let mut cursor = self.cursor(index);
  111. let entry = cursor.load();
  112. let mark = if entry.is_some() {
  113. cursor.is_marked(mark)
  114. } else {
  115. None
  116. };
  117. if entry.is_some_and(|entry| entry.is_item()) {
  118. entry.map(|entry| {
  119. (
  120. unsafe { &*(entry as *const XEntry<I> as *const I) },
  121. mark.unwrap(),
  122. )
  123. })
  124. } else {
  125. None
  126. }
  127. }
  128. /// Stores the provided item in the `XArray` at the target index and mark it with input `mark`.
  129. /// and return the old item if it was previously stored in target index.
  130. pub fn store_with_mark(&mut self, index: u64, item: I, mark: M) -> Option<I> {
  131. let stored_entry = XEntry::from_item(item);
  132. let mut cursor = self.cursor_mut(index);
  133. let old_entry = cursor.store(stored_entry);
  134. cursor.set_mark(mark).unwrap();
  135. XEntry::into_item(old_entry)
  136. }
  137. /// Mark the item at the target index in the `XArray` with the input `mark`.
  138. /// If the item does not exist, return an Error.
  139. pub fn set_mark(&mut self, index: u64, mark: M) -> Result<(), ()> {
  140. self.cursor_mut(index).set_mark(mark)
  141. }
  142. /// Unset the input `mark` for the item at the target index in the `XArray`.
  143. /// If the item does not exist, return an Error.
  144. pub fn unset_mark(&mut self, index: u64, mark: M) -> Result<(), ()> {
  145. self.cursor_mut(index).unset_mark(mark)
  146. }
  147. /// Obtain a reference to the XEntry from a pointer pointing to it.
  148. ///
  149. /// # Safety
  150. /// The user must ensure that the pointer remains valid for the duration of use of the target XEntry reference.
  151. pub(crate) unsafe fn ref_entry(&self, entry_ptr: *const XEntry<I>) -> &XEntry<I> {
  152. &*entry_ptr
  153. }
  154. /// Unset the input `mark` for all of the items in the `XArray`.
  155. pub fn unset_mark_all(&mut self, mark: M) {
  156. let mut handle_list = VecDeque::new();
  157. if let Some(node) = self.head.as_node_mut() {
  158. handle_list.push_back(node);
  159. }
  160. while !handle_list.is_empty() {
  161. let node = handle_list.pop_front().unwrap();
  162. let mut offset = 0;
  163. let node_mark = node.mark(mark.index());
  164. while (offset as usize) < SLOT_SIZE {
  165. if node_mark.is_marked(offset) {
  166. // Safety: During this operation, the used XNode will not be removed and rge referenced XEntry must be valid.
  167. let entry = unsafe { self.ref_entry(node.entry(offset)) };
  168. if let Some(node) = entry.as_node_mut() {
  169. handle_list.push_back(node);
  170. }
  171. }
  172. offset += 1;
  173. }
  174. node.clear_mark(mark.index());
  175. }
  176. }
  177. /// Removes the `XEntry` at the target index within the `XArray`,
  178. /// and return the removed item if it was previously stored in target index.
  179. pub fn remove(&mut self, index: u64) -> Option<I> {
  180. let old_entry = self.cursor_mut(index).remove();
  181. XEntry::into_item(old_entry)
  182. }
  183. /// Create an `Cursor` to perform read related operations on the `XArray`.
  184. pub(crate) fn cursor<'a>(&'a self, index: u64) -> Cursor<'a, I, M> {
  185. Cursor::new(self, index)
  186. }
  187. /// Create an `CursorMut` to perform read and write operations on the `XArray`.
  188. pub(crate) fn cursor_mut<'a>(&'a mut self, index: u64) -> CursorMut<'a, I, M> {
  189. CursorMut::new(self, index)
  190. }
  191. }
  192. impl<I: ItemEntry + Clone, M: ValidMark> Clone for XArray<I, M> {
  193. /// Clone with cow mechanism.
  194. fn clone(&self) -> Self {
  195. let cloned_head = self.head.clone();
  196. Self {
  197. head: cloned_head,
  198. _marker: PhantomData,
  199. }
  200. }
  201. }