Skip to main content

weak_table/
ptr_weak_weak_hash_map.rs

1//! A hash map where the keys and values are both held by weak pointers, and keys are compared by
2//! pointer.
3
4use crate::common::*;
5use crate::compat::*;
6
7use super::by_ptr::*;
8use super::traits::*;
9use super::weak_weak_hash_map as base;
10
11pub use super::weak_weak_hash_map::{
12    Drain, Entry, ExtractIf, IntoIter, IntoKeys, IntoValues, Iter, Keys, Values,
13};
14pub use super::PtrWeakWeakHashMap;
15
16universal_hashless_members! {
17    PtrWeakWeakHashMap
18    ("`PtrWeakWeakHashMap", a "map")
19    crate::WeakWeakHashMap::with_capacity_and_hasher
20    {K, V}
21}
22
23impl<K: WeakElement, V: WeakElement, S: BuildHasher> PtrWeakWeakHashMap<K, V, S>
24where
25    K::Strong: Deref,
26{
27    universal_key_independent_members! {"mappings"}
28
29    /// Gets the requested entry.
30    ///
31    /// expected *O*(1) time; worst-case *O*(*p*) time
32    pub fn entry(&mut self, key: K::Strong) -> Entry<'_, ByPtr<K>, V> {
33        self.0.entry(key)
34    }
35
36    /// Returns a reference to the value corresponding to the key.
37    ///
38    /// Returns `None` if no matching key is found.
39    ///
40    /// expected *O*(1) time; worst-case *O*(*p*) time
41    pub fn get(&self, key: &K::Strong) -> Option<V::Strong> {
42        self.0.get(&(key.deref() as *const _))
43    }
44
45    /// Returns true if the map contains the specified key.
46    ///
47    /// expected *O*(1) time; worst-case *O*(*p*) time
48    pub fn contains_key(&self, key: &K::Strong) -> bool {
49        self.0.contains_key(&(key.deref() as *const _))
50    }
51
52    /// Unconditionally inserts the value, returning the old value if already present. Does not
53    /// replace the key.
54    ///
55    /// expected *O*(1) time; worst-case *O*(*p*) time
56    pub fn insert(&mut self, key: K::Strong, value: V::Strong) -> Option<V::Strong> {
57        self.0.insert(key, value)
58    }
59
60    /// Removes the entry with the given key, if it exists, and returns the value.
61    ///
62    /// expected *O*(1) time; worst-case *O*(*p*) time
63    pub fn remove(&mut self, key: &K::Strong) -> Option<V::Strong> {
64        self.0.remove(&(key.deref() as *const _))
65    }
66
67    /// Removes all mappings not satisfying the given predicate.
68    ///
69    /// Also removes any expired mappings.
70    ///
71    /// *O*(*n*) time
72    pub fn retain<F>(&mut self, f: F)
73    where
74        F: FnMut(K::Strong, V::Strong) -> bool,
75    {
76        self.0.retain(f);
77    }
78
79    /// Is this map a submap of the other, using the given value comparison.
80    ///
81    /// In particular, all the keys of self must be in other and the values must compare true with
82    /// value_equal.
83    ///
84    /// expected *O*(*n*) time; worst-case *O*(*nq*) time (where *n* is
85    /// `self.capacity()` and *q* is the length of the probe sequences
86    /// in `other`)
87    pub fn submap_with<F, S1, V1>(
88        &self,
89        other: &PtrWeakWeakHashMap<K, V1, S1>,
90        value_equal: F,
91    ) -> bool
92    where
93        F: FnMut(V::Strong, V1::Strong) -> bool,
94        V1: WeakElement,
95        S1: BuildHasher,
96    {
97        self.0.is_submap_with(&other.0, value_equal)
98    }
99
100    /// Is self a submap of other?
101    ///
102    /// expected *O*(*n*) time; worst-case *O*(*nq*) time (where *n* is
103    /// `self.capacity()` and *q* is the length of the probe sequences
104    /// in `other`)
105    pub fn is_submap<V1, S1>(&self, other: &PtrWeakWeakHashMap<K, V1, S1>) -> bool
106    where
107        V1: WeakElement,
108        V::Strong: PartialEq<V1::Strong>,
109        S1: BuildHasher,
110    {
111        self.0.is_submap(&other.0)
112    }
113
114    /// Are the keys of self a subset of the keys of other?
115    ///
116    /// expected *O*(*n*) time; worst-case *O*(*nq*) time (where *n* is
117    /// `self.capacity()` and *q* is the length of the probe sequences
118    /// in `other`)
119    pub fn domain_is_subset<V1, S1>(&self, other: &PtrWeakWeakHashMap<K, V1, S1>) -> bool
120    where
121        V1: WeakElement,
122        S1: BuildHasher,
123    {
124        self.0.domain_is_subset(&other.0)
125    }
126}
127
128impl<K: WeakElement, V: WeakElement, S> PtrWeakWeakHashMap<K, V, S>
129where
130    K::Strong: Deref,
131{
132    /// Gets an iterator over the keys and values.
133    ///
134    /// *O*(1) time
135    pub fn iter(&self) -> Iter<'_, ByPtr<K>, V> {
136        self.0.iter()
137    }
138
139    /// Gets an iterator over the keys.
140    ///
141    /// *O*(1) time
142    pub fn keys(&self) -> Keys<'_, ByPtr<K>, V> {
143        self.0.keys()
144    }
145
146    /// Gets an iterator over the values.
147    ///
148    /// *O*(1) time
149    pub fn values(&self) -> Values<'_, ByPtr<K>, V> {
150        self.0.values()
151    }
152
153    /// Gets a draining iterator, which removes all the values but retains the storage.
154    ///
155    /// *O*(1) time (and *O*(*n*) time to dispose of the result)
156    pub fn drain(&mut self) -> Drain<'_, ByPtr<K>, V> {
157        self.0.drain()
158    }
159
160    ptr_into_kv_methods! {}
161
162    /// Gets an iterator that removes and returns elements matching a given predicate.
163    ///
164    /// Expired elements are also removed.
165    ///
166    /// If this iterator is dropped before it is completed, then no further
167    /// elements are removed.
168    /// (This is in contrast to the behavior of [`drain`](Self::drain)).
169    ///
170    /// *O*(1) time
171    pub fn extract_if<'a, F>(&'a mut self, f: F) -> ExtractIf<'a, ByPtr<K>, V, F>
172    where
173        F: FnMut(K::Strong, V::Strong) -> bool + 'a,
174    {
175        self.0.extract_if(f)
176    }
177}
178
179impl<K, V, V1, S, S1> PartialEq<PtrWeakWeakHashMap<K, V1, S1>> for PtrWeakWeakHashMap<K, V, S>
180where
181    K: WeakElement,
182    K::Strong: Deref,
183    V: WeakElement,
184    V1: WeakElement,
185    V::Strong: PartialEq<V1::Strong>,
186    S: BuildHasher,
187    S1: BuildHasher,
188{
189    fn eq(&self, other: &PtrWeakWeakHashMap<K, V1, S1>) -> bool {
190        self.0 == other.0
191    }
192}
193
194impl<K: WeakElement, V: WeakElement, S: BuildHasher> Eq for PtrWeakWeakHashMap<K, V, S>
195where
196    K::Strong: Deref,
197    V::Strong: Eq,
198{
199}
200
201impl<K, V, S> FromIterator<(K::Strong, V::Strong)> for PtrWeakWeakHashMap<K, V, S>
202where
203    K: WeakElement,
204    K::Strong: Deref,
205    V: WeakElement,
206    S: BuildHasher + Default,
207{
208    fn from_iter<T: IntoIterator<Item = (K::Strong, V::Strong)>>(iter: T) -> Self {
209        PtrWeakWeakHashMap(base::WeakWeakHashMap::<ByPtr<K>, V, S>::from_iter(iter))
210    }
211}
212
213#[cfg(any(test, feature = "std", feature = "ahash"))]
214impl<K, V, const N: usize> From<[(K::Strong, V::Strong); N]>
215    for PtrWeakWeakHashMap<K, V, RandomState>
216where
217    K: WeakElement,
218    K::Strong: Deref,
219    V: WeakElement,
220{
221    /// Converts an array of key-value pairs into a map.
222    ///
223    /// If any entries in the array have equal keys,
224    /// all but one of the corresponding values will be dropped.
225    fn from(value: [(K::Strong, V::Strong); N]) -> Self {
226        Self::from_iter(value)
227    }
228}
229
230impl<K, V, S> Extend<(K::Strong, V::Strong)> for PtrWeakWeakHashMap<K, V, S>
231where
232    K: WeakElement,
233    K::Strong: Deref,
234    V: WeakElement,
235    S: BuildHasher,
236{
237    fn extend<T: IntoIterator<Item = (K::Strong, V::Strong)>>(&mut self, iter: T) {
238        self.0.extend(iter);
239    }
240}
241
242impl<K, V, S> Debug for PtrWeakWeakHashMap<K, V, S>
243where
244    K: WeakElement,
245    K::Strong: Debug,
246    V: WeakElement,
247    V::Strong: Debug,
248{
249    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
250        self.0.fmt(f)
251    }
252}
253
254impl<K: WeakElement, V: WeakElement, S> IntoIterator for PtrWeakWeakHashMap<K, V, S> {
255    type Item = (K::Strong, V::Strong);
256    type IntoIter = IntoIter<ByPtr<K>, V>;
257
258    /// Creates an owning iterator from `self`.
259    ///
260    /// *O*(1) time (and *O*(*n*) time to dispose of the result)
261    fn into_iter(self) -> Self::IntoIter {
262        self.0.into_iter()
263    }
264}
265
266impl<'a, K: WeakElement, V: WeakElement, S> IntoIterator for &'a PtrWeakWeakHashMap<K, V, S> {
267    type Item = (K::Strong, V::Strong);
268    type IntoIter = Iter<'a, ByPtr<K>, V>;
269
270    /// Creates a borrowing iterator from `self`.
271    ///
272    /// *O*(1) time
273    fn into_iter(self) -> Self::IntoIter {
274        (&self.0).into_iter()
275    }
276}
277
278#[cfg(test)]
279mod test {
280    #![allow(clippy::print_stderr)]
281    // TODO 050: remove.
282    #![cfg_attr(feature = "ahash", allow(deprecated))]
283
284    use super::{Entry, PtrWeakWeakHashMap};
285    use crate::{
286        compat::{
287            eprintln, format,
288            rc::{Rc, Weak},
289            Vec,
290        },
291        tests::util::VecDebugAsMap,
292    };
293
294    crate::tests::common::empty_constructor_tests! {PtrWeakWeakHashMap<Weak<u32>, Weak<u32>>}
295
296    //    fn show_me(weakmap: &PtrWeakWeakHashMap<Weak<u32>, Weak<f32>>) {
297    //        for (key, _) in weakmap {
298    //            eprint!(" {:2}", *key);
299    //        }
300    //        eprintln!();
301    //    }
302
303    // From https://github.com/tov/weak-table-rs/issues/1#issuecomment-461858060
304    #[test]
305    fn insert_and_check() {
306        let mut rcs: Vec<(Rc<u32>, Rc<f32>)> = Vec::new();
307
308        for i in 0..200 {
309            rcs.push((Rc::new(i), Rc::new(i as f32 + 0.1)));
310        }
311
312        let mut weakmap: PtrWeakWeakHashMap<Weak<u32>, Weak<f32>> = PtrWeakWeakHashMap::new();
313
314        for (key, value) in rcs.iter().cloned() {
315            weakmap.insert(key, value);
316            //            show_me(&weakmap);
317        }
318
319        let mut count = 0;
320
321        for (key, value) in &rcs {
322            assert!(weakmap.contains_key(key));
323
324            match weakmap.entry(Rc::clone(key)) {
325                Entry::Occupied(occ) => {
326                    assert_eq!(occ.get(), value);
327                    count += 1;
328                }
329                Entry::Vacant(_) => {
330                    eprintln!("PointerWeakWeakHashMap: missing: {}", *key);
331                }
332            }
333        }
334
335        assert_eq!(count, rcs.len());
336    }
337
338    #[test]
339    fn debug_map() {
340        let rcs: Vec<Rc<u32>> = (0..20).map(Rc::new).collect();
341        let map: PtrWeakWeakHashMap<Weak<u32>, Weak<u32>> =
342            rcs.iter().map(|n| (n.clone(), n.clone())).collect();
343        let vec: VecDebugAsMap<_, _> = map.iter().collect();
344        assert_eq!(format!("{map:?}"), format!("{vec:?}"));
345    }
346
347    #[test]
348    fn is_submap() {
349        let mut zero_rcs: Vec<Rc<u32>> = (0..50).map(|_| Rc::new(0)).collect();
350        let rcs: Vec<Rc<u32>> = (0..50).map(Rc::new).collect();
351
352        let weakmap: PtrWeakWeakHashMap<Weak<u32>, Weak<u32>> = zero_rcs
353            .iter()
354            .zip(rcs.iter())
355            .take(25)
356            .map(|(k, v)| (k.clone(), v.clone()))
357            .collect();
358        let mut weakmap2 = weakmap.clone();
359
360        assert!(weakmap.is_submap(&weakmap2));
361        assert!(weakmap2.is_submap(&weakmap));
362
363        weakmap2.extend(
364            zero_rcs
365                .iter()
366                .zip(rcs.iter())
367                .skip(25)
368                .map(|(k, v)| (k.clone(), v.clone())),
369        );
370        assert!(weakmap.is_submap(&weakmap2));
371        assert!(!weakmap2.is_submap(&weakmap));
372        assert!(weakmap.domain_is_subset(&weakmap2));
373        assert!(!weakmap2.domain_is_subset(&weakmap));
374
375        weakmap2.insert(zero_rcs[0].clone(), rcs[12].clone());
376        assert!(!weakmap.is_submap(&weakmap2));
377        assert!(!weakmap2.is_submap(&weakmap));
378        assert!(weakmap.submap_with(&weakmap2, |_v1, _v2| true));
379        assert!(!weakmap2.submap_with(&weakmap, |_v1, _v2| true));
380
381        let _ = zero_rcs.remove(0);
382        assert!(weakmap.is_submap(&weakmap2));
383    }
384}