1use crate::array::Array;
8use crate::doubly_linked_list::{self, DoublyLinkedList, DoublyLinkedListContainable};
9use crate::ptr_traits::{ManagedPtr, PtrTraits};
10use crate::singly_linked_list::{self, SinglyLinkedList, SinglyLinkedListContainable};
11use crate::size_tracker::SizeTracker;
12use core::borrow::Borrow;
13use core::marker::PhantomData;
14use core::pin::Pin;
15use core::ptr::NonNull;
16use kalloc::AllocError;
17
18pub trait HashTableKeyable<K: ?Sized> {
25 type Key<'a>: Borrow<K>
30 where
31 Self: 'a;
32
33 fn get_key(&self) -> Self::Key<'_>;
35}
36
37pub trait HashTraits<K: ?Sized> {
42 fn get_hash(key: &K) -> usize;
44}
45
46pub trait DefaultHashable {
55 fn hash_key(&self) -> usize;
57}
58
59macro_rules! impl_default_hashable_for_int {
60 ($($t:ty),*) => {
61 $(
62 impl DefaultHashable for $t {
63 #[inline]
64 fn hash_key(&self) -> usize {
65 *self as usize
66 }
67 }
68 )*
69 };
70}
71
72impl_default_hashable_for_int!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
73
74#[derive(Debug, Default, Clone, Copy)]
78pub struct DefaultHashTraits;
79
80impl<K: DefaultHashable + ?Sized> HashTraits<K> for DefaultHashTraits {
81 #[inline]
82 fn get_hash(key: &K) -> usize {
83 key.hash_key()
84 }
85}
86
87mod sealed {
88 use super::*;
89
90 pub trait Sealed {}
91
92 impl<P, Tag, S> Sealed for SinglyLinkedList<P, Tag, S>
93 where
94 P: PtrTraits,
95 P::Target: SinglyLinkedListContainable<P::Target, Tag>,
96 S: SizeTracker,
97 {
98 }
99
100 impl<P, Tag, S> Sealed for DoublyLinkedList<P, Tag, S>
101 where
102 P: PtrTraits,
103 P::Target: DoublyLinkedListContainable<P::Target, Tag>,
104 S: SizeTracker,
105 {
106 }
107}
108
109pub trait HashTableBucket<P: PtrTraits>: sealed::Sealed + Sized {
119 type Iter<'a>: core::iter::Iterator<Item = &'a P::Target>
121 where
122 Self: 'a,
123 P: 'a;
124
125 fn try_new_buckets(count: usize) -> Result<Pin<Array<Self>>, AllocError>;
127
128 fn is_empty(&self) -> bool;
130
131 unsafe fn push_front_raw(self: Pin<&mut Self>, ptr: P);
138
139 fn find_if<F>(&self, f: F) -> Option<&P::Target>
141 where
142 F: FnMut(&P::Target) -> bool;
143
144 fn erase_if<F>(self: Pin<&mut Self>, f: F) -> Option<P>
147 where
148 F: FnMut(&P::Target) -> bool;
149
150 unsafe fn erase(self: Pin<&mut Self>, obj: &P::Target) -> Option<P>;
157
158 unsafe fn replace_raw(self: Pin<&mut Self>, obj: &P::Target, replacement: P) -> Option<P>;
166
167 fn clear(self: Pin<&mut Self>);
169
170 fn iter<'a>(&'a self) -> Self::Iter<'a>
172 where
173 P: 'a;
174}
175
176#[inline]
178fn unpin_singly_linked_list<P, Tag, S>(
179 list: Pin<&mut SinglyLinkedList<P, Tag, S>>,
180) -> &mut SinglyLinkedList<P, Tag, S>
181where
182 P: PtrTraits,
183 P::Target: SinglyLinkedListContainable<P::Target, Tag>,
184 S: SizeTracker,
185{
186 unsafe { list.get_unchecked_mut() }
189}
190
191impl<P, Tag, S> HashTableBucket<P> for SinglyLinkedList<P, Tag, S>
192where
193 P: PtrTraits,
194 P::Target: SinglyLinkedListContainable<P::Target, Tag>,
195 S: SizeTracker,
196{
197 type Iter<'a>
198 = singly_linked_list::Iterator<'a, P, Tag>
199 where
200 Self: 'a,
201 P: 'a;
202
203 #[inline]
204 fn try_new_buckets(count: usize) -> Result<Pin<Array<Self>>, AllocError> {
205 Ok(Array::<Self>::try_new(count)?.into_pin())
206 }
207
208 #[inline]
209 fn is_empty(&self) -> bool {
210 SinglyLinkedList::is_empty(self)
211 }
212
213 #[inline]
214 unsafe fn push_front_raw(self: Pin<&mut Self>, ptr: P) {
215 unsafe { SinglyLinkedList::push_front_raw(unpin_singly_linked_list(self), ptr) }
218 }
219
220 #[inline]
221 fn find_if<F>(&self, f: F) -> Option<&P::Target>
222 where
223 F: FnMut(&P::Target) -> bool,
224 {
225 SinglyLinkedList::find_if(self, f)
226 }
227
228 #[inline]
229 fn erase_if<F>(self: Pin<&mut Self>, f: F) -> Option<P>
230 where
231 F: FnMut(&P::Target) -> bool,
232 {
233 SinglyLinkedList::erase_if(unpin_singly_linked_list(self), f)
234 }
235
236 #[inline]
237 unsafe fn erase(self: Pin<&mut Self>, obj: &P::Target) -> Option<P> {
238 if !<P::Target as SinglyLinkedListContainable<P::Target, Tag>>::get_node(obj).in_container()
239 {
240 return None;
241 }
242 SinglyLinkedList::erase_if(unpin_singly_linked_list(self), |other| {
243 core::ptr::eq(other, obj)
244 })
245 }
246
247 #[inline]
248 unsafe fn replace_raw(self: Pin<&mut Self>, obj: &P::Target, replacement: P) -> Option<P> {
249 unsafe {
252 SinglyLinkedList::replace_if_raw(
253 unpin_singly_linked_list(self),
254 |other| core::ptr::eq(other, obj),
255 replacement,
256 )
257 }
258 }
259
260 #[inline]
261 fn clear(self: Pin<&mut Self>) {
262 SinglyLinkedList::clear(unpin_singly_linked_list(self))
263 }
264
265 #[inline]
266 fn iter<'a>(&'a self) -> Self::Iter<'a>
267 where
268 P: 'a,
269 {
270 SinglyLinkedList::iter(self)
271 }
272}
273
274impl<P, Tag, S> HashTableBucket<P> for DoublyLinkedList<P, Tag, S>
275where
276 P: PtrTraits,
277 P::Target: DoublyLinkedListContainable<P::Target, Tag>,
278 S: SizeTracker,
279{
280 type Iter<'a>
281 = doubly_linked_list::ForwardIterator<'a, P, Tag>
282 where
283 Self: 'a,
284 P: 'a;
285
286 #[inline]
287 fn try_new_buckets(count: usize) -> Result<Pin<Array<Self>>, AllocError> {
288 Array::try_new_pin_init(count, Self::new)
289 }
290
291 #[inline]
292 fn is_empty(&self) -> bool {
293 DoublyLinkedList::is_empty(self)
294 }
295
296 #[inline]
297 unsafe fn push_front_raw(self: Pin<&mut Self>, ptr: P) {
298 unsafe { DoublyLinkedList::push_front_raw(self, ptr) }
301 }
302
303 #[inline]
304 fn find_if<F>(&self, f: F) -> Option<&P::Target>
305 where
306 F: FnMut(&P::Target) -> bool,
307 {
308 DoublyLinkedList::find_if(self, f)
309 }
310
311 #[inline]
312 fn erase_if<F>(self: Pin<&mut Self>, f: F) -> Option<P>
313 where
314 F: FnMut(&P::Target) -> bool,
315 {
316 DoublyLinkedList::erase_if(self, f)
317 }
318
319 #[inline]
320 unsafe fn erase(self: Pin<&mut Self>, obj: &P::Target) -> Option<P> {
321 unsafe { DoublyLinkedList::erase(self, obj) }
324 }
325
326 #[inline]
327 unsafe fn replace_raw(self: Pin<&mut Self>, obj: &P::Target, replacement: P) -> Option<P> {
328 unsafe { DoublyLinkedList::replace_raw(self, obj, replacement) }
331 }
332
333 #[inline]
334 fn clear(self: Pin<&mut Self>) {
335 DoublyLinkedList::clear(self)
336 }
337
338 #[inline]
339 fn iter<'a>(&'a self) -> Self::Iter<'a>
340 where
341 P: 'a,
342 {
343 self.forward_iter()
344 }
345}
346
347pub type HashTableInsertOrFindResult<'a, K, P, B, H> =
352 Result<(), (P, HashTableCursorMut<'a, K, P, B, H>)>;
353
354pub struct HashTable<K, P, B = SinglyLinkedList<P>, H = DefaultHashTraits>
483where
484 P: PtrTraits,
485 P::Target: HashTableKeyable<K>,
486 B: HashTableBucket<P>,
487 K: Eq,
488 H: HashTraits<K>,
489{
490 count: usize,
492
493 buckets: Pin<Array<B>>,
501
502 _phantom: PhantomData<(K, P, H)>,
503}
504
505impl<K, P, B, H> HashTable<K, P, B, H>
506where
507 P: PtrTraits,
508 P::Target: HashTableKeyable<K>,
509 B: HashTableBucket<P>,
510 K: Eq,
511 H: HashTraits<K>,
512{
513 #[inline]
519 pub const fn new() -> Self {
520 Self { count: 0, buckets: Array::new().into_pin(), _phantom: PhantomData }
521 }
522
523 pub fn try_new(bucket_count: usize) -> Result<Self, AllocError> {
531 let mut table = Self::new();
532 table.try_init(bucket_count)?;
533 Ok(table)
534 }
535
536 pub fn try_init(&mut self, bucket_count: usize) -> Result<(), AllocError> {
546 assert!(!self.is_initialized(), "HashTable may only be initialized once");
547 assert!(bucket_count > 0, "HashTables must have at least one bucket");
548 self.buckets = B::try_new_buckets(bucket_count)?;
549 Ok(())
550 }
551
552 #[inline]
554 pub fn is_initialized(&self) -> bool {
555 !self.buckets.is_empty()
556 }
557
558 #[inline]
560 pub fn bucket_count(&self) -> usize {
561 self.buckets.len()
562 }
563
564 #[inline]
566 pub fn len(&self) -> usize {
567 self.count
568 }
569
570 #[inline]
572 pub fn is_empty(&self) -> bool {
573 self.count == 0
574 }
575
576 #[inline]
582 fn bucket_mut(&mut self, ndx: usize) -> Pin<&mut B> {
583 unsafe { self.buckets.as_mut().map_unchecked_mut(|buckets| &mut buckets[ndx]) }
586 }
587
588 #[inline]
590 fn bucket_index(&self, key: &K) -> usize {
591 debug_assert!(self.is_initialized(), "HashTable used before initialization");
592 H::get_hash(key) % self.buckets.len()
593 }
594
595 #[inline]
597 fn bucket_index_of(&self, obj: &P::Target) -> usize {
598 let obj_key = <P::Target as HashTableKeyable<K>>::get_key(obj);
599 self.bucket_index(obj_key.borrow())
600 }
601
602 #[inline]
604 fn key_matches(obj: &P::Target, key: &K) -> bool {
605 let obj_key = <P::Target as HashTableKeyable<K>>::get_key(obj);
606 let obj_key: &K = obj_key.borrow();
607 obj_key == key
608 }
609
610 #[inline]
612 fn find_in_bucket(bucket: &B, key: &K) -> Option<NonNull<P::Target>> {
613 bucket.find_if(|obj| Self::key_matches(obj, key)).map(NonNull::from)
614 }
615
616 #[inline]
620 fn locate(&self, ptr: &P) -> (usize, Option<NonNull<P::Target>>) {
621 let obj_key = <P::Target as HashTableKeyable<K>>::get_key(PtrTraits::get_ref(ptr));
622 let key: &K = obj_key.borrow();
623 let ndx = self.bucket_index(key);
624 (ndx, Self::find_in_bucket(&self.buckets[ndx], key))
625 }
626
627 #[inline]
639 pub fn insert(&mut self, ptr: P)
640 where
641 P: ManagedPtr,
642 {
643 unsafe { self.insert_raw(ptr) }
646 }
647
648 pub unsafe fn insert_raw(&mut self, ptr: P) {
663 let (ndx, existing) = self.locate(&ptr);
664
665 debug_assert!(existing.is_none(), "Duplicate keys are not allowed in a HashTable");
669
670 unsafe { self.bucket_mut(ndx).push_front_raw(ptr) };
673 self.count += 1;
674 }
675
676 #[inline]
694 pub fn insert_or_find(&mut self, ptr: P) -> HashTableInsertOrFindResult<'_, K, P, B, H>
695 where
696 P: ManagedPtr,
697 {
698 unsafe { self.insert_or_find_raw(ptr) }
701 }
702
703 pub unsafe fn insert_or_find_raw(
718 &mut self,
719 ptr: P,
720 ) -> HashTableInsertOrFindResult<'_, K, P, B, H> {
721 let (ndx, existing) = self.locate(&ptr);
722 if existing.is_some() {
723 return Err((ptr, HashTableCursorMut { table: self, bucket: ndx, current: existing }));
724 }
725
726 unsafe { self.bucket_mut(ndx).push_front_raw(ptr) };
729 self.count += 1;
730 Ok(())
731 }
732
733 #[inline]
746 pub fn insert_or_replace(&mut self, ptr: P) -> Option<P>
747 where
748 P: ManagedPtr,
749 {
750 unsafe { self.insert_or_replace_raw(ptr) }
753 }
754
755 pub unsafe fn insert_or_replace_raw(&mut self, ptr: P) -> Option<P> {
771 let (ndx, existing) = self.locate(&ptr);
772 let bucket = self.bucket_mut(ndx);
773 match existing {
774 None => {
775 unsafe { bucket.push_front_raw(ptr) };
778 self.count += 1;
779 None
780 }
781 Some(existing) => unsafe { bucket.replace_raw(existing.as_ref(), ptr) },
785 }
786 }
787
788 #[inline]
794 pub fn find(&self, key: &K) -> Option<&P::Target> {
795 let ndx = self.bucket_index(key);
796 self.buckets[ndx].find_if(|obj| Self::key_matches(obj, key))
797 }
798
799 #[inline]
809 pub fn find_cursor(&mut self, key: &K) -> HashTableCursorMut<'_, K, P, B, H> {
810 let ndx = self.bucket_index(key);
811 let current = Self::find_in_bucket(&self.buckets[ndx], key);
812 HashTableCursorMut { table: self, bucket: ndx, current }
813 }
814
815 #[inline]
823 pub fn erase(&mut self, key: &K) -> Option<P> {
824 let ndx = self.bucket_index(key);
825 let ret = self.bucket_mut(ndx).erase_if(|obj| Self::key_matches(obj, key));
826 if ret.is_some() {
827 self.count -= 1;
828 }
829 ret
830 }
831
832 #[inline]
847 pub unsafe fn erase_element(&mut self, obj: &P::Target) -> Option<P> {
848 let ndx = self.bucket_index_of(obj);
849 let ret = unsafe { self.bucket_mut(ndx).erase(obj) };
853 if ret.is_some() {
854 self.count -= 1;
855 }
856 ret
857 }
858
859 pub fn erase_if<F>(&mut self, mut f: F) -> Option<P>
862 where
863 F: FnMut(&P::Target) -> bool,
864 {
865 debug_assert!(self.is_initialized(), "HashTable used before initialization");
866
867 if self.is_empty() {
868 return None;
869 }
870
871 let ret = (0..self.bucket_count()).find_map(|ndx| self.bucket_mut(ndx).erase_if(&mut f));
872 if ret.is_some() {
873 self.count -= 1;
874 }
875 ret
876 }
877
878 #[inline]
881 pub fn find_if<F>(&self, mut f: F) -> Option<&P::Target>
882 where
883 F: FnMut(&P::Target) -> bool,
884 {
885 debug_assert!(self.is_initialized(), "HashTable used before initialization");
886 self.iter().find(|&obj| f(obj))
887 }
888
889 pub fn clear(&mut self) {
894 for ndx in 0..self.bucket_count() {
895 self.bucket_mut(ndx).clear();
896 }
897 self.count = 0;
898 }
899
900 #[inline]
902 pub fn iter(&self) -> HashTableIter<'_, P, B> {
903 HashTableIter { buckets: self.buckets.iter(), current: None, remaining: self.count }
904 }
905}
906
907impl<K, P, B, H> Default for HashTable<K, P, B, H>
908where
909 P: PtrTraits,
910 P::Target: HashTableKeyable<K>,
911 B: HashTableBucket<P>,
912 K: Eq,
913 H: HashTraits<K>,
914{
915 #[inline]
917 fn default() -> Self {
918 Self::new()
919 }
920}
921
922impl<K, P, B, H> Drop for HashTable<K, P, B, H>
923where
924 P: PtrTraits,
925 P::Target: HashTableKeyable<K>,
926 B: HashTableBucket<P>,
927 K: Eq,
928 H: HashTraits<K>,
929{
930 fn drop(&mut self) {
931 if P::IS_MANAGED {
932 self.clear();
933 } else {
934 debug_assert!(self.is_empty(), "HashTable must be empty on destruction");
935 }
936 }
937}
938
939impl<K, P, B, H> core::fmt::Debug for HashTable<K, P, B, H>
940where
941 P: PtrTraits,
942 P::Target: HashTableKeyable<K> + core::fmt::Debug,
943 B: HashTableBucket<P>,
944 K: Eq,
945 H: HashTraits<K>,
946{
947 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
948 f.debug_set().entries(self.iter()).finish()
949 }
950}
951
952impl<'a, K, P, B, H> IntoIterator for &'a HashTable<K, P, B, H>
953where
954 P: PtrTraits,
955 P::Target: HashTableKeyable<K>,
956 B: HashTableBucket<P>,
957 K: Eq,
958 H: HashTraits<K>,
959{
960 type Item = &'a P::Target;
961 type IntoIter = HashTableIter<'a, P, B>;
962
963 #[inline]
964 fn into_iter(self) -> Self::IntoIter {
965 self.iter()
966 }
967}
968
969pub struct HashTableCursorMut<'a, K, P, B = SinglyLinkedList<P>, H = DefaultHashTraits>
974where
975 P: PtrTraits,
976 P::Target: HashTableKeyable<K>,
977 B: HashTableBucket<P>,
978 K: Eq,
979 H: HashTraits<K>,
980{
981 table: &'a mut HashTable<K, P, B, H>,
982 bucket: usize,
984 current: Option<NonNull<P::Target>>,
986}
987
988impl<'a, K, P, B, H> HashTableCursorMut<'a, K, P, B, H>
989where
990 P: PtrTraits,
991 P::Target: HashTableKeyable<K>,
992 B: HashTableBucket<P>,
993 K: Eq,
994 H: HashTraits<K>,
995{
996 #[inline]
999 pub fn get(&self) -> Option<&P::Target> {
1000 self.current.map(|current| unsafe { current.as_ref() })
1003 }
1004
1005 #[inline]
1009 pub fn erase(self) -> Option<P> {
1010 let current = self.current?;
1011 let ret = unsafe { self.table.bucket_mut(self.bucket).erase(current.as_ref()) };
1014 if ret.is_some() {
1015 self.table.count -= 1;
1016 }
1017 ret
1018 }
1019}
1020
1021pub struct HashTableIter<'a, P, B = SinglyLinkedList<P>>
1023where
1024 P: PtrTraits + 'a,
1025 B: HashTableBucket<P>,
1026{
1027 buckets: core::slice::Iter<'a, B>,
1029 current: Option<B::Iter<'a>>,
1031 remaining: usize,
1033}
1034
1035impl<'a, P, B> Iterator for HashTableIter<'a, P, B>
1036where
1037 P: PtrTraits + 'a,
1038 B: HashTableBucket<P> + 'a,
1039{
1040 type Item = &'a P::Target;
1041
1042 fn next(&mut self) -> Option<Self::Item> {
1043 loop {
1044 if let Some(obj) = self.current.as_mut().and_then(|iter| iter.next()) {
1045 self.remaining -= 1;
1046 return Some(obj);
1047 }
1048 match self.buckets.next() {
1049 Some(bucket) => self.current = Some(bucket.iter()),
1050 None => {
1051 self.current = None;
1052 return None;
1053 }
1054 }
1055 }
1056 }
1057
1058 #[inline]
1059 fn size_hint(&self) -> (usize, Option<usize>) {
1060 (self.remaining, Some(self.remaining))
1061 }
1062}
1063
1064impl<'a, P, B> ExactSizeIterator for HashTableIter<'a, P, B>
1065where
1066 P: PtrTraits + 'a,
1067 B: HashTableBucket<P> + 'a,
1068{
1069}
1070
1071impl<'a, P, B> core::iter::FusedIterator for HashTableIter<'a, P, B>
1072where
1073 P: PtrTraits + 'a,
1074 B: HashTableBucket<P> + 'a,
1075{
1076}
1077
1078#[cfg(test)]
1079mod tests {
1080 extern crate alloc;
1081 use super::*;
1082 use crate::doubly_linked_list::DoublyLinkedListNode;
1083 use crate::intrusive_container_test_support::*;
1084 use crate::ref_ptr::RefPtr;
1085 use crate::singly_linked_list::SinglyLinkedListNode;
1086 use crate::unique_ptr::UniquePtr;
1087
1088 const REGULAR_BUCKETS: usize = 37;
1089 const SHARED_BUCKETS: usize = 1031;
1090
1091 #[derive(
1092 crate::SinglyLinkedListContainable, crate::DoublyLinkedListContainable, crate::Recyclable,
1093 )]
1094 struct TestObject {
1095 value: i32,
1096 #[sll_node]
1097 sll_node: SinglyLinkedListNode<TestObject>,
1098 #[dll_node]
1099 dll_node: DoublyLinkedListNode<TestObject>,
1100 }
1101
1102 impl TestValue for TestObject {
1103 fn new(value: i32) -> Self {
1104 Self {
1105 value,
1106 sll_node: SinglyLinkedListNode::new(),
1107 dll_node: DoublyLinkedListNode::new(),
1108 }
1109 }
1110 }
1111
1112 impl HashTableKeyable<usize> for TestObject {
1113 type Key<'a> = usize;
1114 fn get_key(&self) -> usize {
1115 self.value as usize
1116 }
1117 }
1118
1119 #[derive(
1120 crate::SinglyLinkedListContainable, crate::DoublyLinkedListContainable, crate::Recyclable,
1121 )]
1122 struct UniqueTestObject {
1123 value: i32,
1124 #[sll_node]
1125 sll_node: SinglyLinkedListNode<UniqueTestObject>,
1126 #[dll_node]
1127 dll_node: DoublyLinkedListNode<UniqueTestObject>,
1128 }
1129
1130 impl TestValue for UniqueTestObject {
1131 fn new(value: i32) -> Self {
1132 Self {
1133 value,
1134 sll_node: SinglyLinkedListNode::new(),
1135 dll_node: DoublyLinkedListNode::new(),
1136 }
1137 }
1138 }
1139
1140 impl HashTableKeyable<usize> for UniqueTestObject {
1141 type Key<'a> = usize;
1142 fn get_key(&self) -> usize {
1143 self.value as usize
1144 }
1145 }
1146
1147 #[fbl::ref_counted]
1148 #[derive(
1149 crate::SinglyLinkedListContainable, crate::DoublyLinkedListContainable, crate::Recyclable,
1150 )]
1151 #[repr(C)]
1152 pub struct RefTestObject {
1153 value: i32,
1154 #[sll_node]
1155 sll_node: SinglyLinkedListNode<RefTestObject>,
1156 #[dll_node]
1157 dll_node: DoublyLinkedListNode<RefTestObject>,
1158 }
1159
1160 impl TestValue for RefTestObject {
1161 fn new_ref_counted(value: i32) -> RefPtr<Self> {
1162 crate::make_ref_counted!(RefTestObject {
1163 value: value,
1164 sll_node: SinglyLinkedListNode::new(),
1165 dll_node: DoublyLinkedListNode::new()
1166 })
1167 .unwrap()
1168 }
1169 }
1170
1171 impl HashTableKeyable<usize> for RefTestObject {
1172 type Key<'a> = usize;
1173 fn get_key(&self) -> usize {
1174 self.value as usize
1175 }
1176 }
1177
1178 ::zr::static_assert!(
1181 core::mem::size_of::<HashTable<usize, *mut TestObject>>()
1182 == 3 * core::mem::size_of::<usize>()
1183 );
1184 ::zr::static_assert!(
1185 core::mem::align_of::<HashTable<usize, *mut TestObject>>()
1186 == core::mem::align_of::<usize>()
1187 );
1188 ::zr::static_assert!(
1189 core::mem::size_of::<HashTable<usize, *mut TestObject, DoublyLinkedList<*mut TestObject>>>(
1190 ) == 3 * core::mem::size_of::<usize>()
1191 );
1192
1193 macro_rules! generate_hash_table_tests {
1194 ($mod_name:ident, $ptr_type:ty, $bucket_type:ty, $factory_type:ty, $insert:expr) => {
1195 mod $mod_name {
1196 use super::*;
1197
1198 type Table = HashTable<usize, $ptr_type, $bucket_type>;
1199
1200 fn raw_of(ptr: &$ptr_type) -> *const <$ptr_type as PtrTraits>::Target {
1201 PtrTraits::get_ref(ptr)
1202 }
1203
1204 fn bucket_elements(
1206 table: &Table,
1207 ndx: usize,
1208 ) -> alloc::vec::Vec<*const <$ptr_type as PtrTraits>::Target> {
1209 table.buckets[ndx].iter().map(|obj| obj as *const _).collect()
1210 }
1211
1212 #[test]
1213 fn test_basic() {
1214 let mut factory = <$factory_type>::new();
1215 let mut table = Table::try_new(REGULAR_BUCKETS).unwrap();
1216 assert!(table.is_initialized());
1217 assert_eq!(table.bucket_count(), REGULAR_BUCKETS);
1218 assert!(table.is_empty());
1219 assert_eq!(table.len(), 0);
1220
1221 $insert(&mut table, factory.create(1));
1222 $insert(&mut table, factory.create(2));
1223 $insert(&mut table, factory.create(3));
1224 assert!(!table.is_empty());
1225 assert_eq!(table.len(), 3);
1226
1227 assert_eq!(table.find(&1).unwrap().value, 1);
1228 assert_eq!(table.find(&2).unwrap().value, 2);
1229 assert_eq!(table.find(&3).unwrap().value, 3);
1230 assert!(table.find(&4).is_none());
1231
1232 let erased = table.erase(&2).unwrap();
1233 assert_eq!(PtrTraits::get_ref(&erased).value, 2);
1234 assert_eq!(table.len(), 2);
1235 assert!(table.find(&2).is_none());
1236 assert!(table.erase(&2).is_none());
1237 assert_eq!(table.len(), 2);
1238
1239 table.clear();
1240 assert!(table.is_empty());
1241 assert_eq!(table.len(), 0);
1242 assert!(table.find(&1).is_none());
1243 assert!(table.find(&3).is_none());
1244 }
1245
1246 #[test]
1247 fn test_collisions() {
1248 let mut factory = <$factory_type>::new();
1249 let mut table = Table::try_new(REGULAR_BUCKETS).unwrap();
1250
1251 let base = 5;
1253 let keys = [base, base + REGULAR_BUCKETS, base + 2 * REGULAR_BUCKETS];
1254 for key in keys {
1255 $insert(&mut table, factory.create(key as i32));
1256 }
1257 assert_eq!(table.len(), 3);
1258 assert_eq!(table.buckets[base].iter().count(), 3);
1259 for (ndx, bucket) in table.buckets.iter().enumerate() {
1260 if ndx != base {
1261 assert!(bucket.is_empty());
1262 }
1263 }
1264
1265 for key in keys {
1266 assert_eq!(table.find(&key).unwrap().value, key as i32);
1267 }
1268
1269 assert!(table.erase(&keys[1]).is_some());
1271 assert_eq!(table.len(), 2);
1272 assert!(table.find(&keys[1]).is_none());
1273 assert_eq!(table.find(&keys[0]).unwrap().value, keys[0] as i32);
1274 assert_eq!(table.find(&keys[2]).unwrap().value, keys[2] as i32);
1275 assert_eq!(table.buckets[base].iter().count(), 2);
1276
1277 table.clear();
1278 assert!(table.buckets[base].is_empty());
1279 }
1280
1281 #[test]
1282 fn test_insert_or_find() {
1283 let mut factory = <$factory_type>::new();
1284 let mut table = Table::try_new(REGULAR_BUCKETS).unwrap();
1285
1286 let first = factory.create(7);
1287 let first_raw = raw_of(&first);
1288 assert!(unsafe { table.insert_or_find_raw(first) }.is_ok());
1289 assert_eq!(table.len(), 1);
1290
1291 let dup = factory.create(7);
1293 let dup_raw = raw_of(&dup);
1294 match unsafe { table.insert_or_find_raw(dup) } {
1295 Ok(()) => panic!("insert_or_find must not insert a duplicate key"),
1296 Err((returned, cursor)) => {
1297 assert!(core::ptr::eq(raw_of(&returned), dup_raw));
1298 assert!(core::ptr::eq(cursor.get().unwrap(), first_raw));
1299 }
1300 }
1301 assert_eq!(table.len(), 1);
1302 assert!(core::ptr::eq(table.find(&7).unwrap(), first_raw));
1303
1304 assert!(unsafe { table.insert_or_find_raw(factory.create(8)) }.is_ok());
1306 assert_eq!(table.len(), 2);
1307
1308 let dup = factory.create(8);
1310 match unsafe { table.insert_or_find_raw(dup) } {
1311 Ok(()) => panic!("insert_or_find must not insert a duplicate key"),
1312 Err((_returned, cursor)) => {
1313 assert_eq!(
1314 cursor.erase().map(|p| PtrTraits::get_ref(&p).value),
1315 Some(8)
1316 );
1317 }
1318 }
1319 assert_eq!(table.len(), 1);
1320 assert!(table.find(&8).is_none());
1321
1322 table.clear();
1323 }
1324
1325 #[test]
1326 fn test_insert_or_replace() {
1327 let mut factory = <$factory_type>::new();
1328 let mut table = Table::try_new(REGULAR_BUCKETS).unwrap();
1329
1330 let first = factory.create(3);
1331 let first_raw = raw_of(&first);
1332 assert!(unsafe { table.insert_or_replace_raw(first) }.is_none());
1333 assert_eq!(table.len(), 1);
1334
1335 let second = factory.create(3);
1336 let second_raw = raw_of(&second);
1337 let replaced = unsafe { table.insert_or_replace_raw(second) }.unwrap();
1338 assert!(core::ptr::eq(raw_of(&replaced), first_raw));
1339 assert!(!PtrTraits::get_ref(&replaced).sll_node.in_container());
1340 assert!(!PtrTraits::get_ref(&replaced).dll_node.in_container());
1341 assert_eq!(table.len(), 1);
1342 assert!(core::ptr::eq(table.find(&3).unwrap(), second_raw));
1343
1344 assert!(unsafe { table.insert_or_replace_raw(factory.create(4)) }.is_none());
1345 assert_eq!(table.len(), 2);
1346
1347 table.clear();
1348 }
1349
1350 #[test]
1351 fn test_insert_or_replace_in_chain() {
1352 let mut factory = <$factory_type>::new();
1353 let mut table = Table::try_new(REGULAR_BUCKETS).unwrap();
1354
1355 let base = 9;
1357 let keys = [base, base + REGULAR_BUCKETS, base + 2 * REGULAR_BUCKETS];
1358 for key in keys {
1359 $insert(&mut table, factory.create(key as i32));
1360 }
1361
1362 for position in [1, 2, 0] {
1365 let elements = bucket_elements(&table, base);
1366 let old = elements[position];
1367 let key = unsafe { &*old }.value;
1369
1370 let replacement = factory.create(key);
1371 let replacement_raw = raw_of(&replacement);
1372 let replaced = unsafe { table.insert_or_replace_raw(replacement) }.unwrap();
1373 assert!(core::ptr::eq(raw_of(&replaced), old));
1374 assert_eq!(table.len(), keys.len());
1375 assert!(core::ptr::eq(
1376 table.find(&(key as usize)).unwrap(),
1377 replacement_raw
1378 ));
1379
1380 let mut expected = elements;
1382 expected[position] = replacement_raw;
1383 assert_eq!(bucket_elements(&table, base), expected);
1384 }
1385
1386 table.clear();
1387 }
1388
1389 #[test]
1390 fn test_find_cursor() {
1391 let mut factory = <$factory_type>::new();
1392 let mut table = Table::try_new(REGULAR_BUCKETS).unwrap();
1393 for i in 0..10 {
1394 $insert(&mut table, factory.create(i));
1395 }
1396
1397 assert_eq!(table.find_cursor(&4).get().unwrap().value, 4);
1398 let erased = table.find_cursor(&4).erase().unwrap();
1399 assert_eq!(PtrTraits::get_ref(&erased).value, 4);
1400 assert_eq!(table.len(), 9);
1401 assert!(table.find(&4).is_none());
1402
1403 assert!(table.find_cursor(&4).get().is_none());
1404 assert!(table.find_cursor(&4).erase().is_none());
1405 assert_eq!(table.len(), 9);
1406
1407 table.clear();
1408 }
1409
1410 #[test]
1411 fn test_erase_element() {
1412 let mut factory = <$factory_type>::new();
1413 let mut table = Table::try_new(REGULAR_BUCKETS).unwrap();
1414 for i in 0..10 {
1415 $insert(&mut table, factory.create(i));
1416 }
1417
1418 let obj: *const _ = table.find(&6).unwrap();
1419 let erased = unsafe { table.erase_element(&*obj) }.unwrap();
1421 assert!(core::ptr::eq(raw_of(&erased), obj));
1422 assert_eq!(table.len(), 9);
1423 assert!(table.find(&6).is_none());
1424
1425 assert!(unsafe { table.erase_element(PtrTraits::get_ref(&erased)) }.is_none());
1428 assert_eq!(table.len(), 9);
1429
1430 table.clear();
1431 }
1432
1433 #[test]
1434 fn test_erase_element_in_chain() {
1435 let orders = [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]];
1438 for (iteration, order) in orders.iter().enumerate() {
1439 let mut factory = <$factory_type>::new();
1440 let mut table = Table::try_new(REGULAR_BUCKETS).unwrap();
1441
1442 let base = 11;
1444 let keys = [base, base + REGULAR_BUCKETS, base + 2 * REGULAR_BUCKETS];
1445 for key in keys {
1446 $insert(&mut table, factory.create(key as i32));
1447 }
1448
1449 let mut remaining = bucket_elements(&table, base);
1450 let mut positions = alloc::vec::Vec::from(*order);
1451 for step in 0..positions.len() {
1452 let position = positions.remove(0);
1453 let obj = remaining.remove(position);
1454 for p in positions.iter_mut() {
1456 if *p > position {
1457 *p -= 1;
1458 }
1459 }
1460
1461 let erased = if (iteration + step) % 2 == 0 {
1462 unsafe { table.erase_element(&*obj) }.unwrap()
1464 } else {
1465 let key = unsafe { &*obj }.value as usize;
1467 table.find_cursor(&key).erase().unwrap()
1468 };
1469 assert!(core::ptr::eq(raw_of(&erased), obj));
1470 assert_eq!(table.len(), remaining.len());
1471 assert_eq!(bucket_elements(&table, base), remaining);
1472 for &other in remaining.iter() {
1473 let key = unsafe { &*other }.value as usize;
1475 assert!(core::ptr::eq(table.find(&key).unwrap(), other));
1476 }
1477 }
1478 assert!(table.is_empty());
1479 assert!(table.buckets[base].is_empty());
1480 }
1481 }
1482
1483 #[test]
1484 fn test_iter() {
1485 let mut factory = <$factory_type>::new();
1486 let mut table = Table::try_new(REGULAR_BUCKETS).unwrap();
1487 assert!(table.iter().next().is_none());
1488
1489 const COUNT: i32 = 100;
1490 for i in 0..COUNT {
1491 $insert(&mut table, factory.create(i));
1492 }
1493
1494 let iter = table.iter();
1495 assert_eq!(iter.len(), COUNT as usize);
1496 let mut seen = [false; COUNT as usize];
1497 let mut count = 0;
1498 for obj in &table {
1499 assert!(!seen[obj.value as usize]);
1500 seen[obj.value as usize] = true;
1501 count += 1;
1502 }
1503 assert_eq!(count, COUNT);
1504 assert!(seen.iter().all(|&s| s));
1505
1506 table.clear();
1507 assert!(table.iter().next().is_none());
1508 }
1509
1510 #[test]
1511 fn test_erase_if_and_find_if() {
1512 let mut factory = <$factory_type>::new();
1513 let mut table = Table::try_new(REGULAR_BUCKETS).unwrap();
1514 assert!(table.erase_if(|_| true).is_none());
1515
1516 for i in 0..20 {
1517 $insert(&mut table, factory.create(i));
1518 }
1519
1520 assert_eq!(table.find_if(|obj| obj.value == 13).unwrap().value, 13);
1521 assert!(table.find_if(|obj| obj.value == 20).is_none());
1522
1523 let erased = table.erase_if(|obj| obj.value == 13).unwrap();
1524 assert_eq!(PtrTraits::get_ref(&erased).value, 13);
1525 assert_eq!(table.len(), 19);
1526 assert!(table.find(&13).is_none());
1527 assert!(table.erase_if(|obj| obj.value == 13).is_none());
1528
1529 while table.erase_if(|_| true).is_some() {}
1531 assert!(table.is_empty());
1532 assert!(table.iter().next().is_none());
1533 }
1534
1535 #[test]
1536 fn test_dynamic_bucket_counts() {
1537 for bucket_count in [REGULAR_BUCKETS, SHARED_BUCKETS] {
1538 let mut factory = <$factory_type>::new();
1539 let mut table = Table::try_new(bucket_count).unwrap();
1540 assert_eq!(table.bucket_count(), bucket_count);
1541
1542 let count = 2 * bucket_count;
1544 for i in 0..count {
1545 $insert(&mut table, factory.create(i as i32));
1546 }
1547 assert_eq!(table.len(), count);
1548 for bucket in table.buckets.iter() {
1549 assert_eq!(bucket.iter().count(), 2);
1550 }
1551
1552 for i in 0..count {
1553 assert_eq!(table.find(&i).unwrap().value, i as i32);
1554 }
1555 for i in 0..count {
1556 assert!(table.erase(&i).is_some());
1557 assert_eq!(table.len(), count - i - 1);
1558 }
1559 assert!(table.is_empty());
1560 assert!(table.buckets.iter().all(|bucket| bucket.is_empty()));
1561 }
1562 }
1563 }
1564 };
1565 }
1566
1567 generate_hash_table_tests!(
1568 raw_ptr_sll_tests,
1569 *mut TestObject,
1570 SinglyLinkedList<*mut TestObject>,
1571 RawFactory<TestObject>,
1572 |table: &mut Table, obj| unsafe { table.insert_raw(obj) }
1573 );
1574
1575 generate_hash_table_tests!(
1576 raw_ptr_dll_tests,
1577 *mut TestObject,
1578 DoublyLinkedList<*mut TestObject>,
1579 RawFactory<TestObject>,
1580 |table: &mut Table, obj| unsafe { table.insert_raw(obj) }
1581 );
1582
1583 generate_hash_table_tests!(
1584 unique_ptr_sll_tests,
1585 UniquePtr<UniqueTestObject>,
1586 SinglyLinkedList<UniquePtr<UniqueTestObject>>,
1587 UniqueFactory<UniqueTestObject>,
1588 |table: &mut Table, obj| table.insert(obj)
1589 );
1590
1591 generate_hash_table_tests!(
1592 unique_ptr_dll_tests,
1593 UniquePtr<UniqueTestObject>,
1594 DoublyLinkedList<UniquePtr<UniqueTestObject>>,
1595 UniqueFactory<UniqueTestObject>,
1596 |table: &mut Table, obj| table.insert(obj)
1597 );
1598
1599 generate_hash_table_tests!(
1600 ref_ptr_sll_tests,
1601 RefPtr<RefTestObject>,
1602 SinglyLinkedList<RefPtr<RefTestObject>>,
1603 RefFactory<RefTestObject>,
1604 |table: &mut Table, obj| table.insert(obj)
1605 );
1606
1607 generate_hash_table_tests!(
1608 ref_ptr_dll_tests,
1609 RefPtr<RefTestObject>,
1610 DoublyLinkedList<RefPtr<RefTestObject>>,
1611 RefFactory<RefTestObject>,
1612 |table: &mut Table, obj| table.insert(obj)
1613 );
1614
1615 #[test]
1616 fn test_delayed_init() {
1617 let mut table = HashTable::<usize, UniquePtr<UniqueTestObject>>::new();
1618 assert!(!table.is_initialized());
1619 assert_eq!(table.bucket_count(), 0);
1620 assert!(table.is_empty());
1621 assert_eq!(table.len(), 0);
1622 assert!(table.iter().next().is_none());
1623 table.clear();
1624
1625 table.try_init(REGULAR_BUCKETS).unwrap();
1626 assert!(table.is_initialized());
1627 assert_eq!(table.bucket_count(), REGULAR_BUCKETS);
1628 assert!(table.is_empty());
1629
1630 table.insert(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
1631 assert_eq!(table.len(), 1);
1632 assert_eq!(table.find(&1).unwrap().value, 1);
1633 }
1634
1635 #[test]
1636 fn test_default_is_uninitialized() {
1637 let table: HashTable<usize, *mut TestObject> = Default::default();
1638 assert!(!table.is_initialized());
1639 assert!(table.is_empty());
1640
1641 let table: HashTable<usize, *mut TestObject, DoublyLinkedList<*mut TestObject>> =
1642 Default::default();
1643 assert!(!table.is_initialized());
1644 assert!(table.is_empty());
1645 }
1646
1647 #[test]
1648 fn test_move_table() {
1649 type DllTable = HashTable<
1652 usize,
1653 UniquePtr<UniqueTestObject>,
1654 DoublyLinkedList<UniquePtr<UniqueTestObject>>,
1655 >;
1656 let mut table = DllTable::try_new(REGULAR_BUCKETS).unwrap();
1657 for i in 0..10 {
1658 table.insert(UniquePtr::try_new(UniqueTestObject::new(i)).unwrap());
1659 }
1660
1661 let mut moved = table;
1662 assert_eq!(moved.len(), 10);
1663 for i in 0..10 {
1664 assert_eq!(moved.find(&(i as usize)).unwrap().value, i);
1665 }
1666 assert!(moved.erase(&3).is_some());
1667 moved.insert(UniquePtr::try_new(UniqueTestObject::new(42)).unwrap());
1668 assert_eq!(moved.len(), 10);
1669 assert_eq!(moved.iter().count(), 10);
1670
1671 let mut late = DllTable::new();
1673 late = core::mem::replace(&mut moved, late);
1674 assert_eq!(late.len(), 10);
1675 assert!(!moved.is_initialized());
1676 }
1677
1678 struct ShiftHashTraits;
1679
1680 impl HashTraits<usize> for ShiftHashTraits {
1681 fn get_hash(key: &usize) -> usize {
1682 *key >> 4
1683 }
1684 }
1685
1686 #[test]
1687 fn test_custom_hash_traits() {
1688 let mut table = HashTable::<
1689 usize,
1690 UniquePtr<UniqueTestObject>,
1691 SinglyLinkedList<UniquePtr<UniqueTestObject>>,
1692 ShiftHashTraits,
1693 >::try_new(REGULAR_BUCKETS)
1694 .unwrap();
1695
1696 for i in 0..32 {
1698 table.insert(UniquePtr::try_new(UniqueTestObject::new(i)).unwrap());
1699 }
1700 assert_eq!(table.buckets[0].iter().count(), 16);
1701 assert_eq!(table.buckets[1].iter().count(), 16);
1702 for i in 0..32 {
1703 assert_eq!(table.find(&i).unwrap().value, i as i32);
1704 }
1705 }
1706
1707 struct ReversedHashTraits;
1708
1709 impl HashTraits<usize> for ReversedHashTraits {
1710 fn get_hash(key: &usize) -> usize {
1711 usize::MAX - *key
1712 }
1713 }
1714
1715 #[test]
1716 fn test_hash_reduced_modulo_bucket_count() {
1717 let mut table = HashTable::<
1719 usize,
1720 UniquePtr<UniqueTestObject>,
1721 DoublyLinkedList<UniquePtr<UniqueTestObject>>,
1722 ReversedHashTraits,
1723 >::try_new(REGULAR_BUCKETS)
1724 .unwrap();
1725
1726 for i in 0..100 {
1727 table.insert(UniquePtr::try_new(UniqueTestObject::new(i)).unwrap());
1728 }
1729 for (ndx, bucket) in table.buckets.iter().enumerate() {
1730 for obj in bucket.iter() {
1731 assert_eq!((usize::MAX - obj.value as usize) % REGULAR_BUCKETS, ndx);
1732 }
1733 }
1734 for i in 0..100 {
1735 assert_eq!(table.find(&i).unwrap().value, i as i32);
1736 }
1737 }
1738
1739 #[test]
1740 fn test_default_hash_traits() {
1741 assert_eq!(<DefaultHashTraits as HashTraits<usize>>::get_hash(&40), 40);
1742 assert_eq!(<DefaultHashTraits as HashTraits<u32>>::get_hash(&1031), 1031);
1743 assert_eq!(<DefaultHashTraits as HashTraits<u64>>::get_hash(&1), 1);
1744 assert_eq!(<DefaultHashTraits as HashTraits<u8>>::get_hash(&200), 200);
1745 assert_eq!(<DefaultHashTraits as HashTraits<usize>>::get_hash(&usize::MAX), usize::MAX);
1746 }
1747
1748 use alloc::sync::Arc;
1749 use core::sync::atomic::{AtomicUsize, Ordering};
1750
1751 #[derive(
1752 crate::SinglyLinkedListContainable, crate::DoublyLinkedListContainable, crate::Recyclable,
1753 )]
1754 struct LifecycleObject {
1755 key: u64,
1756 destroyed: Arc<AtomicUsize>,
1757 #[sll_node]
1758 sll_node: SinglyLinkedListNode<LifecycleObject>,
1759 #[dll_node]
1760 dll_node: DoublyLinkedListNode<LifecycleObject>,
1761 }
1762
1763 impl LifecycleObject {
1764 fn new(key: u64, destroyed: Arc<AtomicUsize>) -> Self {
1765 Self {
1766 key,
1767 destroyed,
1768 sll_node: SinglyLinkedListNode::new(),
1769 dll_node: DoublyLinkedListNode::new(),
1770 }
1771 }
1772 }
1773
1774 impl HashTableKeyable<u64> for LifecycleObject {
1775 type Key<'a> = u64;
1776 fn get_key(&self) -> u64 {
1777 self.key
1778 }
1779 }
1780
1781 impl Drop for LifecycleObject {
1782 fn drop(&mut self) {
1783 self.destroyed.fetch_add(1, Ordering::Relaxed);
1784 }
1785 }
1786
1787 type LifecycleDllBuckets = DoublyLinkedList<UniquePtr<LifecycleObject>>;
1788
1789 #[test]
1790 fn test_lifecycle_on_drop() {
1791 let destroyed = Arc::new(AtomicUsize::new(0));
1792 {
1793 let mut table =
1794 HashTable::<u64, UniquePtr<LifecycleObject>>::try_new(SHARED_BUCKETS).unwrap();
1795 let mut dll_table =
1796 HashTable::<u64, UniquePtr<LifecycleObject>, LifecycleDllBuckets>::try_new(
1797 SHARED_BUCKETS,
1798 )
1799 .unwrap();
1800 for key in 0..5 {
1801 table.insert(
1802 UniquePtr::try_new(LifecycleObject::new(key, destroyed.clone())).unwrap(),
1803 );
1804 dll_table.insert(
1805 UniquePtr::try_new(LifecycleObject::new(key, destroyed.clone())).unwrap(),
1806 );
1807 }
1808 assert_eq!(destroyed.load(Ordering::Relaxed), 0);
1809 } assert_eq!(destroyed.load(Ordering::Relaxed), 10);
1811 }
1812
1813 #[test]
1814 fn test_lifecycle_on_clear_and_erase() {
1815 let destroyed = Arc::new(AtomicUsize::new(0));
1816 let mut table =
1817 HashTable::<u64, UniquePtr<LifecycleObject>>::try_new(REGULAR_BUCKETS).unwrap();
1818 for key in 0..5 {
1819 table.insert(UniquePtr::try_new(LifecycleObject::new(key, destroyed.clone())).unwrap());
1820 }
1821
1822 let erased = table.erase(&2).unwrap();
1824 assert_eq!(destroyed.load(Ordering::Relaxed), 0);
1825 drop(erased);
1826 assert_eq!(destroyed.load(Ordering::Relaxed), 1);
1827
1828 table.clear();
1829 assert_eq!(destroyed.load(Ordering::Relaxed), 5);
1830 assert!(table.is_empty());
1831 }
1832
1833 #[test]
1834 fn test_move_between_table_and_free_list() {
1835 pin_init::stack_pin_init!(let free = LifecycleDllBuckets::new());
1838 let destroyed = Arc::new(AtomicUsize::new(0));
1839 for _ in 0..4 {
1840 free.as_mut().push_front(
1841 UniquePtr::try_new(LifecycleObject::new(0, destroyed.clone())).unwrap(),
1842 );
1843 }
1844
1845 let mut active =
1846 HashTable::<u64, UniquePtr<LifecycleObject>, LifecycleDllBuckets>::try_new(
1847 SHARED_BUCKETS,
1848 )
1849 .unwrap();
1850 let ids = [0x1000u64, 0x1000 + SHARED_BUCKETS as u64, 0x2000, 0x3000];
1851 for id in ids {
1852 let mut state = free.as_mut().pop_front().unwrap();
1853 state.key = id;
1854 active.insert(state);
1855 }
1856 assert!(free.is_empty());
1857 assert_eq!(active.len(), ids.len());
1858
1859 for id in ids {
1860 let state: *const LifecycleObject = active.find(&id).unwrap();
1861 let mut removed = unsafe { active.erase_element(&*state) }.unwrap();
1863 removed.key = 0;
1864 free.as_mut().push_front(removed);
1865 }
1866 assert!(active.is_empty());
1867 assert_eq!(destroyed.load(Ordering::Relaxed), 0);
1868
1869 free.as_mut().clear();
1870 assert_eq!(destroyed.load(Ordering::Relaxed), 4);
1871 }
1872}