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
213impl<K, V, const N: usize> From<[(K::Strong, V::Strong); N]>
214    for PtrWeakWeakHashMap<K, V, RandomState>
215where
216    K: WeakElement,
217    K::Strong: Deref,
218    V: WeakElement,
219{
220    /// Converts an array of key-value pairs into a map.
221    ///
222    /// If any entries in the array have equal keys,
223    /// all but one of the corresponding values will be dropped.
224    fn from(value: [(K::Strong, V::Strong); N]) -> Self {
225        Self::from_iter(value)
226    }
227}
228
229impl<K, V, S> Extend<(K::Strong, V::Strong)> for PtrWeakWeakHashMap<K, V, S>
230where
231    K: WeakElement,
232    K::Strong: Deref,
233    V: WeakElement,
234    S: BuildHasher,
235{
236    fn extend<T: IntoIterator<Item = (K::Strong, V::Strong)>>(&mut self, iter: T) {
237        self.0.extend(iter);
238    }
239}
240
241impl<K, V, S> Debug for PtrWeakWeakHashMap<K, V, S>
242where
243    K: WeakElement,
244    K::Strong: Debug,
245    V: WeakElement,
246    V::Strong: Debug,
247{
248    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
249        self.0.fmt(f)
250    }
251}
252
253impl<K: WeakElement, V: WeakElement, S> IntoIterator for PtrWeakWeakHashMap<K, V, S> {
254    type Item = (K::Strong, V::Strong);
255    type IntoIter = IntoIter<ByPtr<K>, V>;
256
257    /// Creates an owning iterator from `self`.
258    ///
259    /// *O*(1) time (and *O*(*n*) time to dispose of the result)
260    fn into_iter(self) -> Self::IntoIter {
261        self.0.into_iter()
262    }
263}
264
265impl<'a, K: WeakElement, V: WeakElement, S> IntoIterator for &'a PtrWeakWeakHashMap<K, V, S> {
266    type Item = (K::Strong, V::Strong);
267    type IntoIter = Iter<'a, ByPtr<K>, V>;
268
269    /// Creates a borrowing iterator from `self`.
270    ///
271    /// *O*(1) time
272    fn into_iter(self) -> Self::IntoIter {
273        (&self.0).into_iter()
274    }
275}
276
277#[cfg(test)]
278mod test {
279    #![allow(clippy::print_stderr)]
280
281    use super::{Entry, PtrWeakWeakHashMap};
282    use crate::{
283        compat::{
284            eprintln, format,
285            rc::{Rc, Weak},
286            Vec,
287        },
288        tests::util::VecDebugAsMap,
289    };
290
291    crate::tests::common::empty_constructor_tests! {PtrWeakWeakHashMap<Weak<u32>, Weak<u32>>}
292
293    //    fn show_me(weakmap: &PtrWeakWeakHashMap<Weak<u32>, Weak<f32>>) {
294    //        for (key, _) in weakmap {
295    //            eprint!(" {:2}", *key);
296    //        }
297    //        eprintln!();
298    //    }
299
300    // From https://github.com/tov/weak-table-rs/issues/1#issuecomment-461858060
301    #[test]
302    fn insert_and_check() {
303        let mut rcs: Vec<(Rc<u32>, Rc<f32>)> = Vec::new();
304
305        for i in 0..200 {
306            rcs.push((Rc::new(i), Rc::new(i as f32 + 0.1)));
307        }
308
309        let mut weakmap: PtrWeakWeakHashMap<Weak<u32>, Weak<f32>> = PtrWeakWeakHashMap::new();
310
311        for (key, value) in rcs.iter().cloned() {
312            weakmap.insert(key, value);
313            //            show_me(&weakmap);
314        }
315
316        let mut count = 0;
317
318        for (key, value) in &rcs {
319            assert!(weakmap.contains_key(key));
320
321            match weakmap.entry(Rc::clone(key)) {
322                Entry::Occupied(occ) => {
323                    assert_eq!(occ.get(), value);
324                    count += 1;
325                }
326                Entry::Vacant(_) => {
327                    eprintln!("PointerWeakWeakHashMap: missing: {}", *key);
328                }
329            }
330        }
331
332        assert_eq!(count, rcs.len());
333    }
334
335    #[test]
336    fn debug_map() {
337        let rcs: Vec<Rc<u32>> = (0..20).map(Rc::new).collect();
338        let map: PtrWeakWeakHashMap<Weak<u32>, Weak<u32>> =
339            rcs.iter().map(|n| (n.clone(), n.clone())).collect();
340        let vec: VecDebugAsMap<_, _> = map.iter().collect();
341        assert_eq!(format!("{map:?}"), format!("{vec:?}"));
342    }
343
344    #[test]
345    fn is_submap() {
346        let mut zero_rcs: Vec<Rc<u32>> = (0..50).map(|_| Rc::new(0)).collect();
347        let rcs: Vec<Rc<u32>> = (0..50).map(Rc::new).collect();
348
349        let weakmap: PtrWeakWeakHashMap<Weak<u32>, Weak<u32>> = zero_rcs
350            .iter()
351            .zip(rcs.iter())
352            .take(25)
353            .map(|(k, v)| (k.clone(), v.clone()))
354            .collect();
355        let mut weakmap2 = weakmap.clone();
356
357        assert!(weakmap.is_submap(&weakmap2));
358        assert!(weakmap2.is_submap(&weakmap));
359
360        weakmap2.extend(
361            zero_rcs
362                .iter()
363                .zip(rcs.iter())
364                .skip(25)
365                .map(|(k, v)| (k.clone(), v.clone())),
366        );
367        assert!(weakmap.is_submap(&weakmap2));
368        assert!(!weakmap2.is_submap(&weakmap));
369        assert!(weakmap.domain_is_subset(&weakmap2));
370        assert!(!weakmap2.domain_is_subset(&weakmap));
371
372        weakmap2.insert(zero_rcs[0].clone(), rcs[12].clone());
373        assert!(!weakmap.is_submap(&weakmap2));
374        assert!(!weakmap2.is_submap(&weakmap));
375        assert!(weakmap.submap_with(&weakmap2, |_v1, _v2| true));
376        assert!(!weakmap2.submap_with(&weakmap, |_v1, _v2| true));
377
378        let _ = zero_rcs.remove(0);
379        assert!(weakmap.is_submap(&weakmap2));
380    }
381}