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
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use primitives::Zero;
use std::{cmp::Ordering, ops::Add};
/// The weight type in a Treap. It is used to perform operations like
/// calculating sums or maximum values of an interval in logrithmic time over
/// treap.
pub trait ConsoliableWeight: Clone + Eq {
/// Create a default or 'zero' value for the weight. Consolidating with this
/// value should not change the other value.
fn empty() -> Self;
/// Combine two weights into a single one.
fn consolidate(a: &Self, b: &Self) -> Self;
/// Combine another weight into `self`. It allows for implementing more
/// efficient in-place consolidation.
fn accure(&mut self, other: &Self) {
*self = Self::consolidate(&*self, other);
}
}
impl<T: Add<Output = T> + Clone + Zero + Eq> ConsoliableWeight for T {
fn empty() -> Self { T::zero() }
fn consolidate(a: &Self, b: &Self) -> Self { a.clone() + b.clone() }
fn accure(&mut self, other: &Self) { *self = self.clone() + other.clone() }
}
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
/// Represents a dummy version of `ConsolidatableWeight`.
///
/// `NoWeight` is a unit struct that doesn't store any data. It is used as a
/// placeholder or a default implementation in scenarios where a weight
/// component is required by the interface but not actually needed for the
/// specific use case.
pub struct NoWeight;
impl ConsoliableWeight for NoWeight {
#[inline]
fn empty() -> Self { NoWeight }
#[inline]
fn consolidate(_: &Self, _: &Self) -> Self { NoWeight }
#[inline]
fn accure(&mut self, _other: &Self) {}
}
/// `TreapMap` is a struct which implements a treap which can be indexed by a
/// different key (type `SearchKey`). The associate type `SortKey` and
/// `SearchKey` defines how to order node in treap collaborately.
///
/// As the user only needs to provider the `SearchKey` in searching an element,
/// but the underlying treap is ordered by both `SortKey` and `SearchKey`.
/// `TreapMap` also maintains `KeyMng` to recover `SortKey` from `SearchKey`. It
/// could be a `HashMap`.
///
/// If `TreapMap` is indexed in the same key as the inside treap. The `SortKey`
/// can be deprecated to `()` and the `KeyMng` can be deprecated to a unit type.
/// Since it is compiled through static dispatch, unnecessary operations will be
/// optimized away.
pub trait TreapMapConfig: Sized {
/// The search key type in the TreapMap, supporting query/remove a node by
/// key.
type SearchKey;
/// The sort key in the treap.
type SortKey;
/// The stored value.
type Value: Clone;
/// The external map which can computing `SortKey` from `SearchKey`. If not
/// needed, it could be a unit type.
type ExtMap: KeyMngTrait<Self>;
/// The consolidable weight.
type Weight: ConsoliableWeight;
/// Compare the key.
fn next_node_dir(
me: (&Self::SortKey, &Self::SearchKey),
other: (&Self::SortKey, &Self::SearchKey),
) -> Option<Direction>;
}
/// Represents the possible directions in a binary tree search based on key
/// comparisons.
///
/// This enum is defined as part of the [`TreapMapConfig`] trait and is used to
/// determine the direction of traversal in a binary tree during key-based
/// searches.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Direction {
/// Indicates that the search should proceed to the left child of the
/// current node. This direction is typically chosen when the current
/// key is greater than the search key.
Left,
/// Indicates that the search should proceed to the right child of the
/// current node. This direction is usually selected when the current
/// key is less than the search key.
Right,
}
/// Searching in `Treap` requires sort key. This trait manages the relationship
/// among sort keys, search keys and values in a Treap. This is necessary when
/// the sort key is not directly derivable from the search key or is not a null
/// element.
pub trait KeyMngTrait<C: TreapMapConfig>: Default {
/// Invoked when a new key-value pair is changed in the Treap.
fn view_update(
&mut self, key: &C::SearchKey, value: Option<&C::Value>,
old_value: Option<&C::Value>,
);
/// Number of the keys
fn len(&self) -> usize;
/// Retrieve the sort key for a given search key.
/// Returns `None` if the search key is not in the treap.
fn get_sort_key(&self, key: &C::SearchKey) -> Option<C::SortKey>;
/// Generate the sort key from a key-value pair.
fn make_sort_key(&self, key: &C::SearchKey, value: &C::Value)
-> C::SortKey;
}
/// If `TreapMap` is indexed in the same key as the inside treap, it can be
/// configed in a simple way.
pub trait SharedKeyTreapMapConfig {
/// The search key in the TreapMap.
type Key: Ord;
/// The stored value.
type Value: Clone;
/// The consolidable weight.
type Weight: ConsoliableWeight;
}
impl<T: SharedKeyTreapMapConfig> TreapMapConfig for T {
type ExtMap = Counter;
type SearchKey = T::Key;
type SortKey = ();
type Value = T::Value;
type Weight = T::Weight;
#[inline]
fn next_node_dir(
(_, me): (&(), &Self::SearchKey), (_, other): (&(), &Self::SearchKey),
) -> Option<Direction> {
match me.cmp(other) {
Ordering::Less => Some(Direction::Left),
Ordering::Equal => None,
Ordering::Greater => Some(Direction::Right),
}
}
}
#[derive(Default)]
pub struct Counter(pub usize);
impl<C: TreapMapConfig<SortKey = ()>> KeyMngTrait<C> for Counter {
#[inline]
fn view_update(
&mut self, _key: &C::SearchKey, value: Option<&C::Value>,
old_value: Option<&C::Value>,
) {
if value.is_some() {
self.0 += 1;
}
if old_value.is_some() {
self.0 -= 1
}
}
fn len(&self) -> usize { self.0 }
fn get_sort_key(&self, _key: &C::SearchKey) -> Option<()> { Some(()) }
fn make_sort_key(
&self, _key: &C::SearchKey, _value: &C::Value,
) -> C::SortKey {
()
}
}
impl MallocSizeOf for Counter {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.0.size_of(ops)
}
}