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}