Skip to main content

substrate_data/model/map/
map.rs

1//! [`Map`]: entries in file order, indexed once it's big.
2
3use std::collections::HashMap;
4use std::sync::OnceLock;
5
6use crate::model::quick_hash::QuickBuild;
7use crate::model::value::Value;
8use crate::sync::Arc;
9
10/// How many keys a map has before a lookup indexes them: below it a scan
11/// beats hashing (`benches/data.rs`'s maps, small records).
12pub(super) const INDEXED_FROM: usize = 32;
13
14/// Keys are shared: a decoded document allocates each distinct key once,
15/// however many maps have it.
16#[derive(Clone, Default)]
17pub struct Map {
18    entries: Vec<(Arc<str>, Value)>,
19    /// Each key's position, once a lookup in a big map asked for it;
20    /// boxed, so a map (and so every [`Value`]) is no bigger for it.
21    index: OnceLock<Box<KeyIndex>>,
22}
23
24/// Each key's position among a map's entries.
25#[derive(Clone, Default)]
26struct KeyIndex(HashMap<Arc<str>, usize, QuickBuild>);
27
28impl std::fmt::Debug for Map {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        f.debug_tuple("Map").field(&self.entries).finish()
31    }
32}
33
34impl PartialEq for Map {
35    fn eq(&self, other: &Self) -> bool {
36        self.entries == other.entries
37    }
38}
39
40impl Map {
41    /// An empty map.
42    #[must_use]
43    pub fn new() -> Self {
44        Self::default()
45    }
46
47    /// An empty map with room for `n` entries.
48    #[must_use]
49    pub fn with_capacity(n: usize) -> Self {
50        Self {
51            entries: Vec::with_capacity(n),
52            index: OnceLock::new(),
53        }
54    }
55
56    /// A map of `entries` already known to have distinct keys — for the
57    /// parser, which checked each as it read it.
58    pub(crate) fn from_entries(entries: Vec<(Arc<str>, Value)>) -> Self {
59        Self {
60            entries,
61            index: OnceLock::new(),
62        }
63    }
64
65    /// Where `key` is: by the index in a big map (made now if it isn't
66    /// yet), by a scan in a small one.
67    fn position(&self, key: &str) -> Option<usize> {
68        if self.entries.len() < INDEXED_FROM {
69            return self.entries.iter().position(|(k, _)| &**k == key);
70        }
71        let index = self.index.get_or_init(|| {
72            Box::new(KeyIndex(
73                self.entries
74                    .iter()
75                    .enumerate()
76                    .map(|(i, (k, _))| (k.clone(), i))
77                    .collect(),
78            ))
79        });
80        index.0.get(key).copied()
81    }
82
83    /// The index, if one's made: what a change keeps current.
84    fn index_mut(&mut self) -> Option<&mut HashMap<Arc<str>, usize, QuickBuild>> {
85        self.index.get_mut().map(|b| &mut b.0)
86    }
87
88    /// The value of `key`.
89    pub fn get(&self, key: &str) -> Option<&Value> {
90        self.position(key).map(|i| &self.entries[i].1)
91    }
92
93    /// The value of `key`, to change.
94    pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
95        let i = self.position(key)?;
96        Some(&mut self.entries[i].1)
97    }
98
99    /// The value of the `i`-th entry.
100    pub fn value_at(&self, i: usize) -> Option<&Value> {
101        self.entries.get(i).map(|(_, v)| v)
102    }
103
104    /// The position of `key` among the entries.
105    pub fn index_of(&self, key: &str) -> Option<usize> {
106        self.position(key)
107    }
108
109    /// Sets `key`, in place if it's there, else at the end; returns the old value.
110    pub fn insert(&mut self, key: impl Into<String>, value: Value) -> Option<Value> {
111        let key = key.into();
112        if let Some(slot) = self.get_mut(&key) {
113            return Some(std::mem::replace(slot, value));
114        }
115        self.push_unchecked(key.into(), value);
116        None
117    }
118
119    /// Appends without checking for the key — for decoders that already did.
120    pub(crate) fn push_unchecked(&mut self, key: Arc<str>, value: Value) {
121        let at = self.entries.len();
122        if let Some(index) = self.index_mut() {
123            index.insert(key.clone(), at);
124        }
125        self.entries.push((key, value));
126    }
127
128    /// Takes `key`'s entry out: its value, the others keeping their order.
129    pub fn remove(&mut self, key: &str) -> Option<Value> {
130        let i = self.position(key)?;
131        let (_, value) = self.entries.remove(i);
132        if let Some(index) = self.index_mut() {
133            index.remove(key);
134            for at in index.values_mut() {
135                if *at > i {
136                    *at -= 1;
137                }
138            }
139        }
140        Some(value)
141    }
142
143    /// How many entries.
144    pub fn len(&self) -> usize {
145        self.entries.len()
146    }
147
148    /// Whether it has no entries.
149    pub fn is_empty(&self) -> bool {
150        self.entries.is_empty()
151    }
152
153    /// The entries, in order.
154    pub fn iter(&self) -> impl ExactSizeIterator<Item = (&str, &Value)> {
155        self.entries.iter().map(|(k, v)| (&**k, v))
156    }
157
158    /// The keys, in order.
159    pub fn keys(&self) -> impl ExactSizeIterator<Item = &str> + Clone {
160        self.entries.iter().map(|(k, _)| &**k)
161    }
162
163    /// The values, in order.
164    pub fn values(&self) -> impl ExactSizeIterator<Item = &Value> {
165        self.entries.iter().map(|(_, v)| v)
166    }
167
168    /// Keeps the entries `keep` says to, in one pass; the index made again
169    /// when it's next needed.
170    pub fn retain(&mut self, mut keep: impl FnMut(&str, &Value) -> bool) {
171        self.entries.retain(|(k, v)| keep(k, v));
172        self.index = OnceLock::new();
173    }
174}
175
176impl IntoIterator for Map {
177    type Item = (String, Value);
178    type IntoIter = std::iter::Map<
179        std::vec::IntoIter<(Arc<str>, Value)>,
180        fn((Arc<str>, Value)) -> (String, Value),
181    >;
182    fn into_iter(self) -> Self::IntoIter {
183        self.entries.into_iter().map(|(k, v)| (k.to_string(), v))
184    }
185}
186
187impl<'a> IntoIterator for &'a Map {
188    type Item = (&'a str, &'a Value);
189    type IntoIter = std::iter::Map<
190        std::slice::Iter<'a, (Arc<str>, Value)>,
191        fn(&'a (Arc<str>, Value)) -> (&'a str, &'a Value),
192    >;
193    fn into_iter(self) -> Self::IntoIter {
194        self.entries.iter().map(|(k, v)| (&**k, v))
195    }
196}
197
198impl<K: Into<String>> FromIterator<(K, Value)> for Map {
199    fn from_iter<I: IntoIterator<Item = (K, Value)>>(iter: I) -> Self {
200        let mut map = Map::new();
201        for (k, v) in iter {
202            map.insert(k, v);
203        }
204        map
205    }
206}