treap_map/
update.rs

1use crate::KeyMngTrait;
2
3use super::{config::TreapMapConfig, node::Node};
4
5///  The interface for insert/update/delete a node in a `Treap` by key by custom
6/// logic.
7pub trait TreapNodeUpdate<C: TreapMapConfig> {
8    /// The return value
9    type Ret;
10    /// The return value if delete is required.
11    type DeleteRet;
12
13    /// Retrieve the key of the node to be updated.
14    fn treap_key(&self) -> (&C::SortKey, &C::SearchKey);
15
16    /// The core update logic for a node.
17    ///
18    /// We pass `Option<&mut Box<_>>` instead of `&mut Option<Box<_>>` here
19    /// intentionally. This approach restricts the function from directly
20    /// inserting or removing nodes. Instead, the function should
21    /// communicates any attempts to add or remove nodes through
22    /// the `UpdateResult`.
23    fn update_node(
24        self, maybe_node: Option<&mut Box<Node<C>>>,
25    ) -> OpResult<C, Self::Ret, Self::DeleteRet>;
26
27    /// When a node needs to be deleted during an update, the deleted node will
28    /// be fed to this method. The deletion logic itself is managed by
29    /// `update_inner`.
30    fn handle_delete(
31        deleted_node: Option<Box<Node<C>>>, delete_ret: Self::DeleteRet,
32    ) -> Self::Ret;
33}
34
35pub enum OpResult<C: TreapMapConfig, R, DR> {
36    /// Used when the targeted slot in the Treap is vacant and a new node
37    /// should be inserted at this position.
38    InsertOnVacant { insert: Box<Node<C>>, ret: R },
39    /// Used when the targeted node been updated or remains unchanged.
40    /// `update_weight` is a flag to indicate whether the weight of the node
41    /// has changed as a result of the update. `ret` is the return value
42    /// associated with this operation.
43    ///
44    /// ⚠️ WARNING: The update operation must not change the sort key of the
45    /// node.
46    Updated { update_weight: bool, ret: R },
47    /// Used when the targeted node is not changed. Equivalent to `Updated`
48    /// with `update_weight = false`
49    Noop(R),
50    /// Used when the targeted node should be deleted.
51    Delete(DR),
52}
53
54pub(crate) struct InsertOp<'a, C: TreapMapConfig> {
55    pub node: Box<Node<C>>,
56    pub ext_map: &'a mut C::ExtMap,
57}
58
59impl<'a, C: TreapMapConfig> TreapNodeUpdate<C> for InsertOp<'a, C> {
60    type DeleteRet = ();
61    type Ret = Option<C::Value>;
62
63    fn treap_key(&self) -> (&C::SortKey, &C::SearchKey) {
64        (&self.node.sort_key, &self.node.key)
65    }
66
67    fn update_node(
68        self, maybe_node: Option<&mut Box<Node<C>>>,
69    ) -> OpResult<C, Self::Ret, Self::DeleteRet> {
70        use OpResult::*;
71
72        if let Some(node) = maybe_node {
73            let ret = Some(node.value.clone());
74            let update_weight = node.weight != self.node.weight;
75
76            self.ext_map.view_update(
77                &self.node.key,
78                Some(&self.node.value),
79                Some(&node.value),
80            );
81
82            node.value = self.node.value;
83            node.weight = self.node.weight;
84
85            Updated { ret, update_weight }
86        } else {
87            self.ext_map.view_update(
88                &self.node.key,
89                Some(&self.node.value),
90                None,
91            );
92            InsertOnVacant {
93                insert: self.node,
94                ret: None,
95            }
96        }
97    }
98
99    fn handle_delete(
100        _deleted_node: Option<Box<Node<C>>>, _delete_ret: (),
101    ) -> Self::Ret {
102        // update_node never returns deletion
103        unreachable!()
104    }
105}
106
107pub(crate) struct RemoveOp<'a, C: TreapMapConfig> {
108    pub key: (&'a C::SortKey, &'a C::SearchKey),
109    pub ext_map: &'a mut C::ExtMap,
110}
111
112impl<'a, C: TreapMapConfig> TreapNodeUpdate<C> for RemoveOp<'a, C> {
113    type DeleteRet = ();
114    type Ret = Option<C::Value>;
115
116    fn treap_key(&self) -> (&C::SortKey, &C::SearchKey) { self.key }
117
118    fn update_node(
119        self, maybe_node: Option<&mut Box<Node<C>>>,
120    ) -> OpResult<C, Self::Ret, Self::DeleteRet> {
121        self.ext_map.view_update(
122            self.key.1,
123            None,
124            maybe_node.map(|x| &x.value),
125        );
126        OpResult::Delete(())
127    }
128
129    fn handle_delete(
130        deleted_node: Option<Box<Node<C>>>, _delete_ret: (),
131    ) -> Self::Ret {
132        deleted_node.map(|x| x.value)
133    }
134}
135
136/// Represents the outcome of an operation applied in the
137/// [`TreapMap::update`][crate::TreapMap::update] function.
138///
139/// `ApplyOpOutcome` is used to convey the result of a user-defined operation
140/// applied to a node in the `TreapMap`. It provides details to the `TreapMap`
141/// about how to properly maintain the node after the operation.
142
143pub struct ApplyOpOutcome<T> {
144    /// The value to be forwarded as the return value of the `update`
145    /// function.
146    pub out: T,
147    /// A flag indicating whether the operation has modified the node's weight.
148    /// If `true`, the `TreapMap` will recompute the accumulated weights.
149    pub update_weight: bool,
150    ///  A flag indicating whether the operation has changed the node's key or
151    /// sort key. If `true`, the `TreapMap` will reposition the node within the
152    /// treap.
153    pub update_key: bool,
154    /// A flag indicating whether the node should be deleted following the
155    /// operation. If `true`, the `TreapMap` will remove the node.
156    pub delete_item: bool,
157}
158
159pub(crate) struct ApplyOp<'a, C, U, I, T, E>
160where
161    C: TreapMapConfig,
162    U: FnOnce(&mut Node<C>) -> Result<ApplyOpOutcome<T>, E>,
163    I: FnOnce() -> Result<(Node<C>, T), E>,
164{
165    pub key: (&'a C::SortKey, &'a C::SearchKey),
166    pub ext_map: &'a mut C::ExtMap,
167    pub update: U,
168    pub insert: I,
169}
170
171impl<'a, 'b, C, U, I, T, E> TreapNodeUpdate<C> for ApplyOp<'a, C, U, I, T, E>
172where
173    C: TreapMapConfig,
174    U: FnOnce(&mut Node<C>) -> Result<ApplyOpOutcome<T>, E>,
175    I: FnOnce() -> Result<(Node<C>, T), E>,
176{
177    type DeleteRet = (T, bool);
178    type Ret = Result<(T, Option<Box<Node<C>>>), E>;
179
180    fn treap_key(&self) -> (&'a C::SortKey, &'a C::SearchKey) { self.key }
181
182    fn update_node(
183        self, maybe_node: Option<&mut Box<Node<C>>>,
184    ) -> OpResult<C, Self::Ret, Self::DeleteRet> {
185        use OpResult::*;
186        match maybe_node {
187            None => {
188                let (node, ret) = match (self.insert)() {
189                    Ok(x) => x,
190                    Err(err) => {
191                        return Noop(Err(err));
192                    }
193                };
194
195                self.ext_map
196                    .view_update(&*self.key.1, Some(&node.value), None);
197                assert!(
198                    C::next_node_dir(self.key, (&node.sort_key, &node.key))
199                        .is_none(),
200                    "Inserted node has inconsistent key"
201                );
202                InsertOnVacant {
203                    insert: Box::new(node),
204                    ret: Ok((ret, None)),
205                }
206            }
207            Some(node) => {
208                let old_value = node.value.clone();
209                let ApplyOpOutcome {
210                    out,
211                    update_weight,
212                    update_key,
213                    delete_item,
214                } = match (self.update)(node) {
215                    Ok(x) => x,
216                    Err(err) => {
217                        return Noop(Err(err));
218                    }
219                };
220                let new_value =
221                    if delete_item { None } else { Some(&node.value) };
222                self.ext_map.view_update(
223                    &*self.key.1,
224                    new_value,
225                    Some(&old_value),
226                );
227
228                if update_key || delete_item {
229                    Delete((out, delete_item))
230                } else {
231                    Updated {
232                        update_weight,
233                        ret: Ok((out, None)),
234                    }
235                }
236            }
237        }
238    }
239
240    fn handle_delete(
241        deleted_node: Option<Box<Node<C>>>, (ret, delete_item): (T, bool),
242    ) -> Self::Ret {
243        let to_reinsert_node = if !delete_item {
244            Some(deleted_node.unwrap())
245        } else {
246            None
247        };
248        Ok((ret, to_reinsert_node))
249    }
250}