1use std::collections::HashMap;
16use std::hash::{BuildHasher, Hasher};
17use std::sync::{Arc, OnceLock};
18
19use crate::Name;
20
21const LINEAR_LOOKUP_MAX: usize = 8;
24
25#[inline]
32pub(crate) fn process_hash_seed() -> u64 {
33 static SEED: OnceLock<u64> = OnceLock::new();
34 *SEED.get_or_init(|| {
35 std::collections::hash_map::RandomState::new().hash_one(0x5eed_u64) | 1
37 })
38}
39
40#[derive(Clone, Copy)]
45pub(crate) struct NameHasher(u64);
46
47#[derive(Clone, Copy)]
50pub(crate) struct NameState(u64);
51
52impl Default for NameState {
53 #[inline]
54 fn default() -> Self {
55 Self(0xcbf2_9ce4_8422_2325 ^ process_hash_seed())
56 }
57}
58
59impl BuildHasher for NameState {
60 type Hasher = NameHasher;
61
62 #[inline]
63 fn build_hasher(&self) -> NameHasher {
64 NameHasher(self.0)
65 }
66}
67
68impl Hasher for NameHasher {
69 #[inline]
70 fn write(&mut self, bytes: &[u8]) {
71 for &b in bytes {
72 self.0 = (self.0 ^ u64::from(b)).wrapping_mul(0x0000_0100_0000_01b3);
73 }
74 }
75
76 #[inline]
77 fn finish(&self) -> u64 {
78 self.0
79 }
80}
81
82#[derive(Clone, Default)]
87pub(crate) struct NameDict {
88 inner: Arc<Inner>,
89}
90
91#[derive(Clone, Default)]
92struct Inner {
93 names: Vec<Name>,
94 ids: HashMap<Name, u32, NameState>,
95}
96
97impl NameDict {
98 #[inline]
99 pub(crate) fn id_of(&self, name: &str) -> Option<u32> {
100 let inner = &*self.inner;
101 if inner.names.len() <= LINEAR_LOOKUP_MAX {
102 inner
103 .names
104 .iter()
105 .position(|n| n.as_str() == name)
106 .map(|i| i as u32)
107 } else {
108 inner.ids.get(name).copied()
109 }
110 }
111
112 pub(crate) fn id_or_insert(&mut self, name: &Name) -> u32 {
114 self.id_or_insert_with(name, || name.clone())
115 }
116
117 pub(crate) fn id_or_insert_with(&mut self, name: &str, make: impl FnOnce() -> Name) -> u32 {
123 if let Some(id) = self.id_of(name) {
124 return id;
125 }
126 let name = make();
127 let inner = Arc::make_mut(&mut self.inner);
128 let id = inner.names.len() as u32;
129 inner.names.push(name.clone());
130 inner.ids.insert(name, id);
131 id
132 }
133
134 #[cfg(test)]
136 pub(crate) fn id_or_insert_str(&mut self, name: &str) -> u32 {
137 match self.id_of(name) {
138 Some(id) => id,
139 None => self.id_or_insert(&Name::new(name)),
140 }
141 }
142
143 #[inline]
146 pub(crate) fn name(&self, id: u32) -> &Name {
147 &self.inner.names[id as usize]
148 }
149
150 pub(crate) fn len(&self) -> usize {
151 self.inner.names.len()
152 }
153
154 pub(crate) fn heap_bytes(&self) -> usize {
156 let inner = &*self.inner;
157 inner.names.capacity() * std::mem::size_of::<Name>()
158 + inner.ids.capacity() * (std::mem::size_of::<Name>() + std::mem::size_of::<u32>() + 1)
159 }
160}
161
162#[derive(Clone, Default)]
164pub(crate) struct Dicts {
165 pub(crate) labels: NameDict,
166 pub(crate) types: NameDict,
167 pub(crate) keys: NameDict,
168 pub(crate) values: ValueDict,
169}
170
171impl Dicts {
172 pub(crate) fn heap_bytes(&self) -> usize {
173 self.labels.heap_bytes()
174 + self.types.heap_bytes()
175 + self.keys.heap_bytes()
176 + self.values.heap_bytes()
177 }
178}
179
180const VALUE_MAX_LEN: usize = 32;
184const TRIAL_VALUES: u16 = 64;
188const TRIAL_DISTINCT: usize = 8;
189const KEY_MISSES: u16 = 64;
193const VALUES_MAX: usize = 4096;
196
197#[derive(Clone, Default)]
209pub(crate) struct ValueDict {
210 strings: NameDict,
211 keys: Arc<Vec<KeyValues>>,
213}
214
215#[derive(Clone)]
216enum KeyValues {
217 Trial {
219 seen: u16,
220 distinct: Vec<u64>,
221 },
222 Numbered {
224 misses: u16,
225 },
226 Stored,
227}
228
229#[derive(Debug, Clone, Default, PartialEq, Eq)]
233pub struct ValueDictionary {
234 pub strings: Vec<Arc<str>>,
236 pub keys: Vec<(Name, ValueKeyState)>,
238}
239
240#[derive(Debug, Clone, Copy, PartialEq, Eq)]
242pub enum ValueKeyState {
243 Numbered { misses: u16 },
245 Stored,
247}
248
249impl Default for KeyValues {
250 fn default() -> Self {
251 KeyValues::Trial {
252 seen: 0,
253 distinct: Vec::new(),
254 }
255 }
256}
257
258impl ValueDict {
259 #[inline]
262 pub(crate) fn number(&mut self, key: u32, value: &str) -> Option<u32> {
263 if value.len() > VALUE_MAX_LEN {
264 return None;
265 }
266 match self.keys.get(key as usize) {
267 Some(KeyValues::Stored) => None,
268 Some(KeyValues::Numbered { misses }) => {
269 if let Some(id) = self.strings.id_of(value) {
270 return Some(id);
271 }
272 if *misses >= KEY_MISSES || self.strings.len() >= VALUES_MAX {
273 return None;
274 }
275 let keys = Arc::make_mut(&mut self.keys);
276 if let KeyValues::Numbered { misses } = &mut keys[key as usize] {
277 *misses += 1;
278 }
279 Some(
280 self.strings
281 .id_or_insert_with(value, || crate::Name::from_arc(Arc::from(value))),
282 )
283 }
284 _ => {
285 self.observe(key, value);
286 None
287 }
288 }
289 }
290
291 fn observe(&mut self, key: u32, value: &str) {
294 let keys = Arc::make_mut(&mut self.keys);
295 if keys.len() <= key as usize {
296 keys.resize_with(key as usize + 1, KeyValues::default);
297 }
298 let state = &mut keys[key as usize];
299 let KeyValues::Trial { seen, distinct } = state else {
300 return;
301 };
302 let hash = NameState::default().hash_one(value);
303 if !distinct.contains(&hash) {
304 if distinct.len() == TRIAL_DISTINCT {
305 *state = KeyValues::Stored;
306 return;
307 }
308 distinct.push(hash);
309 }
310 *seen += 1;
311 if *seen == TRIAL_VALUES {
312 *state = KeyValues::Numbered { misses: 0 };
313 }
314 }
315
316 #[inline]
321 pub(crate) fn number_existing(&self, key: u32, value: &str) -> Option<u32> {
322 if value.len() > VALUE_MAX_LEN {
323 return None;
324 }
325 match self.keys.get(key as usize) {
326 Some(KeyValues::Numbered { .. }) => self.strings.id_of(value),
327 _ => None,
328 }
329 }
330
331 pub(crate) fn export(&self, key_name: impl Fn(u32) -> Name) -> ValueDictionary {
335 let strings = (0..self.strings.len() as u32)
336 .map(|id| Arc::from(self.string(id)))
337 .collect();
338 let keys = self
339 .keys
340 .iter()
341 .enumerate()
342 .filter_map(|(key, state)| {
343 let state = match state {
344 KeyValues::Trial { .. } => return None,
345 KeyValues::Numbered { misses } => ValueKeyState::Numbered { misses: *misses },
346 KeyValues::Stored => ValueKeyState::Stored,
347 };
348 Some((key_name(key as u32), state))
349 })
350 .collect();
351 ValueDictionary { strings, keys }
352 }
353
354 pub(crate) fn import(
359 &mut self,
360 dictionary: &ValueDictionary,
361 mut key_id: impl FnMut(&Name) -> u32,
362 ) -> Result<(), String> {
363 if dictionary.strings.len() > VALUES_MAX {
364 return Err("value dictionary holds too many strings".into());
365 }
366 for value in &dictionary.strings {
367 if value.len() > VALUE_MAX_LEN {
368 return Err("value dictionary holds a string too long to number".into());
369 }
370 let before = self.strings.len();
371 self.strings
372 .id_or_insert_with(value, || crate::Name::from_arc(Arc::clone(value)));
373 if self.strings.len() == before {
374 return Err("value dictionary repeats a string".into());
375 }
376 }
377 let keys = Arc::make_mut(&mut self.keys);
378 for (name, state) in &dictionary.keys {
379 let key = key_id(name) as usize;
380 if keys.len() <= key {
381 keys.resize_with(key + 1, KeyValues::default);
382 }
383 keys[key] = match *state {
384 ValueKeyState::Numbered { misses } => KeyValues::Numbered {
385 misses: misses.min(KEY_MISSES),
386 },
387 ValueKeyState::Stored => KeyValues::Stored,
388 };
389 }
390 Ok(())
391 }
392
393 #[inline]
395 pub(crate) fn string(&self, id: u32) -> &str {
396 self.strings.name(id).as_str()
397 }
398
399 pub(crate) fn heap_bytes(&self) -> usize {
400 let strings: usize = (0..self.strings.len() as u32)
402 .map(|id| 2 * std::mem::size_of::<usize>() + self.string(id).len())
403 .sum();
404 self.strings.heap_bytes()
405 + strings
406 + self.keys.capacity() * std::mem::size_of::<KeyValues>()
407 }
408}
409
410#[cfg(test)]
411mod tests {
412 use super::*;
413
414 #[test]
417 fn values_are_numbered_only_for_keys_that_repeat_a_few() {
418 let mut values = ValueDict::default();
419 for i in 0..TRIAL_VALUES {
420 assert_eq!(values.number(0, ["a", "b", "c"][i as usize % 3]), None);
421 assert_eq!(values.number(1, &format!("id-{i}")), None);
422 }
423 let a = values.number(0, "a").expect("key 0 is numbered");
424 assert_eq!(values.string(a), "a");
425 assert_eq!(values.number(0, "a"), Some(a));
426 assert_eq!(values.number(1, "id-1"), None);
427 assert_eq!(values.number(0, &"x".repeat(VALUE_MAX_LEN + 1)), None);
428 let added = (0..2 * KEY_MISSES)
431 .filter(|i| values.number(0, &format!("new-{i}")).is_some())
432 .count();
433 assert_eq!(added, KEY_MISSES as usize - 1);
434 assert_eq!(values.number(0, "a"), Some(a));
435 }
436
437 #[test]
438 fn names_are_numbered_once_in_both_lookup_modes() {
439 let mut dict = NameDict::default();
440 let names: Vec<Name> = (0..20).map(|i| Name::new(&format!("N{i}"))).collect();
441 for (i, name) in names.iter().enumerate() {
442 assert_eq!(dict.id_or_insert(name), i as u32);
443 for (j, earlier) in names[..=i].iter().enumerate() {
445 assert_eq!(dict.id_of(earlier), Some(j as u32));
446 assert_eq!(dict.name(j as u32), earlier);
447 }
448 }
449 assert_eq!(dict.id_or_insert(&names[3]), 3);
450 assert_eq!(dict.id_or_insert_str("N7"), 7);
451 assert_eq!(dict.id_or_insert_str("fresh"), 20);
452 assert_eq!(dict.id_of("missing"), None);
453 assert_eq!(dict.len(), 21);
454 }
455
456 #[test]
457 fn a_clone_shares_the_table_until_one_side_adds_a_name() {
458 let mut dict = NameDict::default();
459 dict.id_or_insert_str("A");
460 let mut copy = dict.clone();
461 assert_eq!(copy.id_or_insert_str("B"), 1);
462 assert_eq!(dict.id_of("B"), None);
463 assert_eq!(dict.id_or_insert_str("C"), 1);
464 assert_eq!(copy.name(1).as_str(), "B");
465 assert_eq!(dict.name(1).as_str(), "C");
466 }
467
468 #[test]
471 fn hashers_are_seeded_per_process() {
472 use std::hash::BuildHasher;
473 let unseeded = {
474 let mut h: u64 = 0xcbf2_9ce4_8422_2325;
475 for &b in b"name" {
476 h = (h ^ u64::from(b)).wrapping_mul(0x0000_0100_0000_01b3);
477 }
478 h
479 };
480 let mut hasher = NameState::default().build_hasher();
481 hasher.write(b"name");
482 assert_ne!(hasher.finish(), unseeded);
483 assert_eq!(
484 NameState::default().hash_one("name"),
485 NameState::default().hash_one("name")
486 );
487 }
488}