1use std::fmt::{Debug, Formatter};
2use std::hash::Hash;
3use std::ptr;
4use std::{collections::HashMap, mem::MaybeUninit};
5
6#[derive(Debug, Clone)]
13pub struct InlineHashMap<K, V, const N: usize>(InlineHashMapInner<K, V, N>);
14
15impl<K, V, const N: usize> InlineHashMap<K, V, N>
16where
17 K: Hash + Eq,
18{
19 pub(crate) fn new() -> Self {
21 Self(InlineHashMapInner::new())
22 }
23
24 #[inline]
26 pub fn len(&self) -> usize {
27 self.0.len()
28 }
29
30 #[inline]
32 pub fn is_empty(&self) -> bool {
33 self.len() == 0
34 }
35
36 #[inline]
42 pub fn iter(&self) -> Box<dyn Iterator<Item = (&K, &V)> + '_> {
43 self.0.iter()
44 }
45
46 #[inline]
48 pub fn to_map(&self) -> HashMap<K, V>
49 where
50 K: Clone + Hash + Eq,
51 V: Clone,
52 {
53 self.0.to_map()
54 }
55
56 #[inline]
58 pub fn is_heap_allocated(&self) -> bool {
59 self.0.is_heap_allocated()
60 }
61
62 #[inline]
67 pub fn insert(&mut self, key: K, value: V) {
68 self.0.insert(key, value)
69 }
70
71 #[inline]
73 pub fn remove(&mut self, key: &K) -> Option<V> {
74 self.0.remove(key)
75 }
76
77 #[inline]
79 pub fn get(&self, key: &K) -> Option<&V> {
80 self.0.get(key)
81 }
82
83 #[inline]
85 pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
86 self.0.get_mut(key)
87 }
88
89 #[inline]
91 pub fn contains_key(&self, key: &K) -> bool {
92 self.0.contains_key(key)
93 }
94}
95
96enum InlineHashMapInner<K, V, const N: usize> {
97 Inline {
98 len: usize,
99 data: [MaybeUninit<(K, V)>; N],
100 },
101 Heap(HashMap<K, V>),
102}
103
104impl<K, V, const N: usize> Debug for InlineHashMapInner<K, V, N>
105where
106 K: Debug,
107 V: Debug,
108{
109 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
110 write!(f, "InlineHashMap<{} items>", self.len())
111 }
112}
113
114impl<K, V, const N: usize> Clone for InlineHashMapInner<K, V, N>
115where
116 K: Clone,
117 V: Clone,
118{
119 fn clone(&self) -> Self {
120 match self {
121 Self::Heap(m) => Self::Heap(m.clone()),
122 Self::Inline { len, data } => {
123 let mut new_data = super::uninit_array();
124
125 let iter = data.iter().take(*len).enumerate();
126
127 for (idx, element) in iter {
128 let element = unsafe { &*element.as_ptr() };
129 let (key, value) = element.clone();
130 new_data[idx] = MaybeUninit::new((key, value));
131 }
132
133 Self::Inline {
134 len: *len,
135 data: new_data,
136 }
137 }
138 }
139 }
140}
141
142impl<K, V, const N: usize> Drop for InlineHashMapInner<K, V, N> {
143 fn drop(&mut self) {
144 if let Self::Inline { len, data } = self {
145 for element in data.iter_mut().take(*len) {
146 unsafe { ptr::drop_in_place(element.as_mut_ptr()) };
147 }
148 }
149 }
150}
151
152impl<K, V, const N: usize> InlineHashMapInner<K, V, N> {
153 #[inline]
154 pub(crate) fn new() -> Self {
155 Self::Inline {
156 len: 0,
157 data: super::uninit_array(),
158 }
159 }
160
161 #[inline]
162 pub fn iter(&self) -> Box<dyn Iterator<Item = (&K, &V)> + '_> {
163 match self {
164 Self::Inline { len, data } => {
165 Box::new(unsafe { InlineHashMapIterator::new(data, *len) })
166 }
167 Self::Heap(h) => Box::new(h.iter()),
168 }
169 }
170
171 #[inline]
172 fn to_map(&self) -> HashMap<K, V>
173 where
174 K: Clone + Hash + Eq,
175 V: Clone,
176 {
177 match &self {
178 InlineHashMapInner::Heap(m) => m.clone(),
179 InlineHashMapInner::Inline { len, data } => {
180 let mut new_data = HashMap::with_capacity(*len);
181
182 let iter = data.iter().take(*len);
183
184 for element in iter {
185 let element = unsafe { &*element.as_ptr() };
186 let (key, value) = element.clone();
187 new_data.insert(key, value);
188 }
189
190 new_data
191 }
192 }
193 }
194
195 #[inline]
196 pub fn len(&self) -> usize {
197 match self {
198 Self::Inline { len, .. } => *len,
199 Self::Heap(map) => map.len(),
200 }
201 }
202
203 #[inline]
204 pub fn is_heap_allocated(&self) -> bool {
205 matches!(self, Self::Heap(_))
206 }
207}
208
209impl<K: Eq + Hash, V, const N: usize> InlineHashMapInner<K, V, N> {
210 pub fn get<'m>(&'m self, k: &K) -> Option<&'m V> {
211 match self {
212 Self::Inline { data, len } => unsafe {
213 InlineHashMapIterator::new(data, *len)
214 .find(|(key, _)| key.eq(&k))
215 .map(|(_, value)| value)
216 },
217 Self::Heap(map) => map.get(k),
218 }
219 }
220
221 pub fn get_mut<'m>(&'m mut self, k: &K) -> Option<&'m mut V> {
222 match self {
223 Self::Inline { data, len } => unsafe {
224 InlineHashMapIteratorMut::new(data, *len)
225 .find(|(key, _)| key.eq(k))
226 .map(|(_, value)| value)
227 },
228 Self::Heap(map) => map.get_mut(k),
229 }
230 }
231
232 pub fn remove(&mut self, key: &K) -> Option<V> {
233 match self {
234 Self::Inline { data, len } => {
235 let idx = data
236 .iter()
237 .take(*len)
238 .map(|x| unsafe { &*x.as_ptr() })
239 .position(|x| &x.0 == key)?;
240
241 let element = unsafe {
242 std::mem::replace(data.get_unchecked_mut(idx), MaybeUninit::uninit())
243 };
244
245 data.swap(idx, *len - 1);
248 *len -= 1;
249
250 Some(unsafe { element.assume_init().1 })
251 }
252 Self::Heap(h) => h.remove(key),
253 }
254 }
255
256 pub fn insert(&mut self, k: K, v: V) {
257 let (array, len) = match self {
258 Self::Inline { data, len } => (data, len),
259 Self::Heap(map) => {
260 map.insert(k, v);
261 return;
262 }
263 };
264
265 for element in array.iter_mut().take(*len) {
266 let (key, value) = unsafe { element.assume_init_mut() };
268 if (*key).eq(&k) {
269 let old_value = std::mem::replace(value, v);
270 drop(old_value);
271 return;
272 }
273 }
274
275 if *len >= N {
276 let mut map = HashMap::with_capacity(*len + 1);
277
278 while *len != 0 {
281 *len -= 1;
282
283 let (key, value) = unsafe { array[*len].assume_init_read() };
286 map.insert(key, value);
287 }
288
289 map.insert(k, v);
290 *self = Self::Heap(map);
291 } else {
292 array[*len].write((k, v));
293 *len += 1;
294 }
295 }
296
297 pub fn contains_key(&self, k: &K) -> bool {
298 match self {
299 Self::Inline { data, len } => unsafe {
300 InlineHashMapIterator::new(data, *len).any(|(key, _)| key.eq(k))
301 },
302 Self::Heap(map) => map.contains_key(k),
303 }
304 }
305}
306
307pub struct InlineHashMapIteratorMut<'a, K, V> {
309 array: &'a mut [MaybeUninit<(K, V)>],
310 idx: usize,
311 len: usize,
312}
313
314impl<'a, K, V> InlineHashMapIteratorMut<'a, K, V> {
315 pub(crate) unsafe fn new(array: &'a mut [MaybeUninit<(K, V)>], len: usize) -> Self {
316 Self { array, idx: 0, len }
317 }
318}
319
320impl<'a, K, V> Iterator for InlineHashMapIteratorMut<'a, K, V> {
321 type Item = &'a mut (K, V);
322
323 fn next(&mut self) -> Option<Self::Item> {
324 if self.idx >= self.len {
325 return None;
326 }
327
328 let element = unsafe { &mut *self.array[self.idx].as_mut_ptr() };
329 self.idx += 1;
330
331 Some(element)
332 }
333}
334
335pub struct InlineHashMapIterator<'a, K, V> {
337 array: &'a [MaybeUninit<(K, V)>],
338 idx: usize,
339 len: usize,
340}
341
342impl<'a, K, V> InlineHashMapIterator<'a, K, V> {
343 pub(crate) unsafe fn new(array: &'a [MaybeUninit<(K, V)>], len: usize) -> Self {
344 Self { array, idx: 0, len }
345 }
346}
347
348impl<'a, K, V> Iterator for InlineHashMapIterator<'a, K, V> {
349 type Item = (&'a K, &'a V);
350
351 fn next(&mut self) -> Option<Self::Item> {
352 if self.idx >= self.len {
353 return None;
354 }
355
356 let (k, v) = unsafe { &*self.array[self.idx].as_ptr() };
357 self.idx += 1;
358
359 Some((k, v))
360 }
361}
362
363#[cfg(test)]
364mod tests {
365 use super::*;
366 use std::cell::Cell;
367 use std::hash::{Hash, Hasher};
368 use std::panic::{catch_unwind, AssertUnwindSafe};
369 use std::rc::Rc;
370
371 struct PanicHash(usize, Rc<Cell<Option<usize>>>);
372
373 impl PartialEq for PanicHash {
374 fn eq(&self, other: &Self) -> bool {
375 self.0 == other.0
376 }
377 }
378
379 impl Eq for PanicHash {}
380
381 impl Hash for PanicHash {
382 fn hash<H: Hasher>(&self, state: &mut H) {
383 assert_ne!(self.1.get(), Some(self.0));
384 self.0.hash(state);
385 }
386 }
387
388 #[test]
389 fn inlinehashmap_iter() {
390 let mut x = InlineHashMap::<String, usize, 5>::new();
391 x.insert("foo".into(), 3);
392 x.insert("bar".into(), 6);
393 x.insert("baz".into(), 7);
394 x.insert("qux".into(), 9);
395
396 let mut iter = x.iter();
397
398 assert_eq!(iter.next(), Some((&"foo".into(), &3usize)));
403 assert_eq!(iter.next(), Some((&"bar".into(), &6usize)));
404 assert_eq!(iter.next(), Some((&"baz".into(), &7usize)));
405 assert_eq!(iter.next(), Some((&"qux".into(), &9usize)));
406 }
407
408 #[test]
409 fn inlinehashmap_growth_hash_panic_is_unwind_safe() {
410 let panic_on = Rc::new(Cell::new(None));
411 let key = |value| PanicHash(value, Rc::clone(&panic_on));
412 let mut map = InlineHashMap::<PanicHash, usize, 3>::new();
413 for value in 1..=3 {
414 map.insert(key(value), value);
415 }
416
417 panic_on.set(Some(2));
418 assert!(catch_unwind(AssertUnwindSafe(|| {
419 map.insert(key(4), 4);
420 }))
421 .is_err());
422 assert!(!map.is_heap_allocated());
423 assert!(map.iter().map(|(key, _)| key.0).eq([1]));
424
425 panic_on.set(None);
426 map.insert(key(5), 5);
427 assert_eq!(map.len(), 2);
428 }
429
430 #[test]
431 fn inlinehashmap_remove() {
432 let mut x = InlineHashMap::<usize, usize, 4>::new();
433 x.insert(789, 1336);
434 assert_eq!(x.len(), 1);
435 assert_eq!(x.get(&789), Some(&1336));
436 assert_eq!(x.remove(&789), Some(1336));
437 assert_eq!(x.len(), 0);
438
439 assert_eq!(x.remove(&789), None);
440
441 for i in 0..4 {
442 x.insert(i, i * 2);
443 }
444
445 assert!(!x.is_heap_allocated());
446 assert_eq!(x.len(), 4);
447
448 assert_eq!(x.remove(&2), Some(4));
449 assert_eq!(x.len(), 3);
450
451 assert_eq!(x.remove(&3), Some(6));
452 assert_eq!(x.len(), 2);
453
454 assert_eq!(x.remove(&1), Some(2));
455 assert_eq!(x.len(), 1);
456
457 assert_eq!(x.remove(&0), Some(0));
458 assert_eq!(x.len(), 0);
459 assert!(!x.is_heap_allocated());
460
461 for i in 0..8 {
463 x.insert(i, i * 2);
464 }
465 assert!(x.is_heap_allocated());
466 assert_eq!(x.len(), 8);
467
468 assert_eq!(x.remove(&7), Some(14));
469 assert_eq!(x.remove(&0), Some(0));
470 }
471
472 #[test]
473 fn inlinehashmap_remove_heap() {
474 let mut x = InlineHashMap::<usize, String, 4>::new();
475 x.insert(42, "test".into());
476 assert_eq!(x.len(), 1);
477 assert_eq!(x.remove(&42), Some("test".into()));
478 assert_eq!(x.len(), 0);
479 }
480
481 #[test]
482 fn inlinehashmap_clone() {
483 let mut x = InlineHashMapInner::<usize, usize, 4>::new();
484
485 for i in 0..10 {
486 x.insert(i, i * 2);
487 }
488
489 let x = x.clone();
490 assert_eq!(x.len(), 10);
491 assert!(x.is_heap_allocated());
492 assert_eq!(x.get(&9), Some(&18));
493 }
494
495 #[test]
496 fn inlinehashmap_to_map_stack() {
497 let mut x = InlineHashMapInner::<usize, usize, 4>::new();
498
499 for i in 0..4 {
500 x.insert(i, i * 2);
501 }
502
503 assert!(!x.is_heap_allocated());
504 assert_eq!(x.len(), 4);
505
506 let xx = x.to_map();
507 assert_eq!(xx.get(&0), Some(&0));
508 assert_eq!(xx.get(&1), Some(&2));
509 assert_eq!(xx.get(&2), Some(&4));
510 assert_eq!(xx.get(&3), Some(&6));
511 assert_eq!(xx.len(), 4);
512
513 x.insert(42, 1337);
514 assert!(x.is_heap_allocated());
515 assert_eq!(x.len(), 5);
516 assert_eq!(x.get(&42), Some(&1337));
517
518 let xx = x.to_map();
519 assert_eq!(xx.get(&0), Some(&0));
520 assert_eq!(xx.get(&42), Some(&1337));
521 assert_eq!(xx.len(), 5);
522 }
523
524 #[test]
525 fn inlinehashmap_to_map_heap() {
526 let mut x = InlineHashMapInner::<usize, String, 4>::new();
527
528 for i in 0..4 {
529 x.insert(i, i.to_string());
530 }
531
532 assert!(!x.is_heap_allocated());
533 assert_eq!(x.len(), 4);
534
535 let xx = x.to_map();
536 assert_eq!(&*xx[&0], "0");
537 assert_eq!(&*xx[&1], "1");
538 assert_eq!(&*xx[&2], "2");
539 assert_eq!(&*xx[&3], "3");
540 assert_eq!(xx.len(), 4);
541
542 x.insert(42, "1337".into());
543 assert!(x.is_heap_allocated());
544 assert_eq!(x.len(), 5);
545 assert_eq!(x.get(&42).map(|x| &**x), Some("1337"));
546
547 let xx = x.to_map();
548 assert_eq!(&*xx[&0], "0");
549 assert_eq!(&*xx[&42], "1337");
550 assert_eq!(xx.len(), 5);
551 }
552
553 #[test]
554 fn inlinehashmap_drop_stack() {
555 let mut x = InlineHashMapInner::<usize, String, 4>::new();
556
557 for i in 0..3 {
558 x.insert(i, i.to_string());
559 }
560
561 assert_eq!(x.len(), 3);
562 assert!(!x.is_heap_allocated());
563 }
564
565 #[test]
566 fn inlinehashmap_drop_heap() {
567 let mut x = InlineHashMapInner::<usize, String, 4>::new();
568
569 for i in 0..16 {
570 x.insert(i, i.to_string());
571 }
572
573 assert_eq!(x.len(), 16);
574 assert!(x.is_heap_allocated());
575 }
576
577 #[test]
578 fn inlinehashmap() {
579 let mut x = InlineHashMapInner::<&'static str, usize, 4>::new();
580 assert_eq!(x.len(), 0);
581 assert_eq!(x.get(&"hi"), None);
582 assert!(!x.is_heap_allocated());
583
584 x.insert("foo", 1337);
585 x.insert("foo", 1);
586 assert_eq!(x.len(), 1);
587 assert_eq!(x.get(&"foo"), Some(&1));
588 assert!(!x.is_heap_allocated());
589
590 x.insert("foo2", 2);
591 x.insert("foo3", 3);
592 x.insert("foo4", 4);
593
594 x.insert("foo", 2);
595 assert_eq!(x.len(), 4);
596 assert_eq!(x.get(&"foo"), Some(&2));
597 assert!(!x.is_heap_allocated());
598
599 x.insert("foo5", 5);
600 x.insert("foo", 3);
601 assert_eq!(x.len(), 5);
602 assert_eq!(x.get(&"foo"), Some(&3));
603 assert!(x.is_heap_allocated());
604
605 x.insert("foo6", 6);
606 x.insert("foo7", 7);
607 x.insert("foo8", 8);
608 x.insert("foo9", 9);
609 x.insert("foo10", 10);
610 x.insert("foo11", 11);
611 }
612}