Skip to main content

subms_treap/features/
persistent.rs

1//! Persistent (copy-on-write) treap.
2//!
3//! Every `insert` / `remove` returns a NEW `PersistentTreap` without
4//! mutating the receiver. The mutation path is copied (`O(log N)`
5//! nodes); every other subtree is shared via `Rc`, so memory stays
6//! sub-linear in the number of held versions.
7//!
8//! Old versions remain fully queryable. This is the right shape for
9//! undo stacks, time-travel debugging, and immutable-by-default
10//! sequence builders.
11//!
12//! The base `Treap` in `lib.rs` is the arena-backed mutable variant.
13//! These two share priority-generation conventions (same LCG) but
14//! intentionally have different memory layouts: the arena base is
15//! cache-dense; the persistent variant trades density for the
16//! shared-subtree invariant `Rc` enforces.
17
18use std::cmp::Ordering;
19use std::rc::Rc;
20
21type Link<K, V> = Option<Rc<Node<K, V>>>;
22
23struct Node<K, V> {
24    key: K,
25    value: V,
26    priority: u64,
27    left: Link<K, V>,
28    right: Link<K, V>,
29}
30
31pub struct PersistentTreap<K, V> {
32    root: Link<K, V>,
33    len: usize,
34    rng_state: u64,
35}
36
37impl<K: Ord + Clone, V: Clone> PersistentTreap<K, V> {
38    pub fn new(seed: u64) -> Self {
39        Self {
40            root: None,
41            len: 0,
42            rng_state: seed | 1,
43        }
44    }
45
46    pub fn len(&self) -> usize {
47        self.len
48    }
49    pub fn is_empty(&self) -> bool {
50        self.len == 0
51    }
52
53    /// Return a NEW treap with `key -> value` inserted (or its value
54    /// replaced). `self` is left untouched. Shared subtrees are
55    /// reference-counted with the previous version.
56    pub fn insert(&self, key: K, value: V) -> Self {
57        let mut next_rng = self.rng_state;
58        let priority = next_priority(&mut next_rng);
59        let (new_root, replaced) = ins(&self.root, key, value, priority);
60        let len = if replaced { self.len } else { self.len + 1 };
61        Self {
62            root: new_root,
63            len,
64            rng_state: next_rng,
65        }
66    }
67
68    /// Return a NEW treap with `key` removed. If `key` is absent, the
69    /// returned treap is structurally identical (root pointer cloned).
70    pub fn remove(&self, key: &K) -> Self {
71        let (new_root, removed) = rem(&self.root, key);
72        let len = if removed { self.len - 1 } else { self.len };
73        Self {
74            root: new_root,
75            len,
76            rng_state: self.rng_state,
77        }
78    }
79
80    pub fn get(&self, key: &K) -> Option<&V> {
81        let mut cur = self.root.as_deref();
82        while let Some(node) = cur {
83            match key.cmp(&node.key) {
84                Ordering::Less => cur = node.left.as_deref(),
85                Ordering::Greater => cur = node.right.as_deref(),
86                Ordering::Equal => return Some(&node.value),
87            }
88        }
89        None
90    }
91
92    pub fn collect_in_order(&self) -> Vec<(K, V)> {
93        let mut out = Vec::with_capacity(self.len);
94        in_order(&self.root, &mut out);
95        out
96    }
97}
98
99impl<K, V> Clone for PersistentTreap<K, V> {
100    fn clone(&self) -> Self {
101        Self {
102            root: self.root.clone(),
103            len: self.len,
104            rng_state: self.rng_state,
105        }
106    }
107}
108
109fn next_priority(state: &mut u64) -> u64 {
110    *state = state
111        .wrapping_mul(6364136223846793005)
112        .wrapping_add(1442695040888963407);
113    // SplitMix64 finalizer - decorrelate the priority from the key, which
114    // is otherwise drawn from the same LCG family and sorts the tree into
115    // a spine. Mirrors the base Treap::next_priority fix.
116    let mut z = *state;
117    z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
118    z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
119    z ^ (z >> 31)
120}
121
122fn ins<K: Ord + Clone, V: Clone>(
123    link: &Link<K, V>,
124    key: K,
125    value: V,
126    priority: u64,
127) -> (Link<K, V>, bool) {
128    match link {
129        None => (
130            Some(Rc::new(Node {
131                key,
132                value,
133                priority,
134                left: None,
135                right: None,
136            })),
137            false,
138        ),
139        Some(node) => match key.cmp(&node.key) {
140            Ordering::Equal => (
141                Some(Rc::new(Node {
142                    key,
143                    value,
144                    priority: node.priority,
145                    left: node.left.clone(),
146                    right: node.right.clone(),
147                })),
148                true,
149            ),
150            Ordering::Less => {
151                let (new_left, replaced) = ins(&node.left, key, value, priority);
152                let new_left_pri = new_left.as_ref().unwrap().priority;
153                let rebuilt = Rc::new(Node {
154                    key: node.key.clone(),
155                    value: node.value.clone(),
156                    priority: node.priority,
157                    left: new_left,
158                    right: node.right.clone(),
159                });
160                let rooted = if new_left_pri > node.priority {
161                    rotate_right(&rebuilt)
162                } else {
163                    rebuilt
164                };
165                (Some(rooted), replaced)
166            }
167            Ordering::Greater => {
168                let (new_right, replaced) = ins(&node.right, key, value, priority);
169                let new_right_pri = new_right.as_ref().unwrap().priority;
170                let rebuilt = Rc::new(Node {
171                    key: node.key.clone(),
172                    value: node.value.clone(),
173                    priority: node.priority,
174                    left: node.left.clone(),
175                    right: new_right,
176                });
177                let rooted = if new_right_pri > node.priority {
178                    rotate_left(&rebuilt)
179                } else {
180                    rebuilt
181                };
182                (Some(rooted), replaced)
183            }
184        },
185    }
186}
187
188fn rem<K: Ord + Clone, V: Clone>(link: &Link<K, V>, key: &K) -> (Link<K, V>, bool) {
189    match link {
190        None => (None, false),
191        Some(node) => match key.cmp(&node.key) {
192            Ordering::Less => {
193                let (new_left, removed) = rem(&node.left, key);
194                let rebuilt = Rc::new(Node {
195                    key: node.key.clone(),
196                    value: node.value.clone(),
197                    priority: node.priority,
198                    left: new_left,
199                    right: node.right.clone(),
200                });
201                (Some(rebuilt), removed)
202            }
203            Ordering::Greater => {
204                let (new_right, removed) = rem(&node.right, key);
205                let rebuilt = Rc::new(Node {
206                    key: node.key.clone(),
207                    value: node.value.clone(),
208                    priority: node.priority,
209                    left: node.left.clone(),
210                    right: new_right,
211                });
212                (Some(rebuilt), removed)
213            }
214            Ordering::Equal => (merge_subtrees(&node.left, &node.right), true),
215        },
216    }
217}
218
219fn merge_subtrees<K: Clone, V: Clone>(left: &Link<K, V>, right: &Link<K, V>) -> Link<K, V> {
220    match (left, right) {
221        (None, r) => r.clone(),
222        (l, None) => l.clone(),
223        (Some(l), Some(r)) => {
224            if l.priority > r.priority {
225                let merged = merge_subtrees(&l.right, right);
226                Some(Rc::new(Node {
227                    key: l.key.clone(),
228                    value: l.value.clone(),
229                    priority: l.priority,
230                    left: l.left.clone(),
231                    right: merged,
232                }))
233            } else {
234                let merged = merge_subtrees(left, &r.left);
235                Some(Rc::new(Node {
236                    key: r.key.clone(),
237                    value: r.value.clone(),
238                    priority: r.priority,
239                    left: merged,
240                    right: r.right.clone(),
241                }))
242            }
243        }
244    }
245}
246
247fn rotate_right<K: Clone, V: Clone>(node: &Rc<Node<K, V>>) -> Rc<Node<K, V>> {
248    let left = node.left.as_ref().expect("rotate_right needs left child");
249    let new_right = Rc::new(Node {
250        key: node.key.clone(),
251        value: node.value.clone(),
252        priority: node.priority,
253        left: left.right.clone(),
254        right: node.right.clone(),
255    });
256    Rc::new(Node {
257        key: left.key.clone(),
258        value: left.value.clone(),
259        priority: left.priority,
260        left: left.left.clone(),
261        right: Some(new_right),
262    })
263}
264
265fn rotate_left<K: Clone, V: Clone>(node: &Rc<Node<K, V>>) -> Rc<Node<K, V>> {
266    let right = node.right.as_ref().expect("rotate_left needs right child");
267    let new_left = Rc::new(Node {
268        key: node.key.clone(),
269        value: node.value.clone(),
270        priority: node.priority,
271        left: node.left.clone(),
272        right: right.left.clone(),
273    });
274    Rc::new(Node {
275        key: right.key.clone(),
276        value: right.value.clone(),
277        priority: right.priority,
278        left: Some(new_left),
279        right: right.right.clone(),
280    })
281}
282
283fn in_order<K: Clone, V: Clone>(link: &Link<K, V>, out: &mut Vec<(K, V)>) {
284    if let Some(node) = link {
285        in_order(&node.left, out);
286        out.push((node.key.clone(), node.value.clone()));
287        in_order(&node.right, out);
288    }
289}
290
291#[cfg(test)]
292#[path = "persistent_tests.rs"]
293mod tests;