Skip to content

Commit 7444a40

Browse files
committed
feat: add deduplication and fast removal to vecmap
1 parent 92e5084 commit 7444a40

1 file changed

Lines changed: 39 additions & 3 deletions

File tree

libdd-trace-utils/src/span/vec_map.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//! involved. Fetching and removing a value is, on the other hand, linear time in the size of the
88
//! map.
99
10+
use crate::span::SpanText;
1011
use serde::ser::{Serialize, Serializer};
1112
use std::borrow::Borrow;
1213
use std::collections::HashMap;
@@ -33,6 +34,15 @@ use std::hash::Hash;
3334
#[derive(Clone, Debug, PartialEq, Default)]
3435
pub struct VecMap<K, V>(Vec<(K, V)>);
3536

37+
/// Values that can be replaced by a special tombstone value that makes them to be ignored later in
38+
/// the pipeline. This makes their removal from a [VecMap] a bit more efficient (still a linear
39+
/// scan, but no shifting involved). Technically equivalent to [Default], but of course having a
40+
/// default value doesn't mean it's suitable as a `None`-like value (typically for a `f64` metrics,
41+
/// being `0` and being absent are entirely different)
42+
pub trait Tombstone {
43+
fn tombstone() -> Self;
44+
}
45+
3646
impl<K, V> VecMap<K, V> {
3747
#[must_use]
3848
#[inline]
@@ -87,9 +97,9 @@ impl<K, V> VecMap<K, V> {
8797
}
8898

8999
/// Remove all entries matching this key from the map. This method uses [Vec::retain], and is
90-
/// thus potentially costly (like any removal in a vector-like datastructure).
91-
// Note: we might implement a tombstone or option-based deletion later, if removal is a bit too
92-
// costly.
100+
/// thus potentially costly (like any removal in a vector-like datastructure). When applicable,
101+
/// prefer [Self::remove_unset], which replaces the entry with a special value (typically an
102+
/// empty string) that is treated as similar to being empty.
93103
#[inline]
94104
pub fn remove_slow<Q>(&mut self, key: &Q)
95105
where
@@ -128,6 +138,19 @@ impl<K, V> VecMap<K, V> {
128138
}
129139
}
130140

141+
impl<K, V: Tombstone> VecMap<K, V> {
142+
#[inline]
143+
pub fn remove_unset<Q>(&mut self, key: &Q)
144+
where
145+
K: Borrow<Q>,
146+
Q: ?Sized + PartialEq,
147+
{
148+
self.iter_mut()
149+
.filter_map(|(k, v)| ((*k).borrow() == key).then_some(v))
150+
.for_each(|v| *v = V::tombstone())
151+
}
152+
}
153+
131154
impl<K, V> From<Vec<(K, V)>> for VecMap<K, V> {
132155
fn from(vec: Vec<(K, V)>) -> Self {
133156
VecMap(vec)
@@ -188,6 +211,12 @@ impl<K: Serialize + Eq + Hash, V: Serialize> Serialize for VecMap<K, V> {
188211
}
189212
}
190213

214+
impl<T: SpanText> Tombstone for T {
215+
fn tombstone() -> Self {
216+
Self::default()
217+
}
218+
}
219+
191220
#[macro_export]
192221
macro_rules! vec_map {
193222
() => { $crate::span::vec_map::VecMap::new() };
@@ -272,4 +301,11 @@ mod tests {
272301
assert_eq!(obj.get("a").unwrap(), 3);
273302
assert_eq!(obj.get("b").unwrap(), 2);
274303
}
304+
305+
#[test]
306+
fn macro_construction() {
307+
let m: VecMap<&str, i32> = vec_map![("a", 1), ("b", 2)];
308+
assert_eq!(m.get("a"), Some(&1));
309+
assert_eq!(m.get("b"), Some(&2));
310+
}
275311
}

0 commit comments

Comments
 (0)