Skip to main content

osom_lib_hash_tables/
defaults.rs

1//! Contains the default, recommended choice for the hash table.
2
3use core::fmt::Debug;
4use core::hash::Hash;
5
6use osom_lib_alloc::traits::Allocator;
7use osom_lib_primitives::{kvp::KVP, length::Length};
8use osom_lib_reprc::traits::ReprC;
9use osom_lib_try_clone::TryClone;
10
11use crate::{
12    abseil::{defaults::DefaultAbseilConfig, hash_table::AbseilHashTable},
13    errors::{HashTableError, TryCloneHashTableError},
14    traits::{ImmutableHashTable, MutableHashTable},
15};
16
17type InnerMap<TKey, TValue, TAllocator> = AbseilHashTable<TKey, TValue, DefaultAbseilConfig<TAllocator>>;
18
19/// Represents the default hash table.
20///
21/// # Notes
22///
23/// At the moment it uses the [`AbseilHashTable`] as the underlying implementation.
24/// This can change in the future though.
25#[repr(transparent)]
26#[must_use]
27pub struct DefaultHashTable<TKey, TValue, TAllocator>
28where
29    TKey: Eq + Hash,
30    TAllocator: Allocator,
31{
32    inner: InnerMap<TKey, TValue, TAllocator>,
33}
34
35impl<TKey, TValue, TAllocator> Debug for DefaultHashTable<TKey, TValue, TAllocator>
36where
37    TKey: Eq + Hash,
38    TAllocator: Allocator,
39{
40    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
41        write!(f, "DefaultHashTable[{}]", stringify!(AbseilHashTable))
42    }
43}
44
45unsafe impl<TKey, TValue, TAllocator> Send for DefaultHashTable<TKey, TValue, TAllocator>
46where
47    TKey: Send + Eq + Hash,
48    TValue: Send,
49    TAllocator: Allocator + Send,
50    InnerMap<TKey, TValue, TAllocator>: Sync,
51{
52}
53
54unsafe impl<TKey, TValue, TAllocator> Sync for DefaultHashTable<TKey, TValue, TAllocator>
55where
56    TKey: Sync + Eq + Hash,
57    TValue: Sync,
58    TAllocator: Allocator + Sync,
59    InnerMap<TKey, TValue, TAllocator>: Sync,
60{
61}
62
63unsafe impl<TKey, TValue, TAllocator> ReprC for DefaultHashTable<TKey, TValue, TAllocator>
64where
65    TKey: Eq + Hash + ReprC,
66    TValue: ReprC,
67    TAllocator: Allocator + ReprC,
68    InnerMap<TKey, TValue, TAllocator>: ReprC,
69{
70    const CHECK: () = const {
71        osom_lib_reprc::hidden::is_reprc::<TKey>();
72        osom_lib_reprc::hidden::is_reprc::<TValue>();
73        osom_lib_reprc::hidden::is_reprc::<TAllocator>();
74        osom_lib_reprc::hidden::is_reprc::<InnerMap<TKey, TValue, TAllocator>>();
75    };
76}
77
78impl<TKey, TValue, TAllocator> DefaultHashTable<TKey, TValue, TAllocator>
79where
80    TKey: Eq + Hash,
81    TAllocator: Allocator,
82{
83    /// Creates a new, empty [`DefaultHashTable`] with the default allocator.
84    #[inline(always)]
85    pub fn new() -> Self
86    where
87        TAllocator: Default,
88    {
89        Self::with_allocator(TAllocator::default())
90    }
91
92    /// Creates a new, empty [`DefaultHashTable`] with the specified allocator.
93    #[inline(always)]
94    pub fn with_allocator(allocator: TAllocator) -> Self {
95        Self {
96            inner: AbseilHashTable::with_config(DefaultAbseilConfig::with_allocator(allocator)),
97        }
98    }
99
100    /// Creates a new [`DefaultHashTable`] with the specified capacity and the default allocator.
101    ///
102    /// This likely will (over)allocate memory.
103    ///
104    /// # Errors
105    ///
106    /// See [`HashTableError`] for details.
107    #[inline(always)]
108    pub fn with_capacity(capacity: Length) -> Result<Self, HashTableError>
109    where
110        TAllocator: Default,
111    {
112        Self::with_capacity_and_allocator(capacity, TAllocator::default())
113    }
114
115    /// Creates a new [`DefaultHashTable`] with the specified capacity and the specified allocator.
116    ///
117    /// This likely will (over)allocate memory.
118    ///
119    /// # Errors
120    ///
121    /// See [`HashTableError`] for details.
122    #[inline(always)]
123    pub fn with_capacity_and_allocator(capacity: Length, allocator: TAllocator) -> Result<Self, HashTableError> {
124        let inner = AbseilHashTable::with_capacity_and_config(capacity, DefaultAbseilConfig::with_allocator(allocator))?;
125        Ok(Self { inner })
126    }
127}
128
129impl<TKey, TValue, TAllocator> ImmutableHashTable<TKey, TValue> for DefaultHashTable<TKey, TValue, TAllocator>
130where
131    TKey: Eq + Hash,
132    TAllocator: Allocator,
133    InnerMap<TKey, TValue, TAllocator>: ImmutableHashTable<TKey, TValue>,
134{
135    #[inline(always)]
136    fn length(&self) -> Length {
137        self.inner.length()
138    }
139
140    #[inline(always)]
141    fn contains<Q>(&self, key: &Q) -> bool
142    where
143        TKey: core::borrow::Borrow<Q>,
144        Q: Eq + Hash + ?Sized,
145    {
146        self.inner.contains(key)
147    }
148
149    #[inline(always)]
150    fn get<Q>(&self, key: &Q) -> Option<&TValue>
151    where
152        TKey: core::borrow::Borrow<Q>,
153        Q: Eq + Hash + ?Sized,
154    {
155        self.inner.get(key)
156    }
157
158    #[inline(always)]
159    fn get_key_value<Q>(&self, key: &Q) -> Option<KVP<&TKey, &TValue>>
160    where
161        TKey: core::borrow::Borrow<Q>,
162        Q: Eq + Hash + ?Sized,
163    {
164        self.inner.get_key_value(key)
165    }
166
167    #[inline(always)]
168    fn iter<'a>(&'a self) -> impl Iterator<Item = KVP<&'a TKey, &'a TValue>>
169    where
170        TKey: 'a,
171        TValue: 'a,
172        Self: 'a,
173    {
174        self.inner.iter()
175    }
176}
177
178impl<TKey, TValue, TAllocator> MutableHashTable<TKey, TValue> for DefaultHashTable<TKey, TValue, TAllocator>
179where
180    TKey: Eq + Hash,
181    TAllocator: Allocator,
182    InnerMap<TKey, TValue, TAllocator>: MutableHashTable<TKey, TValue>,
183{
184    #[inline(always)]
185    fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut TValue>
186    where
187        TKey: core::borrow::Borrow<Q>,
188        Q: Eq + Hash + ?Sized,
189    {
190        self.inner.get_mut(key)
191    }
192
193    #[inline(always)]
194    fn get_key_value_mut<Q>(&mut self, key: &Q) -> Option<KVP<&TKey, &mut TValue>>
195    where
196        TKey: core::borrow::Borrow<Q>,
197        Q: Eq + Hash + ?Sized,
198    {
199        self.inner.get_key_value_mut(key)
200    }
201
202    #[inline(always)]
203    fn remove_entry<Q>(&mut self, key: &Q) -> Option<KVP<TKey, TValue>>
204    where
205        TKey: core::borrow::Borrow<Q>,
206        Q: Eq + Hash + ?Sized,
207    {
208        self.inner.remove_entry(key)
209    }
210
211    #[inline(always)]
212    fn iter_mut<'a>(&'a mut self) -> impl Iterator<Item = KVP<&'a TKey, &'a mut TValue>>
213    where
214        TKey: 'a,
215        TValue: 'a,
216        Self: 'a,
217    {
218        self.inner.iter_mut()
219    }
220
221    #[inline(always)]
222    fn try_insert_or_update_with<FAdd, FUpdate>(
223        &mut self,
224        key: TKey,
225        adder: FAdd,
226        updater: FUpdate,
227    ) -> Result<&mut TValue, crate::errors::HashTableError>
228    where
229        FAdd: FnOnce() -> TValue,
230        FUpdate: FnOnce(&mut TValue),
231    {
232        self.inner.try_insert_or_update_with(key, adder, updater)
233    }
234}
235
236impl<TKey, TValue, TAllocator> Default for DefaultHashTable<TKey, TValue, TAllocator>
237where
238    TKey: Eq + Hash,
239    TAllocator: Allocator + Default,
240    InnerMap<TKey, TValue, TAllocator>: Default,
241{
242    #[inline(always)]
243    fn default() -> Self {
244        Self::new()
245    }
246}
247
248impl<TKey, TValue, TAllocator> TryClone for DefaultHashTable<TKey, TValue, TAllocator>
249where
250    TKey: Eq + Hash,
251    TAllocator: Allocator,
252    InnerMap<TKey, TValue, TAllocator>: TryClone<Error = TryCloneHashTableError>,
253{
254    type Error = TryCloneHashTableError;
255
256    fn try_clone(&self) -> Result<Self, Self::Error> {
257        let inner = self.inner.try_clone()?;
258        Ok(Self { inner })
259    }
260}
261
262impl<TKey, TValue, TAllocator> Clone for DefaultHashTable<TKey, TValue, TAllocator>
263where
264    TKey: Eq + Hash,
265    TAllocator: Allocator,
266    InnerMap<TKey, TValue, TAllocator>: TryClone<Error = TryCloneHashTableError>,
267{
268    fn clone(&self) -> Self {
269        self.try_clone().expect("[DefaultHashTable::try_clone] failure")
270    }
271}
272
273impl<TKey, TValue, TAllocator> PartialEq for DefaultHashTable<TKey, TValue, TAllocator>
274where
275    TKey: Eq + Hash,
276    TAllocator: Allocator,
277    InnerMap<TKey, TValue, TAllocator>: PartialEq,
278{
279    fn eq(&self, other: &Self) -> bool {
280        self.inner == other.inner
281    }
282}
283
284impl<TKey, TValue, TAllocator> Eq for DefaultHashTable<TKey, TValue, TAllocator>
285where
286    TKey: Eq + Hash,
287    TAllocator: Allocator,
288    InnerMap<TKey, TValue, TAllocator>: Eq,
289{
290}
291
292impl<TKey, TValue, TAllocator> Hash for DefaultHashTable<TKey, TValue, TAllocator>
293where
294    TKey: Eq + Hash,
295    TAllocator: Allocator,
296    InnerMap<TKey, TValue, TAllocator>: Hash,
297{
298    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
299        self.inner.hash(state);
300    }
301}
302
303#[cfg(feature = "std")]
304use osom_lib_alloc::std_allocator::StdAllocator;
305
306#[cfg(feature = "std")]
307#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
308/// An alias for [`DefaultHashTable`] with [`StdAllocator`]. Requires `std` feature.
309pub type StdDefaultHashTable<TKey, TValue> = DefaultHashTable<TKey, TValue, StdAllocator>;