content_tree/
leaf.rs

1use std::mem::take;
2use std::ptr::NonNull;
3
4use rle::Searchable;
5
6use super::*;
7
8impl<E: ContentTraits, I: TreeMetrics<E>, const IE: usize, const LE: usize> NodeLeaf<E, I, IE, LE> {
9    // Note this doesn't return a Pin<Box<Self>> like the others. At the point of creation, there's
10    // no reason for this object to be pinned. (Is that a bad idea? I'm not sure.)
11    pub(crate) unsafe fn new(next: Option<NonNull<Self>>) -> Self {
12        Self::new_with_parent(ParentPtr::Root(NonNull::dangling()), next)
13    }
14
15    pub(crate) fn new_with_parent(parent: ParentPtr<E, I, IE, LE>, next: Option<NonNull<Self>>) -> Self {
16        Self {
17            parent,
18            data: [E::default(); LE],
19            num_entries: 0,
20            _pin: PhantomPinned,
21            next,
22        }
23    }
24
25    // pub fn find2(&self, loc: CRDTLocation) -> (ClientSeq, Option<usize>) {
26    //     let mut raw_pos: ClientSeq = 0;
27
28    //     for i in 0..NUM_ENTRIES {
29    //         let entry = self.data[i];
30    //         if entry.is_invalid() { break; }
31
32    //         if entry.loc.client == loc.client && entry.get_seq_range().contains(&loc.seq) {
33    //             if entry.len > 0 {
34    //                 raw_pos += loc.seq - entry.loc.seq;
35    //             }
36    //             return (raw_pos, Some(i));
37    //         } else {
38    //             raw_pos += entry.get_text_len()
39    //         }
40    //     }
41    //     (raw_pos, None)
42    // }
43
44    /// Find a given text offset within the node.
45    ///
46    /// Returns (index, offset within entry)
47    ///
48    /// TODO: Add a parameter for figuring out the offset at content length, and pass that in
49    /// from the ContentLength trait.
50    pub fn find_offset<F>(&self, mut offset: usize, stick_end: bool, entry_to_num: F) -> Option<(usize, usize)>
51        where F: Fn(E) -> usize {
52        for i in 0..self.len_entries() {
53            // if offset == 0 {
54            //     return Some((i, 0));
55            // }
56
57            let entry: E = self.data[i];
58            // if !entry.is_valid() { break; }
59
60            // let text_len = entry.content_len();
61            let entry_len = entry_to_num(entry);
62            if offset < entry_len || (stick_end && entry_len == offset) {
63                // Found it.
64                return Some((i, offset));
65            } else {
66                offset -= entry_len
67            }
68        }
69
70        if offset == 0 { // Special case for the first inserted element - we may never enter the loop.
71            Some((self.len_entries(), 0))
72        } else { None }
73    }
74
75    pub fn next_leaf(&self) -> Option<NonNull<Self>> {
76        self.next
77    }
78
79    pub fn prev_leaf(&self) -> Option<NonNull<Self>> {
80        self.adjacent_leaf_by_traversal(false)
81    }
82
83    pub(crate) fn adjacent_leaf_by_traversal(&self, direction_forward: bool) -> Option<NonNull<Self>> {
84        // TODO: Remove direction_forward here.
85
86        // println!("** traverse called {:?} {}", self, traverse_next);
87        // idx is 0. Go up as far as we can until we get to an index that has room, or we hit the
88        // root.
89        let mut parent = self.parent;
90        let mut node_ptr = NodePtr::Leaf(unsafe { NonNull::new_unchecked(self as *const _ as *mut _) });
91
92        loop {
93            match parent {
94                ParentPtr::Root(_) => { return None; },
95                ParentPtr::Internal(n) => {
96                    let node_ref = unsafe { n.as_ref() };
97                    // Time to find ourself up this tree.
98                    let idx = node_ref.find_child(node_ptr).unwrap();
99                    // println!("found myself at {}", idx);
100
101                    let next_idx: Option<usize> = if direction_forward {
102                        let next_idx = idx + 1;
103                        // This would be much cleaner if I put a len field in NodeInternal instead.
104                        // TODO: Consider using node_ref.count_children() instead of this mess.
105                        if (next_idx < IE) && node_ref.children[next_idx].is_some() {
106                            Some(next_idx)
107                        } else { None }
108                    } else if idx > 0 {
109                        Some(idx - 1)
110                    } else { None };
111                    // println!("index {:?}", next_idx);
112
113                    if let Some(next_idx) = next_idx {
114                        // Whew - now we can descend down from here.
115                        // println!("traversing laterally to {}", next_idx);
116                        node_ptr = unsafe { node_ref.children[next_idx].as_ref().unwrap().as_ptr() };
117                        break;
118                    } else {
119                        // idx is 0. Keep climbing that ladder!
120                        node_ptr = NodePtr::Internal(unsafe { NonNull::new_unchecked(node_ref as *const _ as *mut _) });
121                        parent = node_ref.parent;
122                    }
123                }
124            }
125        }
126
127        // Now back down. We don't need idx here because we just take the first / last item in each
128        // node going down the tree.
129        loop {
130            // println!("nodeptr {:?}", node_ptr);
131            match node_ptr {
132                NodePtr::Internal(n) => {
133                    let node_ref = unsafe { n.as_ref() };
134                    let next_idx = if direction_forward {
135                        0
136                    } else {
137                        let num_children = node_ref.count_children();
138                        assert!(num_children > 0);
139                        num_children - 1
140                    };
141                    node_ptr = unsafe { node_ref.children[next_idx].as_ref().unwrap().as_ptr() };
142                },
143                NodePtr::Leaf(n) => {
144                    // Finally.
145                    return Some(n);
146                }
147            }
148        }
149    }
150
151    // pub(super) fn actually_count_entries(&self) -> usize {
152    //     self.data.iter()
153    //     .position(|e| e.loc.client == CLIENT_INVALID)
154    //     .unwrap_or(NUM_ENTRIES)
155    // }
156    pub fn len_entries(&self) -> usize {
157        self.num_entries as usize
158    }
159
160    pub fn as_slice(&self) -> &[E] {
161        &self.data[0..self.num_entries as usize]
162    }
163
164    // Recursively (well, iteratively) ascend and update all the counts along
165    // the way up. TODO: Move this - This method shouldn't be in NodeLeaf.
166    pub fn update_parent_count(&mut self, amt: I::Update) {
167        if amt == I::Update::default() { return; }
168
169        let mut child = NodePtr::Leaf(unsafe { NonNull::new_unchecked(self) });
170        let mut parent = self.parent;
171
172        loop {
173            match parent {
174                ParentPtr::Root(mut r) => {
175                    unsafe {
176                        I::update_offset_by_marker(&mut r.as_mut().count, &amt);
177                        // r.as_mut().count = r.as_ref().count.wrapping_add(amt as usize); }
178                    }
179                    break;
180                },
181                ParentPtr::Internal(mut n) => {
182                    let idx = unsafe { n.as_mut() }.find_child(child).unwrap();
183                    let c = &mut unsafe { n.as_mut() }.metrics[idx];
184                    // :(
185                    I::update_offset_by_marker(c, &amt);
186                    // *c = c.wrapping_add(amt as u32);
187
188                    // And recurse.
189                    child = NodePtr::Internal(n);
190                    parent = unsafe { n.as_mut() }.parent;
191                },
192            };
193        }
194    }
195
196    pub fn flush_metric_update(&mut self, marker: &mut I::Update) {
197        // println!("flush {:?}", marker);
198        let amt = take(marker);
199        self.update_parent_count(amt);
200    }
201
202    pub fn has_root_as_parent(&self) -> bool {
203        self.parent.is_root()
204    }
205
206    pub fn count_items(&self) -> I::Value {
207        if I::CAN_COUNT_ITEMS {
208            // Optimization using the index. TODO: check if this is actually faster.
209            match self.parent {
210                ParentPtr::Root(root) => {
211                    unsafe { root.as_ref() }.count
212                }
213                ParentPtr::Internal(node) => {
214                    let child = NodePtr::Leaf(unsafe { NonNull::new_unchecked(self as *const _ as *mut _) });
215                    let idx = unsafe { node.as_ref() }.find_child(child).unwrap();
216                    unsafe { node.as_ref() }.metrics[idx]
217                }
218            }
219        } else {
220            // Count items the boring way. Hopefully this will optimize tightly.
221            let mut val = I::Value::default();
222            for elem in self.data[..self.num_entries as usize].iter() {
223                I::increment_offset(&mut val, elem);
224            }
225            val
226        }
227    }
228
229    /// Remove a single item from the node
230    pub fn splice_out(&mut self, idx: usize) {
231        debug_assert!(idx < self.num_entries as usize);
232        self.data.copy_within(idx + 1..self.num_entries as usize, idx);
233        self.num_entries -= 1;
234    }
235
236    pub fn clear_all(&mut self) {
237        // self.data[0..self.num_entries as usize].fill(E::default());
238        self.num_entries = 0;
239    }
240
241    pub fn unsafe_cursor_at_start(&self) -> UnsafeCursor<E, I, IE, LE> {
242        UnsafeCursor::new(
243            unsafe { NonNull::new_unchecked(self as *const _ as *mut _) },
244            0,
245            0
246        )
247    }
248    
249    // pub fn cursor_at_start<'a, 'b: 'a>(&'a self, tree: &'b ContentTreeRaw<E, I, IE, LE>) -> Cursor<E, I, IE, LE> {
250    //     // This is safe because you can only reference a leaf while you immutably borrow a
251    //     // content-tree. The lifetime of the returned cursor should match self.
252    //     unsafe { Cursor::unchecked_from_raw(tree, self.unsafe_cursor_at_start()) }
253    // }
254}
255
256impl<E: ContentTraits + Searchable, I: TreeMetrics<E>, const IE: usize, const LE: usize> NodeLeaf<E, I, IE, LE> {
257    pub fn find(&self, loc: E::Item) -> Option<UnsafeCursor<E, I, IE, LE>> {
258        for i in 0..self.len_entries() {
259            let entry: E = self.data[i];
260
261            if let Some(offset) = entry.get_offset(loc) {
262                debug_assert!(offset < entry.len());
263                // let offset = if entry.is_insert() { entry_offset } else { 0 };
264
265                return Some(UnsafeCursor::new(
266                    unsafe { NonNull::new_unchecked(self as *const _ as *mut _) },
267                    i,
268                    offset
269                ))
270            }
271        }
272        None
273    }
274}