libdd_profiling/profiles/collections/
slice_set.rs1use super::{SetError, ThinSlice};
5use core::hash::{BuildHasher, Hash};
6use core::hint::unreachable_unchecked;
7use hashbrown::HashTable;
8use libdd_alloc::{ChainAllocator, VirtualAllocator};
9
10use super::SetHasher as Hasher;
11
12pub struct SliceSet<T: Copy + Hash + Eq + 'static> {
14 pub(crate) arena: ChainAllocator<VirtualAllocator>,
16
17 pub(crate) slices: HashTable<ThinSlice<'static, T>>,
23}
24
25impl<T: Copy + Hash + Eq + 'static> SliceSet<T> {
26 const SIZE_HINT: usize = 1024 * 1024;
27
28 pub fn try_with_capacity(capacity: usize) -> Result<Self, SetError> {
29 let arena = ChainAllocator::new_in(Self::SIZE_HINT, VirtualAllocator {});
30
31 let mut slices = HashTable::new();
32 slices.try_reserve(capacity, |_| unsafe { unreachable_unchecked() })?;
35
36 Ok(SliceSet { arena, slices })
37 }
38
39 pub unsafe fn insert_unique_uncontended(
43 &mut self,
44 slice: &[T],
45 ) -> Result<ThinSlice<'static, T>, SetError> {
46 let hash = Hasher::default().hash_one(slice);
47 self.insert_unique_uncontended_with_hash(hash, slice)
48 }
49
50 #[inline(never)]
55 pub unsafe fn insert_unique_uncontended_with_hash(
56 &mut self,
57 hash: u64,
58 slice: &[T],
59 ) -> Result<ThinSlice<'static, T>, SetError> {
60 let obj = ThinSlice::try_allocate_for(slice, &self.arena)?;
61 let uninit = unsafe { &mut *obj.as_ptr() };
62 let new_slice = ThinSlice::try_from_slice_in(slice, uninit)?;
63
64 self.slices
65 .try_reserve(1, |thin| Hasher::default().hash_one(thin.as_slice()))?;
66
67 self.slices
71 .insert_unique(hash, new_slice, |_| unsafe { unreachable_unchecked() });
72
73 Ok(new_slice)
74 }
75
76 pub fn try_insert(&mut self, slice: &[T]) -> Result<ThinSlice<'static, T>, SetError>
79 where
80 T: Hash,
81 {
82 let hash = Hasher::default().hash_one(slice);
83
84 if let Some(id) = unsafe { self.find_with_hash(hash, slice) } {
87 return Ok(id);
88 }
89
90 unsafe { self.insert_unique_uncontended(slice) }
92 }
93
94 #[inline(never)]
98 pub(crate) unsafe fn find_with_hash(
99 &self,
100 hash: u64,
101 slice: &[T],
102 ) -> Option<ThinSlice<'static, T>>
103 where
104 T: PartialEq,
105 {
106 let interned_slice = self
107 .slices
108 .find(hash, |thin_slice| thin_slice.as_slice() == slice)?;
109 Some(*interned_slice)
110 }
111
112 pub fn iter(&self) -> impl Iterator<Item = ThinSlice<'_, T>> + '_ {
114 self.slices.iter().copied()
115 }
116
117 pub fn len(&self) -> usize {
119 self.slices.len()
120 }
121
122 pub fn is_empty(&self) -> bool {
124 self.slices.is_empty()
125 }
126
127 pub fn capacity(&self) -> usize {
129 self.slices.capacity()
130 }
131}