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.
142pub struct ApplyOpOutcome<T> {
143    /// The value to be forwarded as the return value of the `update`
144    /// function.
145    pub out: T,
146    /// A flag indicating whether the operation has modified the node's weight.
147    /// If `true`, the `TreapMap` will recompute the accumulated weights.
148    pub update_weight: bool,
149    ///  A flag indicating whether the operation has changed the node's key or
150    /// sort key. If `true`, the `TreapMap` will reposition the node within the
151    /// treap.
152    pub update_key: bool,
153    /// A flag indicating whether the node should be deleted following the
154    /// operation. If `true`, the `TreapMap` will remove the node.
155    pub delete_item: bool,
156}
157
158pub(crate) struct ApplyOp<'a, C, U, I, T, E>
159where
160    C: TreapMapConfig,
161    U: FnOnce(&mut Node<C>) -> Result<ApplyOpOutcome<T>, E>,
162    I: FnOnce() -> Result<(Node<C>, T), E>,
163{
164    pub key: (&'a C::SortKey, &'a C::SearchKey),
165    pub ext_map: &'a mut C::ExtMap,
166    pub update: U,
167    pub insert: I,
168}
169
170impl<'a, C, U, I, T, E> TreapNodeUpdate<C> for ApplyOp<'a, C, U, I, T, E>
171where
172    C: TreapMapConfig,
173    U: FnOnce(&mut Node<C>) -> Result<ApplyOpOutcome<T>, E>,
174    I: FnOnce() -> Result<(Node<C>, T), E>,
175{
176    type DeleteRet = (T, bool);
177    type Ret = Result<(T, Option<Box<Node<C>>>), E>;
178
179    fn treap_key(&self) -> (&'a C::SortKey, &'a C::SearchKey) { self.key }
180
181    fn update_node(
182        self, maybe_node: Option<&mut Box<Node<C>>>,
183    ) -> OpResult<C, Self::Ret, Self::DeleteRet> {
184        use OpResult::*;
185        match maybe_node {
186            None => {
187                let (node, ret) = match (self.insert)() {
188                    Ok(x) => x,
189                    Err(err) => {
190                        return Noop(Err(err));
191                    }
192                };
193
194                self.ext_map
195                    .view_update(self.key.1, Some(&node.value), None);
196                assert!(
197                    C::next_node_dir(self.key, (&node.sort_key, &node.key))
198                        .is_none(),
199                    "Inserted node has inconsistent key"
200                );
201                InsertOnVacant {
202                    insert: Box::new(node),
203                    ret: Ok((ret, None)),
204                }
205            }
206            Some(node) => {
207                let old_value = node.value.clone();
208                let ApplyOpOutcome {
209                    out,
210                    update_weight,
211                    update_key,
212                    delete_item,
213                } = match (self.update)(node) {
214                    Ok(x) => x,
215                    Err(err) => {
216                        return Noop(Err(err));
217                    }
218                };
219                let new_value =
220                    if delete_item { None } else { Some(&node.value) };
221                self.ext_map.view_update(
222                    self.key.1,
223                    new_value,
224                    Some(&old_value),
225                );
226
227                if update_key || delete_item {
228                    Delete((out, delete_item))
229                } else {
230                    Updated {
231                        update_weight,
232                        ret: Ok((out, None)),
233                    }
234                }
235            }
236        }
237    }
238
239    fn handle_delete(
240        deleted_node: Option<Box<Node<C>>>, (ret, delete_item): (T, bool),
241    ) -> Self::Ret {
242        let to_reinsert_node = if !delete_item {
243            Some(deleted_node.unwrap())
244        } else {
245            None
246        };
247        Ok((ret, to_reinsert_node))
248    }
249}