elsa/
index_set.rs

1use std::cell::{Cell, UnsafeCell};
2use std::collections::hash_map::RandomState;
3use std::hash::{BuildHasher, Hash};
4use std::iter::FromIterator;
5use std::ops::Index;
6
7use indexmap::IndexSet;
8use stable_deref_trait::StableDeref;
9
10use crate::index_map::Equivalent;
11
12/// Append-only version of `indexmap::IndexSet` where
13/// insertion does not require mutable access
14pub struct FrozenIndexSet<T, S = RandomState> {
15    set: UnsafeCell<IndexSet<T, S>>,
16    /// Eq/Hash implementations can have side-effects, and using Rc it is possible
17    /// for FrozenIndexSet::insert to be called on a key that itself contains the same
18    /// `FrozenIndexSet`, whose `eq` implementation also calls FrozenIndexSet::insert
19    ///
20    /// We use this `in_use` flag to guard against any reentrancy.
21    in_use: Cell<bool>,
22}
23
24// safety: UnsafeCell implies !Sync
25
26impl<T: Eq + Hash> FrozenIndexSet<T> {
27    pub fn new() -> Self {
28        Self::from(IndexSet::new())
29    }
30}
31
32impl<T: Eq + Hash + StableDeref, S: BuildHasher> FrozenIndexSet<T, S> {
33    // these should never return &T
34    // these should never delete any entries
35    //
36    /// If the value exists in the set, returns a reference to the corresponding
37    /// value, otherwise inserts a new entry in the set for that value
38    /// and returns a reference to it.
39    ///
40    /// Existing values are never overwritten.
41    ///
42    /// # Example
43    /// ```
44    /// use elsa::index_set::FrozenIndexSet;
45    /// let set = FrozenIndexSet::new();
46    /// let a_ref = set.insert(Box::new("a"));
47    /// let aa = "a";
48    /// let other_a_ref = unsafe { aa.as_ptr() as *const &str};
49    /// let other_a = Box::new(aa);
50    /// assert!(!std::ptr::eq(a_ref, other_a_ref));
51    /// assert!(std::ptr::eq(a_ref, set.insert(other_a)));
52    /// ```
53    pub fn insert(&self, value: T) -> &T::Target {
54        assert!(!self.in_use.get());
55        self.in_use.set(true);
56        let ret = unsafe {
57            let set = self.set.get();
58            let (index, _was_vacant) = (*set).insert_full(value);
59            &*(*set)[index]
60        };
61        self.in_use.set(false);
62        ret
63    }
64
65    // these should never return &T
66    // these should never delete any entries
67    /// If the key exists in the set, returns a reference to the corresponding
68    /// value and its index, otherwise inserts a new entry in the set for that value
69    /// and returns a reference to it and its index.
70    ///
71    /// Existing values are never overwritten.
72    ///
73    /// # Example
74    /// ```
75    /// use elsa::index_set::FrozenIndexSet;
76    /// let set = FrozenIndexSet::new();
77    /// assert_eq!(set.insert_full(Box::new("a")), (0, &"a"));
78    /// assert_eq!(set.insert_full(Box::new("b")), (1, &"b"));
79    /// ```
80    pub fn insert_full(&self, value: T) -> (usize, &T::Target) {
81        assert!(!self.in_use.get());
82        self.in_use.set(true);
83        let ret = unsafe {
84            let set = self.set.get();
85            let (index, _was_vacant) = (*set).insert_full(value);
86            (index, &*(*set)[index])
87        };
88        self.in_use.set(false);
89        ret
90    }
91
92    // TODO implement in case the standard Entry API gets improved
93    // // TODO avoid double lookup
94    // pub fn entry<Q: ?Sized>(&self, value: &Q) -> Entry<T, Q>
95    //     where Q: Hash + Equivalent<T> + ToOwned<Owned = T>
96    // {
97    //     assert!(!self.in_use.get());
98    //     self.in_use.set(true);
99    //     unsafe {
100    //         let set = self.set.get();
101    //         match (*set).get_full(value) {
102    //             Some((index, reference)) => {
103    //                 Entry::Occupied(OccupiedEntry {
104    //                     index,
105    //                     reference,
106    //                     set: &*set,
107    //                 })
108    //             }
109    //             None => {
110    //                 Entry::Vacant(VacantEntry {
111    //                     value: Cow::Borrowed(value),
112    //                     set: &*set,
113    //                 })
114    //             }
115    //         }
116    //     }
117    // }
118
119    /// Returns a reference to the value passed as argument if present in the set.
120    ///
121    /// # Arguments
122    /// * `k` may be any type that implements [`Equivalent<T>`].
123    ///
124    /// # Examples
125    ///
126    /// ```
127    /// use elsa::index_set::FrozenIndexSet;
128    ///
129    /// let set = FrozenIndexSet::new();
130    /// set.insert(Box::new("a"));
131    /// assert_eq!(set.get(&Box::new("a")), Some(&"a"));
132    /// assert_eq!(set.get(&Box::new("b")), None);
133    /// ```
134    pub fn get<Q>(&self, k: &Q) -> Option<&T::Target>
135    where
136        Q: ?Sized + Hash + Equivalent<T>,
137    {
138        assert!(!self.in_use.get());
139        self.in_use.set(true);
140        let ret = unsafe {
141            let set = self.set.get();
142            (*set).get(k).map(|x| &**x)
143        };
144        self.in_use.set(false);
145        ret
146    }
147
148    /// Returns the index corresponding to the value if present in the set
149    ///
150    /// # Arguments
151    /// * `k` may be any type that implements [`Equivalent<T>`].
152    ///
153    /// # Examples
154    ///
155    /// ```
156    /// use elsa::FrozenIndexSet;
157    ///
158    /// let set = FrozenIndexSet::new();
159    /// set.insert(Box::new("a"));
160    /// assert_eq!(set.get_index_of(&Box::new("a")), Some(0));
161    /// assert_eq!(set.get_index_of(&Box::new("b")), None);
162    /// ```
163    pub fn get_index_of<Q>(&self, k: &Q) -> Option<usize>
164    where
165        Q: ?Sized + Hash + Equivalent<T>,
166    {
167        assert!(!self.in_use.get());
168        self.in_use.set(true);
169        let ret = unsafe {
170            let set = self.set.get();
171            (*set).get_index_of(k)
172        };
173        self.in_use.set(false);
174        ret
175    }
176
177    /// Returns a reference to the value passed as argument if present in the set,
178    /// along with its index
179    ///
180    /// # Arguments
181    /// * `k` may be any type that implements [`Equivalent<T>`].
182    ///
183    /// # Examples
184    ///
185    /// ```
186    /// use elsa::index_set::FrozenIndexSet;
187    ///
188    /// let set = FrozenIndexSet::new();
189    /// set.insert(Box::new("a"));
190    /// assert_eq!(set.get_full(&Box::new("a")), Some((0, &"a")));
191    /// assert_eq!(set.get_full(&Box::new("b")), None);
192    /// ```
193    pub fn get_full<Q>(&self, k: &Q) -> Option<(usize, &T::Target)>
194    where
195        Q: ?Sized + Hash + Equivalent<T>,
196    {
197        assert!(!self.in_use.get());
198        self.in_use.set(true);
199        let ret = unsafe {
200            let set = self.set.get();
201            (*set).get_full(k).map(|(i, x)| (i, &**x))
202        };
203        self.in_use.set(false);
204        ret
205    }
206
207    /// Returns a reference to value at the index passed as argument, if
208    /// present in the set.
209    ///
210    /// # Examples
211    ///
212    /// ```
213    /// use elsa::index_set::FrozenIndexSet;
214    ///
215    /// let set = FrozenIndexSet::new();
216    /// set.insert(Box::new("a"));
217    /// assert_eq!(set.get_index(0), Some(&"a"));
218    /// assert_eq!(set.get_index(1), None);
219    /// ```
220    pub fn get_index(&self, index: usize) -> Option<&T::Target> {
221        assert!(!self.in_use.get());
222        self.in_use.set(true);
223        let ret = unsafe {
224            let set = self.set.get();
225            (*set).get_index(index).map(|r| &**r)
226        };
227        self.in_use.set(false);
228        ret
229    }
230}
231
232impl<T, S> FrozenIndexSet<T, S> {
233    pub fn into_set(self) -> IndexSet<T, S> {
234        self.set.into_inner()
235    }
236
237    /// Get mutable access to the underlying [`IndexSet`].
238    ///
239    /// This is safe, as it requires a `&mut self`, ensuring nothing is using
240    /// the 'frozen' contents.
241    pub fn as_mut(&mut self) -> &mut IndexSet<T, S> {
242        unsafe { &mut *self.set.get() }
243    }
244
245    // TODO add more
246}
247
248impl<T, S> From<IndexSet<T, S>> for FrozenIndexSet<T, S> {
249    fn from(set: IndexSet<T, S>) -> Self {
250        Self {
251            set: UnsafeCell::new(set),
252            in_use: Cell::new(false),
253        }
254    }
255}
256
257impl<T: Eq + Hash + StableDeref, S> Index<usize> for FrozenIndexSet<T, S> {
258    type Output = T::Target;
259    fn index(&self, idx: usize) -> &T::Target {
260        assert!(!self.in_use.get());
261        self.in_use.set(true);
262        let ret = unsafe {
263            let set = self.set.get();
264            &*(*set)[idx]
265        };
266        self.in_use.set(false);
267        ret
268    }
269}
270
271impl<T: Eq + Hash, S: Default + BuildHasher> FromIterator<T> for FrozenIndexSet<T, S> {
272    fn from_iter<U>(iter: U) -> Self
273    where
274        U: IntoIterator<Item = T>,
275    {
276        let set: IndexSet<_, _> = iter.into_iter().collect();
277        set.into()
278    }
279}
280
281impl<T: Eq + Hash, S: Default> Default for FrozenIndexSet<T, S> {
282    fn default() -> Self {
283        Self::from(IndexSet::default())
284    }
285}
286
287impl<K: Clone, V: Clone> Clone for FrozenIndexSet<K, V> {
288    fn clone(&self) -> Self {
289        assert!(!self.in_use.get());
290        self.in_use.set(true);
291        let self_clone = Self {
292            set: unsafe { self.set.get().as_ref().unwrap() }.clone().into(),
293            in_use: Cell::from(false),
294        };
295        self.in_use.set(false);
296        return self_clone;
297    }
298}
299
300impl<T: Hash + Eq, S: BuildHasher> PartialEq for FrozenIndexSet<T, S> {
301    fn eq(&self, other: &Self) -> bool {
302        assert!(!self.in_use.get());
303        assert!(!other.in_use.get());
304        self.in_use.set(true);
305        other.in_use.set(true);
306        let ret = unsafe { self.set.get().as_ref() == other.set.get().as_ref() };
307        self.in_use.set(false);
308        other.in_use.set(false);
309        ret
310    }
311}