1use core::{
2 hash::{BuildHasher, Hash},
3 iter::FusedIterator,
4 mem::{self, transmute, ManuallyDrop, MaybeUninit},
5 ptr::NonNull,
6};
7
8use crate::{
9 raw::{
10 h2,
11 util::{
12 equivalent_key, likely, make_hash, unlikely, Bucket, InsertSlot, SizedTypeProperties,
13 },
14 Group,
15 },
16 Equivalent,
17};
18
19enum HashValue<F> {
21 Pending(F),
22 Computed(u64),
23}
24
25impl<F: FnOnce() -> u64> HashValue<F> {
26 #[inline]
27 fn new(f: F) -> Self {
28 Self::Pending(f)
29 }
30
31 #[inline]
32 fn get(&mut self) -> u64 {
33 match self {
34 Self::Pending(_) => {
35 let f = match core::mem::replace(self, Self::Computed(0)) {
36 Self::Pending(f) => f,
37 Self::Computed(_) => unsafe { core::hint::unreachable_unchecked() },
38 };
39 let hash = f();
40 *self = Self::Computed(hash);
41 hash
42 }
43 Self::Computed(hash) => *hash,
44 }
45 }
46}
47
48#[derive(Clone)]
49pub struct Inline<const N: usize, K, V, SH, SI, const LINEAR_THRESHOLD: usize = { Group::WIDTH }> {
50 raw: RawInline<N, (K, V), LINEAR_THRESHOLD>,
51 inline_hasher: Option<SI>,
53 heap_hasher: Option<SH>,
54}
55
56struct RawInline<const N: usize, T, const LINEAR_THRESHOLD: usize = { Group::WIDTH }> {
57 aligned_groups: AlignedGroups<N>,
58 len: usize,
59 data: [MaybeUninit<T>; N],
60}
61
62impl<const N: usize, T: Clone, const LINEAR_THRESHOLD: usize> Clone
63 for RawInline<N, T, LINEAR_THRESHOLD>
64{
65 #[inline]
66 fn clone(&self) -> Self {
67 struct DropGuard<'a, T> {
68 data: &'a mut [MaybeUninit<T>],
69 len: usize,
70 }
71
72 impl<'a, T> Drop for DropGuard<'a, T> {
73 fn drop(&mut self) {
74 for i in 0..self.len {
76 unsafe {
77 core::ptr::drop_in_place(self.data[i].as_mut_ptr());
78 }
79 }
80 }
81 }
82
83 let mut aligned_groups: AlignedGroups<N> = unsafe { MaybeUninit::uninit().assume_init() };
85 let mut data: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
86
87 let mut guard = DropGuard {
88 data: &mut data,
89 len: 0,
90 };
91
92 for (i, group) in self.aligned_groups.groups.iter().take(self.len).enumerate() {
94 aligned_groups.groups[i] = *group;
95 guard.data[i] = MaybeUninit::new(unsafe { self.data[i].assume_init_ref().clone() });
97 guard.len += 1;
98 }
99
100 mem::forget(guard);
101
102 Self {
103 aligned_groups,
104 len: self.len,
105 data,
106 }
107 }
108}
109
110#[repr(C)]
111#[derive(Clone, Copy)]
112pub(crate) struct AlignedGroups<const N: usize> {
113 groups: [MaybeUninit<u8>; N],
114 _align: [Group; 0],
115}
116
117impl<const N: usize> AlignedGroups<N> {
118 #[inline]
119 unsafe fn ctrl(&self, index: usize) -> *mut u8 {
120 (self.groups.as_ptr() as *const u8).add(index).cast_mut()
121 }
122}
123
124impl<const N: usize, T, const LINEAR_THRESHOLD: usize> Drop for RawInline<N, T, LINEAR_THRESHOLD> {
125 #[inline]
126 fn drop(&mut self) {
127 unsafe { self.drop_elements() }
128 }
129}
130
131impl<const N: usize, T, const LINEAR_THRESHOLD: usize> RawInline<N, T, LINEAR_THRESHOLD> {
132 const MIN_LINEAR_LEN: usize = if LINEAR_THRESHOLD > 2 {
135 LINEAR_THRESHOLD
136 } else {
137 2
138 };
139
140 #[inline]
141 unsafe fn drop_elements(&mut self) {
142 if T::NEEDS_DROP {
143 for i in 0..self.len {
145 core::ptr::drop_in_place(self.data[i].as_mut_ptr());
146 }
147 }
148 }
149
150 #[inline]
153 fn find<F: FnOnce() -> u64>(
154 &self,
155 hash: &mut HashValue<F>,
156 mut eq: impl FnMut(&T) -> bool,
157 ) -> Option<Bucket<T>> {
158 if N < LINEAR_THRESHOLD || self.len < Self::MIN_LINEAR_LEN {
159 for i in 0..self.len {
161 if eq(unsafe { self.data.get_unchecked(i).assume_init_ref() }) {
162 return Some(unsafe { self.bucket(i) });
163 }
164 }
165 None
166 } else {
167 unsafe {
169 let h2_hash = h2(hash.get());
170 let full_groups = self.len / Group::WIDTH;
171 let mut probe_pos = 0;
172
173 for _ in 0..full_groups {
174 let group = Group::load(self.aligned_groups.ctrl(probe_pos));
175 for bit in group.match_byte(h2_hash) {
176 let index = probe_pos + bit;
177 let item: &T = self.data.get_unchecked(index).assume_init_ref();
178 if likely(eq(item)) {
179 return Some(self.bucket(index));
180 }
181 }
182 probe_pos += Group::WIDTH;
183 }
184
185 let tail_len = self.len % Group::WIDTH;
186 if tail_len > 0 {
187 let group = Group::load(self.aligned_groups.ctrl(probe_pos));
188 for bit in group.match_byte(h2_hash).and(Group::LOWEST_MASK[tail_len]) {
189 let index = probe_pos + bit;
190 let item: &T = self.data.get_unchecked(index).assume_init_ref();
191 if likely(eq(item)) {
192 return Some(self.bucket(index));
193 }
194 }
195 }
196 None
197 }
198 }
199 }
200
201 #[inline]
204 unsafe fn insert_in_slot(&mut self, hash: u64, slot: InsertSlot, value: T) -> Bucket<T> {
205 *self.aligned_groups.ctrl(slot.index) = h2(hash);
207 self.len += 1;
208 let bucket = self.bucket(slot.index);
209 bucket.write(value);
210 bucket
211 }
212
213 #[inline]
215 fn remove_entry<F: FnOnce() -> u64>(
216 &mut self,
217 hash: &mut HashValue<F>,
218 eq: impl FnMut(&T) -> bool,
219 ) -> Option<T> {
220 match self.find(hash, eq) {
221 Some(bucket) => Some(unsafe { self.remove(bucket).0 }),
222 None => None,
223 }
224 }
225
226 #[inline]
229 #[allow(clippy::needless_pass_by_value)]
230 unsafe fn remove(&mut self, item: Bucket<T>) -> (T, InsertSlot) {
231 let index = self.bucket_index(&item);
232 let value = item.read();
234 self.erase(index);
235 (value, InsertSlot { index })
236 }
237
238 #[inline]
240 unsafe fn bucket_index(&self, bucket: &Bucket<T>) -> usize {
241 bucket.to_base_index(NonNull::new_unchecked(self.data.as_ptr() as _))
242 }
243
244 #[inline]
248 unsafe fn erase(&mut self, index: usize) {
249 let last = self.len - 1;
250 if index != last {
251 core::ptr::copy_nonoverlapping(
252 self.data[last].as_ptr(),
253 self.data[index].as_mut_ptr(),
254 1,
255 );
256 self.aligned_groups.groups[index] = self.aligned_groups.groups[last];
257 }
258 self.len -= 1;
259 }
260
261 #[inline]
263 unsafe fn bucket(&self, index: usize) -> Bucket<T> {
264 Bucket::from_base_index(
265 NonNull::new_unchecked(transmute::<*mut MaybeUninit<T>, *mut T>(
266 self.data.as_ptr().cast_mut(),
267 )),
268 index,
269 )
270 }
271}
272
273impl<const N: usize, K, V, const LINEAR_THRESHOLD: usize> RawInline<N, (K, V), LINEAR_THRESHOLD> {
274 #[inline]
277 fn retain<F>(&mut self, f: &mut F)
278 where
279 F: FnMut(&K, &mut V) -> bool,
280 {
281 let mut i = 0;
282 while i < self.len {
283 let (k, v) = unsafe { self.data[i].assume_init_mut() };
284 if f(k, v) {
285 i += 1;
286 } else {
287 unsafe {
288 core::ptr::drop_in_place(self.data[i].as_mut_ptr());
289 self.erase(i);
290 }
291 }
293 }
294 }
295}
296
297pub struct Iter<'a, const N: usize, K, V> {
299 data: &'a [MaybeUninit<(K, V)>; N],
300 index: usize,
301 len: usize,
302}
303
304impl<'a, const N: usize, K, V> Iterator for Iter<'a, N, K, V> {
305 type Item = (&'a K, &'a V);
306
307 #[inline]
308 fn next(&mut self) -> Option<Self::Item> {
309 if self.index < self.len {
310 let kv = unsafe { self.data[self.index].assume_init_ref() };
311 self.index += 1;
312 Some((&kv.0, &kv.1))
313 } else {
314 None
315 }
316 }
317
318 #[inline]
319 fn size_hint(&self) -> (usize, Option<usize>) {
320 let remaining = self.len - self.index;
321 (remaining, Some(remaining))
322 }
323}
324
325impl<'a, const N: usize, K, V> ExactSizeIterator for Iter<'a, N, K, V> {
326 #[inline]
327 fn len(&self) -> usize {
328 self.len - self.index
329 }
330}
331
332impl<'a, const N: usize, K, V> FusedIterator for Iter<'a, N, K, V> {}
333
334impl<'a, const N: usize, K, V> Clone for Iter<'a, N, K, V> {
335 #[inline]
336 fn clone(&self) -> Self {
337 Self {
338 data: self.data,
339 index: self.index,
340 len: self.len,
341 }
342 }
343}
344
345pub struct IntoIter<const N: usize, K, V> {
347 data: [MaybeUninit<(K, V)>; N],
348 index: usize,
349 len: usize,
350}
351
352impl<const N: usize, K, V> Iterator for IntoIter<N, K, V> {
353 type Item = (K, V);
354
355 #[inline]
356 fn next(&mut self) -> Option<Self::Item> {
357 if self.index < self.len {
358 let kv = unsafe { self.data[self.index].as_ptr().read() };
359 self.index += 1;
360 Some(kv)
361 } else {
362 None
363 }
364 }
365
366 #[inline]
367 fn size_hint(&self) -> (usize, Option<usize>) {
368 let remaining = self.len - self.index;
369 (remaining, Some(remaining))
370 }
371}
372
373impl<const N: usize, K, V> ExactSizeIterator for IntoIter<N, K, V> {
374 #[inline]
375 fn len(&self) -> usize {
376 self.len - self.index
377 }
378}
379
380impl<const N: usize, K, V> FusedIterator for IntoIter<N, K, V> {}
381
382impl<const N: usize, K, V> Drop for IntoIter<N, K, V> {
383 fn drop(&mut self) {
384 for i in self.index..self.len {
386 unsafe { core::ptr::drop_in_place(self.data[i].as_mut_ptr()) };
387 }
388 }
389}
390
391impl<const N: usize, K, V, SH, SI, const LINEAR_THRESHOLD: usize> IntoIterator
392 for Inline<N, K, V, SH, SI, LINEAR_THRESHOLD>
393{
394 type Item = (K, V);
395 type IntoIter = IntoIter<N, K, V>;
396
397 #[inline]
398 fn into_iter(self) -> Self::IntoIter {
399 let mut this = ManuallyDrop::new(self);
401 let data = unsafe { core::ptr::read(&this.raw.data) };
402 let len = this.raw.len;
403
404 unsafe {
406 core::ptr::drop_in_place(&mut this.inline_hasher);
407 core::ptr::drop_in_place(&mut this.heap_hasher);
408 }
409
410 IntoIter {
411 data,
412 index: 0,
413 len,
414 }
415 }
416}
417
418impl<const N: usize, K, V, SH, SI, const LINEAR_THRESHOLD: usize>
419 Inline<N, K, V, SH, SI, LINEAR_THRESHOLD>
420{
421 #[inline]
422 pub(crate) fn iter(&self) -> Iter<'_, N, K, V> {
423 Iter {
424 data: &self.raw.data,
425 index: 0,
426 len: self.raw.len,
427 }
428 }
429
430 const VALIDNESS_CHECK: () = assert!(N != 0, "SmallMap cannot be initialized with zero size.");
433
434 #[inline]
435 pub(crate) const fn new(hash_builder: SI, heap_hasher: SH) -> Self {
436 #[allow(clippy::let_unit_value)]
438 let _ = Self::VALIDNESS_CHECK;
439
440 Self {
441 raw: RawInline {
442 aligned_groups: unsafe { MaybeUninit::uninit().assume_init() },
444 len: 0,
445 data: unsafe { MaybeUninit::uninit().assume_init() },
446 },
447 inline_hasher: Some(hash_builder),
448 heap_hasher: Some(heap_hasher),
449 }
450 }
451
452 #[inline]
453 pub(crate) fn is_empty(&self) -> bool {
454 self.raw.len == 0
455 }
456
457 #[inline]
458 pub(crate) fn is_full(&self) -> bool {
459 self.raw.len == N
460 }
461
462 #[inline]
463 pub(crate) fn len(&self) -> usize {
464 self.raw.len
465 }
466
467 #[inline]
470 pub(crate) unsafe fn take_inline_hasher(&mut self) -> SI {
471 self.inline_hasher.take().unwrap_unchecked()
472 }
473
474 #[inline]
477 pub(crate) unsafe fn take_heap_hasher(&mut self) -> SH {
478 self.heap_hasher.take().unwrap_unchecked()
479 }
480
481 #[inline]
482 fn inline_hasher(&self) -> &SI {
483 self.inline_hasher.as_ref().unwrap()
484 }
485}
486
487impl<const N: usize, K, V, SH, SI, const LINEAR_THRESHOLD: usize>
488 Inline<N, K, V, SH, SI, LINEAR_THRESHOLD>
489where
490 K: Eq + Hash,
491 SI: BuildHasher,
492{
493 #[inline]
495 pub(crate) fn get<Q>(&self, k: &Q) -> Option<&V>
496 where
497 Q: ?Sized + Hash + Equivalent<K>,
498 {
499 match self.get_inner(k) {
501 Some((_, v)) => Some(v),
502 None => None,
503 }
504 }
505
506 #[inline]
508 pub(crate) fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut V>
509 where
510 Q: ?Sized + Hash + Equivalent<K>,
511 {
512 match self.get_inner_mut(k) {
514 Some((_, v)) => Some(v),
515 None => None,
516 }
517 }
518
519 #[inline]
521 pub(crate) fn get_key_value<Q>(&self, k: &Q) -> Option<(&K, &V)>
522 where
523 Q: ?Sized + Hash + Equivalent<K>,
524 {
525 match self.get_inner(k) {
527 Some((key, value)) => Some((key, value)),
528 None => None,
529 }
530 }
531
532 #[inline]
534 pub(crate) fn insert(&mut self, k: K, v: V) -> Option<V> {
535 if N < LINEAR_THRESHOLD {
536 let len = self.raw.len;
538 for i in 0..len {
539 let item = unsafe { self.raw.data[i].assume_init_mut() };
540 if k.equivalent(&item.0) {
541 return Some(mem::replace(&mut item.1, v));
542 }
543 }
544 self.raw.data[len].write((k, v));
545 self.raw.len = len + 1;
546 None
547 } else {
548 let hash_builder = self.inline_hasher.as_ref().unwrap();
549 let mut hash = HashValue::new(|| make_hash::<K, SI>(hash_builder, &k));
550 match self.raw.find(&mut hash, equivalent_key(&k)) {
551 Some(bucket) => Some(mem::replace(unsafe { &mut bucket.as_mut().1 }, v)),
552 None => {
553 let slot = InsertSlot {
554 index: self.raw.len,
555 };
556 unsafe { self.raw.insert_in_slot(hash.get(), slot, (k, v)) };
557 None
558 }
559 }
560 }
561 }
562
563 #[inline]
568 pub(crate) unsafe fn insert_unique_unchecked(&mut self, k: K, v: V) -> (&K, &mut V) {
569 let len = self.raw.len;
570 if N < LINEAR_THRESHOLD {
571 self.raw.data[len].write((k, v));
572 self.raw.len = len + 1;
573 let item = self.raw.data[len].assume_init_mut();
574 (&item.0, &mut item.1)
575 } else {
576 let hash_builder = self.inline_hasher.as_ref().unwrap();
577 let hash = make_hash::<K, SI>(hash_builder, &k);
578 let slot = InsertSlot { index: len };
579 let bucket = self.raw.insert_in_slot(hash, slot, (k, v));
580 let (k, v) = bucket.as_mut();
581 (k, v)
582 }
583 }
584
585 #[inline]
588 pub(crate) fn remove_entry<Q>(&mut self, k: &Q) -> Option<(K, V)>
589 where
590 Q: ?Sized + Hash + Equivalent<K>,
591 {
592 let hash_builder = self.inline_hasher.as_ref().unwrap();
593 let mut hash = HashValue::new(|| make_hash::<Q, SI>(hash_builder, k));
594 self.raw.remove_entry(&mut hash, equivalent_key(k))
595 }
596
597 #[inline]
599 pub(crate) fn retain<F>(&mut self, f: &mut F)
600 where
601 F: FnMut(&K, &mut V) -> bool,
602 {
603 self.raw.retain(f);
604 }
605
606 #[inline]
607 fn get_inner<Q>(&self, k: &Q) -> Option<&(K, V)>
608 where
609 Q: ?Sized + Hash + Equivalent<K>,
610 {
611 if unlikely(self.is_empty()) {
612 return None;
613 }
614 let mut hash = HashValue::new(|| make_hash::<Q, SI>(self.inline_hasher(), k));
615 match self.raw.find(&mut hash, equivalent_key(k)) {
616 Some(bucket) => Some(unsafe { bucket.as_ref() }),
617 None => None,
618 }
619 }
620
621 #[inline]
622 fn get_inner_mut<Q>(&mut self, k: &Q) -> Option<&mut (K, V)>
623 where
624 Q: ?Sized + Hash + Equivalent<K>,
625 {
626 if unlikely(self.is_empty()) {
627 return None;
628 }
629 let hash_builder = self.inline_hasher.as_ref().unwrap();
630 let mut hash = HashValue::new(|| make_hash::<Q, SI>(hash_builder, k));
631 match self.raw.find(&mut hash, equivalent_key(k)) {
632 Some(bucket) => Some(unsafe { bucket.as_mut() }),
633 None => None,
634 }
635 }
636}