evmap/
values.rs

1use left_right::aliasing::{Aliased, DropBehavior};
2use std::borrow::Borrow;
3use std::fmt;
4use std::hash::{BuildHasher, Hash};
5
6/// This value determines when a value-set is promoted from a list to a HashBag.
7const BAG_THRESHOLD: usize = 32;
8
9/// A bag of values for a given key in the evmap.
10#[repr(transparent)]
11pub struct Values<T, S = std::collections::hash_map::RandomState>(
12    pub(crate) ValuesInner<T, S, crate::aliasing::NoDrop>,
13);
14
15impl<T, S> Default for Values<T, S> {
16    fn default() -> Self {
17        Values(ValuesInner::Short(Default::default()))
18    }
19}
20
21impl<T, S> fmt::Debug for Values<T, S>
22where
23    T: fmt::Debug,
24    S: BuildHasher,
25{
26    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
27        self.0.fmt(fmt)
28    }
29}
30
31pub(crate) enum ValuesInner<T, S, D>
32where
33    D: DropBehavior,
34{
35    Short(smallvec::SmallVec<[Aliased<T, D>; 1]>),
36    Long(hashbag::HashBag<Aliased<T, D>, S>),
37}
38
39impl<T, S> From<ValuesInner<T, S, crate::aliasing::NoDrop>> for Values<T, S> {
40    fn from(v: ValuesInner<T, S, crate::aliasing::NoDrop>) -> Self {
41        Values(v)
42    }
43}
44
45impl<T, S, D> fmt::Debug for ValuesInner<T, S, D>
46where
47    D: DropBehavior,
48    T: fmt::Debug,
49    S: BuildHasher,
50{
51    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
52        match self {
53            ValuesInner::Short(ref v) => fmt.debug_set().entries(v.iter()).finish(),
54            ValuesInner::Long(ref v) => fmt.debug_set().entries(v.iter()).finish(),
55        }
56    }
57}
58
59impl<T, S> Values<T, S> {
60    /// Returns the number of values.
61    pub fn len(&self) -> usize {
62        match self.0 {
63            ValuesInner::Short(ref v) => v.len(),
64            ValuesInner::Long(ref v) => v.len(),
65        }
66    }
67
68    /// Returns true if the bag holds no values.
69    pub fn is_empty(&self) -> bool {
70        match self.0 {
71            ValuesInner::Short(ref v) => v.is_empty(),
72            ValuesInner::Long(ref v) => v.is_empty(),
73        }
74    }
75
76    /// Returns the number of values that can be held without reallocating.
77    pub fn capacity(&self) -> usize {
78        match self.0 {
79            ValuesInner::Short(ref v) => v.capacity(),
80            ValuesInner::Long(ref v) => v.capacity(),
81        }
82    }
83
84    /// An iterator visiting all elements in arbitrary order.
85    ///
86    /// The iterator element type is &'a T.
87    pub fn iter(&self) -> ValuesIter<'_, T, S> {
88        match self.0 {
89            ValuesInner::Short(ref v) => ValuesIter(ValuesIterInner::Short(v.iter())),
90            ValuesInner::Long(ref v) => ValuesIter(ValuesIterInner::Long(v.iter())),
91        }
92    }
93
94    /// Returns a guarded reference to _one_ value corresponding to the key.
95    ///
96    /// This is mostly intended for use when you are working with no more than one value per key.
97    /// If there are multiple values stored for this key, there are no guarantees to which element
98    /// is returned.
99    pub fn get_one(&self) -> Option<&T> {
100        match self.0 {
101            ValuesInner::Short(ref v) => v.get(0).map(|v| &**v),
102            ValuesInner::Long(ref v) => v.iter().next().map(|v| &**v),
103        }
104    }
105
106    /// Returns true if a value matching `value` is among the stored values.
107    ///
108    /// The value may be any borrowed form of `T`, but [`Hash`] and [`Eq`] on the borrowed form
109    /// *must* match those for the value type.
110    pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool
111    where
112        Aliased<T, crate::aliasing::NoDrop>: Borrow<Q>,
113        Q: Eq + Hash,
114        T: Eq + Hash,
115        S: BuildHasher,
116    {
117        match self.0 {
118            ValuesInner::Short(ref v) => v.iter().any(|v| v.borrow() == value),
119            ValuesInner::Long(ref v) => v.contains(value) != 0,
120        }
121    }
122
123    #[cfg(test)]
124    fn is_short(&self) -> bool {
125        matches!(self.0, ValuesInner::Short(_))
126    }
127}
128
129impl<'a, T, S> IntoIterator for &'a Values<T, S> {
130    type IntoIter = ValuesIter<'a, T, S>;
131    type Item = &'a T;
132    fn into_iter(self) -> Self::IntoIter {
133        self.iter()
134    }
135}
136
137pub struct ValuesIter<'a, T, S>(ValuesIterInner<'a, T, S>);
138
139#[non_exhaustive]
140enum ValuesIterInner<'a, T, S> {
141    Short(<&'a smallvec::SmallVec<[Aliased<T, crate::aliasing::NoDrop>; 1]> as IntoIterator>::IntoIter),
142    Long(<&'a hashbag::HashBag<Aliased<T, crate::aliasing::NoDrop>, S> as IntoIterator>::IntoIter),
143}
144
145impl<'a, T, S> fmt::Debug for ValuesIter<'a, T, S>
146where
147    T: fmt::Debug,
148{
149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150        match self.0 {
151            ValuesIterInner::Short(ref it) => f.debug_tuple("Short").field(it).finish(),
152            ValuesIterInner::Long(ref it) => f.debug_tuple("Long").field(it).finish(),
153        }
154    }
155}
156
157impl<'a, T, S> Iterator for ValuesIter<'a, T, S> {
158    type Item = &'a T;
159    fn next(&mut self) -> Option<Self::Item> {
160        match self.0 {
161            ValuesIterInner::Short(ref mut it) => it.next().map(|v| &**v),
162            ValuesIterInner::Long(ref mut it) => it.next().map(|v| &**v),
163        }
164    }
165
166    fn size_hint(&self) -> (usize, Option<usize>) {
167        match self.0 {
168            ValuesIterInner::Short(ref it) => it.size_hint(),
169            ValuesIterInner::Long(ref it) => it.size_hint(),
170        }
171    }
172}
173
174impl<'a, T, S> ExactSizeIterator for ValuesIter<'a, T, S>
175where
176    <&'a smallvec::SmallVec<[T; 1]> as IntoIterator>::IntoIter: ExactSizeIterator,
177    <&'a hashbag::HashBag<T, S> as IntoIterator>::IntoIter: ExactSizeIterator,
178{
179}
180
181impl<'a, T, S> std::iter::FusedIterator for ValuesIter<'a, T, S>
182where
183    <&'a smallvec::SmallVec<[T; 1]> as IntoIterator>::IntoIter: std::iter::FusedIterator,
184    <&'a hashbag::HashBag<T, S> as IntoIterator>::IntoIter: std::iter::FusedIterator,
185{
186}
187
188impl<T, S, D> ValuesInner<T, S, D>
189where
190    D: DropBehavior,
191    T: Eq + Hash,
192    S: BuildHasher + Clone,
193{
194    pub(crate) fn new() -> Self {
195        ValuesInner::Short(smallvec::SmallVec::new())
196    }
197
198    pub(crate) fn with_capacity_and_hasher(capacity: usize, hasher: &S) -> Self {
199        if capacity > BAG_THRESHOLD {
200            ValuesInner::Long(hashbag::HashBag::with_capacity_and_hasher(
201                capacity,
202                hasher.clone(),
203            ))
204        } else {
205            ValuesInner::Short(smallvec::SmallVec::with_capacity(capacity))
206        }
207    }
208
209    pub(crate) fn shrink_to_fit(&mut self) {
210        match self {
211            ValuesInner::Short(ref mut v) => v.shrink_to_fit(),
212            ValuesInner::Long(ref mut v) => {
213                // here, we actually want to be clever
214                // we want to potentially "downgrade" from a Long to a Short
215                //
216                // NOTE: there may be more than one instance of row in the bag. if there is, we do
217                // not move to a SmallVec. The reason is simple: if we did, we would need to
218                // duplicate those rows again. But, how would we do so safely? If we clone into
219                // both the left and the right map (that is, on both first and second apply), then
220                // we would only free one of them. If we alias the one we have in the hashbag, then
221                // once any instance gets remove from both sides, it'll be freed, which will
222                // invalidate the remaining references.
223                if v.len() < BAG_THRESHOLD && v.len() == v.set_len() {
224                    let mut short = smallvec::SmallVec::with_capacity(v.len());
225                    // NOTE: this drain _must_ have a deterministic iteration order.
226                    // that is, the items must be yielded in the same order regardless of whether
227                    // we are iterating on the left or right map. otherwise, this happens;
228                    //
229                    //   1. after shrink_to_fit, left value is AA*B*, right is B*AA*.
230                    //      X* elements are aliased copies of each other
231                    //   2. swap_remove B (1st); left is AA*B*, right is now A*A
232                    //   3. swap_remove B (2nd); left drops B* and is now AA*, right is A*A
233                    //   4. swap_remove A (1st); left is now A*, right is A*A
234                    //   5. swap_remove A (2nd); left is A*, right drops A* and is now A
235                    //      right dropped A* while A still has it -- no okay!
236                    for (row, n) in v.drain() {
237                        assert_eq!(n, 1);
238                        short.push(row);
239                    }
240                    *self = ValuesInner::Short(short);
241                } else {
242                    v.shrink_to_fit();
243                }
244            }
245        }
246    }
247
248    pub(crate) fn clear(&mut self) {
249        // NOTE: we do _not_ downgrade to Short here -- shrink is for that
250        match self {
251            ValuesInner::Short(ref mut v) => v.clear(),
252            ValuesInner::Long(ref mut v) => v.clear(),
253        }
254    }
255
256    pub(crate) fn swap_remove(&mut self, value: &T) {
257        match self {
258            ValuesInner::Short(ref mut v) => {
259                if let Some(i) = v.iter().position(|v| &**v == value) {
260                    v.swap_remove(i);
261                }
262            }
263            ValuesInner::Long(ref mut v) => {
264                v.remove(value);
265            }
266        }
267    }
268
269    fn baggify(&mut self, capacity: usize, hasher: &S) {
270        if let ValuesInner::Short(ref mut v) = self {
271            let mut long = hashbag::HashBag::with_capacity_and_hasher(capacity, hasher.clone());
272
273            // NOTE: this _may_ drop some values since the bag does not keep duplicates.
274            // that should be fine -- if we drop for the first time, we're dropping
275            // ManuallyDrop, which won't actually drop the aliased values. when we drop for
276            // the second time, we do the actual dropping. since second application has the
277            // exact same original state, this change from short/long should occur exactly
278            // the same.
279            long.extend(v.drain(..));
280            *self = ValuesInner::Long(long);
281        }
282    }
283
284    pub(crate) fn reserve(&mut self, additional: usize, hasher: &S) {
285        match self {
286            ValuesInner::Short(ref mut v) => {
287                let n = v.len() + additional;
288                if n >= BAG_THRESHOLD {
289                    self.baggify(n, hasher);
290                } else {
291                    v.reserve(additional)
292                }
293            }
294            ValuesInner::Long(ref mut v) => v.reserve(additional),
295        }
296    }
297
298    pub(crate) fn push(&mut self, value: Aliased<T, D>, hasher: &S) {
299        match self {
300            ValuesInner::Short(ref mut v) => {
301                // we may want to upgrade to a Long..
302                let n = v.len() + 1;
303                if n >= BAG_THRESHOLD {
304                    self.baggify(n, hasher);
305                    if let ValuesInner::Long(ref mut v) = self {
306                        v.insert(value);
307                    } else {
308                        unreachable!();
309                    }
310                } else {
311                    v.push(value);
312                }
313            }
314            ValuesInner::Long(ref mut v) => {
315                v.insert(value);
316            }
317        }
318    }
319
320    pub(crate) fn retain<F>(&mut self, mut f: F)
321    where
322        F: FnMut(&T) -> bool,
323    {
324        match self {
325            ValuesInner::Short(ref mut v) => v.retain(|v| f(&*v)),
326            ValuesInner::Long(ref mut v) => v.retain(|v, n| if f(v) { n } else { 0 }),
327        }
328    }
329}
330
331impl<T, S> AsRef<Values<T, S>> for ValuesInner<T, S, crate::aliasing::NoDrop> {
332    fn as_ref(&self) -> &Values<T, S> {
333        // safety: Values is #[repr(transparent)]
334        unsafe { &*(self as *const _ as *const Values<T, S>) }
335    }
336}
337
338impl<T, S> ValuesInner<T, S, crate::aliasing::DoDrop>
339where
340    T: Eq + Hash,
341    S: BuildHasher + Clone,
342{
343    pub(crate) unsafe fn alias(
344        other: &ValuesInner<T, S, crate::aliasing::NoDrop>,
345        hasher: &S,
346    ) -> Self {
347        match &other {
348            ValuesInner::Short(s) => {
349                ValuesInner::Short(s.iter().map(|v| v.alias().change_drop()).collect())
350            }
351            ValuesInner::Long(l) => {
352                let mut long = hashbag::HashBag::with_hasher(hasher.clone());
353                long.extend(l.set_iter().map(|(v, n)| (v.alias().change_drop(), n)));
354                ValuesInner::Long(long)
355            }
356        }
357    }
358}
359
360#[cfg(test)]
361mod tests {
362    use super::*;
363    use std::collections::hash_map::RandomState;
364
365    macro_rules! assert_empty {
366        ($x:expr) => {
367            assert_eq!($x.len(), 0);
368            assert!($x.is_empty());
369            assert_eq!($x.iter().count(), 0);
370            assert_eq!($x.into_iter().count(), 0);
371            assert_eq!($x.get_one(), None);
372        };
373    }
374
375    macro_rules! assert_len {
376        ($x:expr, $n:expr) => {
377            assert_eq!($x.len(), $n);
378            assert!(!$x.is_empty());
379            assert_eq!($x.iter().count(), $n);
380            assert_eq!($x.into_iter().count(), $n);
381        };
382    }
383
384    #[test]
385    fn sensible_default() {
386        let v: Values<i32> = Values::default();
387        assert!(v.is_short());
388        assert_eq!(v.capacity(), 1);
389        assert_empty!(v);
390    }
391
392    #[test]
393    fn short_values() {
394        let hasher = RandomState::default();
395        let mut v = Values(ValuesInner::new());
396
397        let values = 0..BAG_THRESHOLD - 1;
398        let len = values.clone().count();
399        for i in values.clone() {
400            v.0.push(Aliased::from(i), &hasher);
401        }
402
403        for i in values.clone() {
404            assert!(v.contains(&i));
405        }
406        assert!(v.is_short());
407        assert_len!(v, len);
408        assert_eq!(v.get_one(), Some(&0));
409
410        v.0.clear();
411
412        assert_empty!(v);
413
414        // clear() should not affect capacity or value type!
415        assert!(v.capacity() > 1);
416        assert!(v.is_short());
417
418        v.0.shrink_to_fit();
419
420        assert_eq!(v.capacity(), 1);
421    }
422
423    #[test]
424    fn long_values() {
425        let hasher = RandomState::default();
426        let mut v = Values(ValuesInner::new());
427
428        let values = 0..BAG_THRESHOLD;
429        let len = values.clone().count();
430        for i in values.clone() {
431            v.0.push(Aliased::from(i), &hasher);
432        }
433
434        for i in values.clone() {
435            assert!(v.contains(&i));
436        }
437        assert!(!v.is_short());
438        assert_len!(v, len);
439        assert!(values.contains(v.get_one().unwrap()));
440
441        v.0.clear();
442
443        assert_empty!(v);
444
445        // clear() should not affect capacity or value type!
446        assert!(v.capacity() > 1);
447        assert!(!v.is_short());
448
449        v.0.shrink_to_fit();
450
451        // Now we have short values!
452        assert!(v.is_short());
453        assert_eq!(v.capacity(), 1);
454    }
455}