1use hashbrown::{
5 DefaultHashBuilder, HashTable, TryReserveError,
6 hash_table::{Entry as RawEntry, Iter as RawIter},
7};
8
9use crate::{Allocator, Ephemeron, Finalize, Gc, GcRef, GcRefCell, Trace, custom_trace};
10use std::{fmt, hash::BuildHasher, marker::PhantomData};
11
12#[derive(Clone, Debug, Default, Finalize)]
14pub struct WeakMap<K: Trace + ?Sized + 'static, V: Trace + 'static> {
15 pub(crate) inner: Gc<GcRefCell<RawWeakMap<K, V>>>,
16}
17
18unsafe impl<K: Trace + ?Sized + 'static, V: Trace + 'static> Trace for WeakMap<K, V> {
19 custom_trace!(this, mark, {
20 mark(&this.inner);
21 });
22}
23
24impl<K: Trace + ?Sized, V: Trace> WeakMap<K, V> {
25 #[must_use]
27 #[inline]
28 pub fn new() -> Self {
29 Allocator::alloc_weak_map()
30 }
31
32 #[inline]
34 pub fn insert(&mut self, key: &Gc<K>, value: V) {
35 self.inner.borrow_mut().insert(key, value);
36 }
37
38 #[inline]
41 pub fn remove(&mut self, key: &Gc<K>) -> bool {
42 self.inner.borrow_mut().remove(key)
43 }
44
45 #[must_use]
47 #[inline]
48 pub fn contains_key(&self, key: &Gc<K>) -> bool {
49 self.inner.borrow().contains_key(key)
50 }
51
52 #[must_use]
54 #[inline]
55 pub fn get<'a>(&'a self, key: &Gc<K>) -> Option<GcRef<'a, Ephemeron<K, V>>> {
56 GcRef::try_map(self.inner.borrow(), |inner| inner.get(key))
57 }
58}
59
60pub(crate) struct RawWeakMap<K, V, S = DefaultHashBuilder>
66where
67 K: Trace + ?Sized + 'static,
68 V: Trace + 'static,
69{
70 hash_builder: S,
71 table: HashTable<Ephemeron<K, V>>,
72}
73
74impl<K, V, S> Finalize for RawWeakMap<K, V, S>
75where
76 K: Trace + ?Sized + 'static,
77 V: Trace + 'static,
78{
79}
80
81unsafe impl<K, V, S> Trace for RawWeakMap<K, V, S>
83where
84 K: Trace + ?Sized + 'static,
85 V: Trace + 'static,
86{
87 custom_trace!(this, mark, {
88 for eph in this.iter() {
89 mark(eph);
90 }
91 });
92}
93
94impl<K, V, S> Default for RawWeakMap<K, V, S>
95where
96 S: Default,
97 K: Trace + ?Sized + 'static,
98 V: Trace + 'static,
99{
100 fn default() -> Self {
101 Self::with_hasher(Default::default())
102 }
103}
104
105impl<K, V> RawWeakMap<K, V, DefaultHashBuilder>
106where
107 K: Trace + ?Sized + 'static,
108 V: Trace + 'static,
109{
110 pub(crate) fn new() -> Self {
115 Self::default()
116 }
117
118 #[allow(unused)]
123 pub(crate) fn with_capacity(capacity: usize) -> Self {
124 Self::with_capacity_and_hasher(capacity, DefaultHashBuilder::default())
125 }
126}
127
128impl<K, V, S> RawWeakMap<K, V, S>
129where
130 K: Trace + ?Sized + 'static,
131 V: Trace + 'static,
132{
133 pub(crate) const fn with_hasher(hash_builder: S) -> Self {
139 Self {
140 hash_builder,
141 table: HashTable::new(),
142 }
143 }
144
145 pub(crate) fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self {
151 Self {
152 hash_builder,
153 table: HashTable::with_capacity(capacity),
154 }
155 }
156
157 #[allow(unused)]
159 pub(crate) const fn hasher(&self) -> &S {
160 &self.hash_builder
161 }
162
163 #[allow(unused)]
168 pub(crate) fn capacity(&self) -> usize {
169 self.table.capacity()
170 }
171
172 pub(crate) fn iter(&self) -> Iter<'_, K, V> {
175 Iter {
176 inner: self.table.iter(),
177 marker: PhantomData,
178 }
179 }
180
181 #[allow(unused)]
186 pub(crate) fn len(&self) -> usize {
187 self.table.len()
188 }
189
190 #[allow(unused)]
195 pub(crate) fn is_empty(&self) -> bool {
196 self.len() == 0
197 }
198
199 pub(crate) fn retain<F>(&mut self, mut f: F)
206 where
207 F: FnMut(&Ephemeron<K, V>) -> bool,
208 {
209 self.table.retain(|item| f(item));
213 }
214
215 #[allow(unused)]
218 pub(crate) fn clear(&mut self) {
219 self.table.clear();
220 }
221}
222
223impl<K, V, S> RawWeakMap<K, V, S>
224where
225 K: Trace + ?Sized + 'static,
226 V: Trace + 'static,
227 S: BuildHasher,
228{
229 #[allow(unused)]
239 pub(crate) fn reserve(&mut self, additional: usize) {
240 self.table
241 .reserve(additional, make_hasher(&self.hash_builder));
242 }
243
244 #[allow(unused)]
253 pub(crate) fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
254 self.table
255 .try_reserve(additional, make_hasher(&self.hash_builder))
256 }
257
258 #[allow(unused)]
262 pub(crate) fn shrink_to_fit(&mut self) {
263 self.table
264 .shrink_to(0, make_hasher::<_, V, S>(&self.hash_builder));
265 }
266
267 #[allow(unused)]
274 pub(crate) fn shrink_to(&mut self, min_capacity: usize) {
275 self.table
276 .shrink_to(min_capacity, make_hasher::<_, V, S>(&self.hash_builder));
277 }
278
279 pub(crate) fn get(&self, k: &Gc<K>) -> Option<&Ephemeron<K, V>> {
281 if self.table.is_empty() {
282 None
283 } else {
284 let hash = make_hash_from_gc(&self.hash_builder, k);
285 self.table.find(hash, equivalent_key(k))
286 }
287 }
288
289 pub(crate) fn contains_key(&self, k: &Gc<K>) -> bool {
291 self.get(k).is_some()
292 }
293
294 pub(crate) fn insert(&mut self, k: &Gc<K>, v: V) -> Option<Ephemeron<K, V>> {
301 let hash = make_hash_from_gc(&self.hash_builder, k);
302 let hasher = make_hasher(&self.hash_builder);
303 let entry = self.table.entry(hash, equivalent_key(k), hasher);
304 let (old, slot) = match entry {
305 RawEntry::Occupied(occupied_entry) => {
306 let (v, slot) = occupied_entry.remove();
307 (Some(v), slot)
308 }
309 RawEntry::Vacant(vacant_entry) => (None, vacant_entry),
310 };
311
312 slot.insert(Ephemeron::new(k, v));
313 old
314 }
315
316 pub(crate) fn remove(&mut self, k: &Gc<K>) -> bool {
319 let hash = make_hash_from_gc(&self.hash_builder, k);
320 if let Ok(entry) = self.table.find_entry(hash, equivalent_key(k)) {
321 entry.remove();
322 true
323 } else {
324 false
325 }
326 }
327
328 pub(crate) fn clear_expired(&mut self) {
330 self.retain(|eph| eph.value().is_some());
331 }
332}
333
334pub(crate) struct Iter<'a, K, V>
335where
336 K: Trace + ?Sized + 'static,
337 V: Trace + 'static,
338{
339 inner: RawIter<'a, Ephemeron<K, V>>,
340 marker: PhantomData<&'a Ephemeron<K, V>>,
341}
342
343impl<K, V> Clone for Iter<'_, K, V>
344where
345 K: Trace + ?Sized + 'static,
346 V: Trace + 'static,
347{
348 #[inline]
349 fn clone(&self) -> Self {
350 Iter {
351 inner: self.inner.clone(),
352 marker: PhantomData,
353 }
354 }
355}
356
357impl<K, V> fmt::Debug for Iter<'_, K, V>
358where
359 K: Trace + ?Sized + 'static + fmt::Debug,
360 V: Trace + 'static + fmt::Debug,
361{
362 #[inline]
363 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364 f.debug_list().entries(self.clone()).finish()
365 }
366}
367
368impl<'a, K, V> Iterator for Iter<'a, K, V>
369where
370 K: Trace + ?Sized + 'static,
371 V: Trace + 'static,
372{
373 type Item = &'a Ephemeron<K, V>;
374
375 #[inline]
376 fn next(&mut self) -> Option<Self::Item> {
377 self.inner.next()
378 }
379
380 #[inline]
381 fn size_hint(&self) -> (usize, Option<usize>) {
382 self.inner.size_hint()
383 }
384}
385
386impl<K, V, S> fmt::Debug for RawWeakMap<K, V, S>
387where
388 K: fmt::Debug + ?Sized + Trace + Finalize,
389 V: fmt::Debug + Trace + Finalize,
390{
391 #[inline]
392 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393 self.iter().fmt(f)
394 }
395}
396
397fn make_hasher<K, V, S>(hash_builder: &S) -> impl Fn(&Ephemeron<K, V>) -> u64 + '_
398where
399 S: BuildHasher,
400 K: Trace + ?Sized + 'static,
401 V: Trace + 'static,
402{
403 move |val| make_hash_from_eph::<K, V, S>(hash_builder, val)
404}
405
406fn make_hash_from_eph<K, V, S>(hash_builder: &S, eph: &Ephemeron<K, V>) -> u64
407where
408 S: BuildHasher,
409 K: Trace + ?Sized + 'static,
410 V: Trace + 'static,
411{
412 use std::hash::Hasher;
413 let mut state = hash_builder.build_hasher();
414 unsafe {
418 if let Some(val) = eph.inner().key() {
419 std::ptr::hash(val, &mut state);
420 } else {
421 std::ptr::hash(eph.inner_ptr().as_ptr(), &mut state);
422 }
423 }
424 state.finish()
425}
426
427fn make_hash_from_gc<K, S>(hash_builder: &S, gc: &Gc<K>) -> u64
428where
429 S: BuildHasher,
430 K: Trace + ?Sized + 'static,
431{
432 use std::hash::Hasher;
433 let mut state = hash_builder.build_hasher();
434 std::ptr::hash(gc.inner_ptr().as_ptr(), &mut state);
435 state.finish()
436}
437
438fn equivalent_key<K, V>(k: &Gc<K>) -> impl Fn(&Ephemeron<K, V>) -> bool + '_
439where
440 K: Trace + ?Sized + 'static,
441 V: Trace + 'static,
442{
443 move |eph| unsafe {
446 eph.inner().key().is_some_and(|val| {
447 let val: *const _ = val;
448 std::ptr::eq(val, k.inner_ptr().as_ptr())
449 })
450 }
451}