1use std::collections::HashMap;
8use std::sync::OnceLock;
9
10use yog_sync::Arc;
11
12use super::value::Value;
13
14const INDEXED_FROM: usize = 32;
17
18#[derive(Clone, Default)]
21pub struct Map {
22 entries: Vec<(Arc<str>, Value)>,
23 index: OnceLock<Box<KeyIndex>>,
26}
27
28#[derive(Clone, Default)]
30struct KeyIndex(HashMap<Arc<str>, usize>);
31
32impl std::fmt::Debug for Map {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 f.debug_tuple("Map").field(&self.entries).finish()
35 }
36}
37
38impl PartialEq for Map {
39 fn eq(&self, other: &Self) -> bool {
40 self.entries == other.entries
41 }
42}
43
44impl Map {
45 pub fn new() -> Self {
46 Self::default()
47 }
48
49 pub fn with_capacity(n: usize) -> Self {
50 Self {
51 entries: Vec::with_capacity(n),
52 index: OnceLock::new(),
53 }
54 }
55
56 fn position(&self, key: &str) -> Option<usize> {
59 if self.entries.len() < INDEXED_FROM {
60 return self.entries.iter().position(|(k, _)| &**k == key);
61 }
62 let index = self.index.get_or_init(|| {
63 Box::new(KeyIndex(
64 self.entries
65 .iter()
66 .enumerate()
67 .map(|(i, (k, _))| (k.clone(), i))
68 .collect(),
69 ))
70 });
71 index.0.get(key).copied()
72 }
73
74 fn index_mut(&mut self) -> Option<&mut HashMap<Arc<str>, usize>> {
76 self.index.get_mut().map(|b| &mut b.0)
77 }
78
79 pub fn get(&self, key: &str) -> Option<&Value> {
80 self.position(key).map(|i| &self.entries[i].1)
81 }
82
83 pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
84 let i = self.position(key)?;
85 Some(&mut self.entries[i].1)
86 }
87
88 pub fn value_at(&self, i: usize) -> Option<&Value> {
90 self.entries.get(i).map(|(_, v)| v)
91 }
92
93 pub fn index_of(&self, key: &str) -> Option<usize> {
95 self.position(key)
96 }
97
98 pub fn insert(&mut self, key: impl Into<String>, value: Value) -> Option<Value> {
100 let key = key.into();
101 if let Some(slot) = self.get_mut(&key) {
102 return Some(std::mem::replace(slot, value));
103 }
104 self.push_unchecked(key.into(), value);
105 None
106 }
107
108 pub(crate) fn push_unchecked(&mut self, key: Arc<str>, value: Value) {
110 let at = self.entries.len();
111 if let Some(index) = self.index_mut() {
112 index.insert(key.clone(), at);
113 }
114 self.entries.push((key, value));
115 }
116
117 pub fn remove(&mut self, key: &str) -> Option<Value> {
118 let i = self.position(key)?;
119 let (_, value) = self.entries.remove(i);
120 if let Some(index) = self.index_mut() {
121 index.remove(key);
122 for at in index.values_mut() {
123 if *at > i {
124 *at -= 1;
125 }
126 }
127 }
128 Some(value)
129 }
130
131 pub fn len(&self) -> usize {
132 self.entries.len()
133 }
134
135 pub fn is_empty(&self) -> bool {
136 self.entries.is_empty()
137 }
138
139 pub fn iter(&self) -> impl ExactSizeIterator<Item = (&str, &Value)> {
140 self.entries.iter().map(|(k, v)| (&**k, v))
141 }
142
143 pub fn keys(&self) -> impl ExactSizeIterator<Item = &str> {
144 self.entries.iter().map(|(k, _)| &**k)
145 }
146
147 pub fn values(&self) -> impl ExactSizeIterator<Item = &Value> {
148 self.entries.iter().map(|(_, v)| v)
149 }
150
151 pub fn retain(&mut self, mut keep: impl FnMut(&str, &Value) -> bool) {
154 self.entries.retain(|(k, v)| keep(k, v));
155 self.index = OnceLock::new();
156 }
157}
158
159impl IntoIterator for Map {
160 type Item = (String, Value);
161 type IntoIter = std::iter::Map<
162 std::vec::IntoIter<(Arc<str>, Value)>,
163 fn((Arc<str>, Value)) -> (String, Value),
164 >;
165 fn into_iter(self) -> Self::IntoIter {
166 self.entries.into_iter().map(|(k, v)| (k.to_string(), v))
167 }
168}
169
170impl<'a> IntoIterator for &'a Map {
171 type Item = (&'a str, &'a Value);
172 type IntoIter = std::iter::Map<
173 std::slice::Iter<'a, (Arc<str>, Value)>,
174 fn(&'a (Arc<str>, Value)) -> (&'a str, &'a Value),
175 >;
176 fn into_iter(self) -> Self::IntoIter {
177 self.entries.iter().map(|(k, v)| (&**k, v))
178 }
179}
180
181impl<K: Into<String>> FromIterator<(K, Value)> for Map {
182 fn from_iter<I: IntoIterator<Item = (K, Value)>>(iter: I) -> Self {
183 let mut map = Map::new();
184 for (k, v) in iter {
185 map.insert(k, v);
186 }
187 map
188 }
189}
190
191#[cfg(test)]
192mod tests;