1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
use alloc::collections::VecDeque;
use core::marker::PhantomData;

use crate::cursor::{Cursor, CursorMut};
use crate::entry::{ItemEntry, XEntry};
use crate::mark::{NoneMark, XMark};
use crate::node::{Height, XNode};
use crate::range::Range;

pub(super) const BITS_PER_LAYER: usize = 6;
pub(super) const SLOT_SIZE: usize = 1 << BITS_PER_LAYER;
pub(super) const SLOT_MASK: usize = SLOT_SIZE - 1;
pub(super) const MAX_HEIGHT: usize = 64 / BITS_PER_LAYER + 1;

/// `XArray` is an abstract data type functioning like an expansive array of items where each item
/// must be an 8-byte object, such as `Arc<T>` or `Box<T>`.
///
/// User-stored pointers must have a minimum alignment of 4 bytes. `XArray` facilitates efficient
/// sequential access to adjacent entries, supporting multiple concurrent reads and exclusively
/// allowing one write operation at a time.
///
/// # Features
/// **Copy-on-write (COW):** If items within `XArray` implement the `Clone` trait, cloning can
/// leverage a COW mechanism. A clone of an `XArray` initially shares the head node with the
/// original, avoiding immediate deep copying. If a mutable operation is required on either
/// `XArray`, a deep copy of the relevant nodes is made first, ensuring isolated operations.
///
/// **Cursors:** Interaction with `XArray` is mediated through [`Cursor`] and [`CursorMut`]. A
/// `Cursor` requires an immutable reference, while `CursorMut` requires a mutable reference. As
/// such, multiple `Cursor` instances can coexist, but `CursorMut` operations are singular,
/// reflecting the behavior of shared (`&`) and exclusive (`&mut`) references. Cursors offer
/// precise index positioning and traversal capabilities in the `XArray`.
///
/// **Marking:** `XArray` enables marking of individual items or the `XArray` itself for user
/// convenience. Items and the `XArray` can have up to three distinct marks by default, with each
/// mark independently maintained. Users can use self-defined types as marks by implementing the
/// `From<Type>` trait for [`XMark`]. Marking is also applicable to internal nodes, indicating
/// marked descendant nodes, though such marking is not transparent to users.
///
/// # Example
///
/// ```
/// use std::sync::Arc;
/// use std::sync::{Mutex, MutexGuard};
/// use xarray::*;
///
/// let mut xarray_arc: XArray<Arc<i32>> = XArray::new();
/// let value = Arc::new(10);
/// xarray_arc.store(10, value);
/// assert!(*xarray_arc.load(10).unwrap().as_ref() == 10);
///
/// let mut xarray_clone = xarray_arc.clone();
/// assert!(*xarray_clone.load(10).unwrap().as_ref() == 10);
/// let value = Arc::new(100);
/// xarray_clone.store(10, value);
///
/// assert!(*xarray_arc.load(10).unwrap().as_ref() == 10);
/// assert!(*xarray_clone.load(10).unwrap().as_ref() == 100);
/// ```
///
/// The XArray concept was originally introduced by Linux, which keeps the data structure of [Linux
/// Radix Trees](https://lwn.net/Articles/175432/).
pub struct XArray<I, M = NoneMark>
where
    I: ItemEntry,
    M: Into<XMark>,
{
    marks: [bool; 3],
    head: XEntry<I>,
    _marker: PhantomData<M>,
}

impl<I: ItemEntry, M: Into<XMark>> XArray<I, M> {
    /// Makes a new, empty `XArray`.
    pub const fn new() -> Self {
        Self {
            marks: [false; 3],
            head: XEntry::EMPTY,
            _marker: PhantomData,
        }
    }

    /// Marks the `XArray` with the input `mark`.
    pub fn set_mark(&mut self, mark: M) {
        self.marks[mark.into().index()] = true;
    }

    /// Unsets the input `mark` for the `XArray`.
    pub fn unset_mark(&mut self, mark: M) {
        self.marks[mark.into().index()] = false;
    }

    /// Checks whether the `XArray` is marked with the input `mark`.
    pub fn is_marked(&self, mark: M) -> bool {
        self.marks[mark.into().index()]
    }

    /// Returns a shared reference to the head `XEntry`.
    pub(super) fn head(&self) -> &XEntry<I> {
        &self.head
    }

    /// Returns an exclusive reference to the head `XEntry`.
    pub(super) fn head_mut(&mut self) -> &mut XEntry<I> {
        &mut self.head
    }

    /// Increases the height of the `XArray` so that the `index`-th element can be stored.
    pub(super) fn reserve(&mut self, index: u64) {
        if self.head.is_null() {
            let height = Height::from_index(index);
            self.head = XEntry::from_node(XNode::new_root(height));
            return;
        }

        loop {
            let height = self.head.as_node_ref().unwrap().height();

            if height.max_index() >= index {
                return;
            }

            let old_entry = core::mem::replace(&mut self.head, XEntry::EMPTY);

            let mut new_node = XNode::new_root(height.go_root());
            new_node.set_entry(0, old_entry);

            self.head = XEntry::from_node(new_node);
        }
    }

    /// Calculates the maximum index of elements that can be stored with the current height of the
    /// `XArray`.
    pub(super) fn max_index(&self) -> u64 {
        self.head()
            .as_node_ref()
            .map(|node| node.height().max_index())
            .unwrap_or(0)
    }

    /// Loads the `index`-th item.
    ///
    /// If the target item exists, it will be returned with `Some(_)`, otherwise, `None` will be
    /// returned.
    pub fn load(&self, index: u64) -> Option<I::Ref<'_>> {
        let mut cursor = self.cursor(index);
        cursor.load()
    }

    /// Stores the provided item in the `XArray` at the target index, and returns the old item if
    /// some item was previously stored in the same position.
    pub fn store(&mut self, index: u64, item: I) -> Option<I> {
        let mut cursor = self.cursor_mut(index);
        cursor.store(item)
    }

    /// Unsets the input `mark` for all of the items in the `XArray`.
    pub fn unset_mark_all(&mut self, mark: M) {
        let mut pending_nodes = VecDeque::new();

        if let Some(node) = self.head.as_node_mut_or_cow() {
            pending_nodes.push_back(node);
        }

        let mark_index = mark.into().index();

        while let Some(node) = pending_nodes.pop_front() {
            let node_mark = node.mark(mark_index);
            node.clear_mark(mark_index);

            node.entries_mut()
                .iter_mut()
                .enumerate()
                .filter(|(offset, _)| node_mark.is_marked(*offset as u8))
                .filter_map(|(_, next_entry)| next_entry.as_node_mut_or_cow())
                .for_each(|next_node| pending_nodes.push_back(next_node));
        }
    }

    /// Removes the `XEntry` in the `XArray` at the target index, and returns the removed item if
    /// some item was previously stored in the same position.
    pub fn remove(&mut self, index: u64) -> Option<I> {
        let mut cursor = self.cursor_mut(index);
        cursor.remove()
    }

    /// Creates a [`Cursor`] to perform read-related operations in the `XArray`.
    pub fn cursor(&self, index: u64) -> Cursor<'_, I, M> {
        Cursor::new(self, index)
    }

    /// Creates a [`CursorMut`] to perform read- and write-related operations in the `XArray`.
    pub fn cursor_mut(&mut self, index: u64) -> CursorMut<'_, I, M> {
        CursorMut::new(self, index)
    }

    /// Creates a [`Range`] which can be immutably iterated over the indexes corresponding to the
    /// specified `range`.
    pub fn range(&self, range: core::ops::Range<u64>) -> Range<'_, I, M> {
        let cursor = Cursor::new(self, range.start);
        Range::new(cursor, range.end)
    }
}

impl<I: ItemEntry + Clone, M: Into<XMark>> Clone for XArray<I, M> {
    /// Clones the `XArray` with the COW mechanism.
    fn clone(&self) -> Self {
        let cloned_head = self.head.clone();
        Self {
            marks: self.marks,
            head: cloned_head,
            _marker: PhantomData,
        }
    }
}