refcount_interner/
arc_interner.rs

1use std::sync::Arc;
2use std::hash::Hash;
3use std::collections::HashSet;
4
5/// An interner returning atomically reference-counted pointers to the interned
6/// data
7///
8/// Interned objects will be deallocated when there are no references to them
9/// any more and `shrink_to_fit()` is called on the interner
10///
11/// # Example
12/// ```rust
13/// # use std::sync::Arc;
14/// use refcount_interner::ArcInterner;
15///
16/// let mut interner = ArcInterner::new();
17///
18/// let x = interner.intern(42);
19/// let y = interner.intern(1337);
20///
21/// assert_eq!(*x, 42);
22/// assert_ne!(x, y);
23/// assert!(Arc::ptr_eq(&x, &interner.intern(42)));
24/// ```
25#[derive(Debug)]
26pub struct ArcInterner<T: ?Sized>(HashSet<Arc<T>>);
27
28impl<T: ?Sized> Default for ArcInterner<T> {
29    fn default() -> ArcInterner<T> {
30        ArcInterner(HashSet::new())
31    }
32}
33
34impl<T: ?Sized + Hash + Eq> ArcInterner<T> {
35    /// Create a new, empty interner.
36    ///
37    /// # Example
38    /// ```rust
39    /// # use refcount_interner::ArcInterner;
40    /// let mut interner = ArcInterner::new();
41    /// # let x = interner.intern(42);
42    /// ```
43    pub fn new() -> ArcInterner<T> {
44        Default::default()
45    }
46
47    /// Attempt to get a reference to an already interned object.
48    ///
49    /// If the object has already been interned, an option containing a
50    /// reference to the already interned object will be returned.
51    ///
52    /// If the object has not yet been interned, `None` will be returned.
53    ///
54    /// # Example
55    /// ```rust
56    /// # use std::sync::Arc;
57    /// # use refcount_interner::ArcInterner;
58    /// let mut interner = ArcInterner::new();
59    ///
60    /// let x = interner.intern(42);
61    /// assert_eq!(interner.try_intern(&42), Some(Arc::new(42)));
62    /// assert_eq!(interner.try_intern(&1337), None);
63    /// ```
64    pub fn try_intern(&self, t: &T) -> Option<Arc<T>> {
65        self.0.get(t).cloned()
66    }
67
68    /// Intern a boxed object
69    ///
70    /// This method must be used to intern unsized types, since unsized types
71    /// cannot be passed to `intern()`. The two most common unsized types,
72    /// `&[T]` and `&str` can be interned with `intern_slice()` and
73    /// `intern_str()` as well.
74    ///
75    /// If the object has already been interned, the passed object will be
76    /// dropped and deallocated, and a reference to the already interned object
77    /// will be returned.
78    ///
79    /// If the object has not yet been interned, the passed object will be moved
80    /// into an `Arc<T>`, remembered for future calls to `intern()`, and
81    /// returned.
82    ///
83    /// # Example
84    /// ```rust
85    /// # use refcount_interner::ArcInterner;
86    /// let mut interner = ArcInterner::new();
87    ///
88    /// let x = Box::new(42);
89    /// let y = interner.intern_boxed(x);
90    ///
91    /// assert_eq!(*y, 42);
92    /// ```
93    pub fn intern_boxed(&mut self, t: Box<T>) -> Arc<T> {
94        if let Some(value) = self.0.get(t.as_ref()) {
95            value.clone()
96        } else {
97            let value: Arc<T> = Arc::from(t);
98            self.0.insert(value.clone());
99            value
100        }
101    }
102
103    /// Deallocate all interned objects that are no longer referenced and shrink
104    /// the internal storage to fit.
105    ///
106    /// # Example
107    /// ```rust
108    /// # use std::sync::Arc;
109    /// # use refcount_interner::ArcInterner;
110    /// let mut interner = ArcInterner::new();
111    ///
112    /// let x = interner.intern(42);
113    /// let y = interner.intern(1337);
114    /// let z = y.clone();
115    ///
116    /// drop(x);
117    /// drop(y);
118    ///
119    /// interner.shrink_to_fit();
120    /// assert_eq!(interner.try_intern(&42), None);
121    /// assert_eq!(interner.try_intern(&1337), Some(Arc::new(1337)));
122    /// ```
123    pub fn shrink_to_fit(&mut self) {
124        self.0.retain(|value| Arc::strong_count(value) > 1);
125        self.0.shrink_to_fit();
126    }
127}
128
129impl<T: Sized + Hash + Eq> ArcInterner<T> {
130    /// Intern an owned object
131    ///
132    /// If the object has already been interned, the passed object will be
133    /// dropped, and a reference to the already interned object will be
134    /// returned.
135    ///
136    /// If the object has not yet been interned, the passed object will be moved
137    /// into an `Arc<T>`, remembered for future calls to `intern()`, and
138    /// returned.
139    ///
140    /// # Example
141    /// ```rust
142    /// # use std::sync::Arc;
143    /// # use refcount_interner::ArcInterner;
144    /// let mut interner = ArcInterner::new();
145    ///
146    /// let x = interner.intern(42);
147    /// let y = interner.intern(1337);
148    ///
149    /// assert_eq!(*x, 42);
150    /// assert_ne!(x, y);
151    /// assert!(Arc::ptr_eq(&x, &interner.intern(42)));
152    /// ```
153    pub fn intern(&mut self, t: T) -> Arc<T> {
154        if let Some(value) = self.0.get(&t) {
155            value.clone()
156        } else {
157            let value = Arc::new(t);
158            self.0.insert(value.clone());
159            value
160        }
161    }
162}
163
164impl<T: Sized + Hash + Eq + Clone> ArcInterner<T> {
165    /// Intern a borrowed object, cloning if it has not yet been interned
166    ///
167    /// If the object has already been interned, a reference to the already
168    /// interned object will be returned.
169    ///
170    /// If the object has not yet been interned, the passed object will be moved
171    /// into an `Arc<T>`, remembered for future calls to `intern()`, and
172    /// returned.
173    ///
174    /// # Example
175    /// ```rust
176    /// # use refcount_interner::ArcInterner;
177    /// let mut interner = ArcInterner::new();
178    ///
179    /// let x = 42;
180    /// let y = interner.intern_cloned(&x);
181    ///
182    /// assert_eq!(x, *y);
183    /// ```
184    pub fn intern_cloned(&mut self, t: &T) -> Arc<T> {
185        if let Some(value) = self.0.get(t) {
186            value.clone()
187        } else {
188            let value = Arc::new(t.clone());
189            self.0.insert(value.clone());
190            value
191        }
192    }
193}
194
195impl<T: Sized + Hash + Eq + Clone> ArcInterner<[T]> {
196    /// Intern a slice object
197    ///
198    /// This method can be used to intern slices without boxing them.
199    ///
200    /// If the slice has already been interned, a reference to the already
201    /// interned slice will be returned.
202    ///
203    /// If the slice has not yet been interned, the passed object will be
204    /// cloned into an `Arc<[T]>`, remembered for future calls to `intern()`,
205    /// and returned.
206    ///
207    /// # Example
208    /// ```rust
209    /// # use refcount_interner::ArcInterner;
210    /// let mut interner = ArcInterner::new();
211    ///
212    /// let x = interner.intern_slice(&[1, 2, 3]);
213    ///
214    /// assert_eq!(x.as_ref(), &[1, 2, 3]);
215    /// ```
216    pub fn intern_slice(&mut self, t: &[T]) -> Arc<[T]> {
217        if let Some(value) = self.0.get(t) {
218            value.clone()
219        } else {
220            let value: Arc<[T]> = Arc::from(t);
221            self.0.insert(value.clone());
222            value
223        }
224    }
225
226    /// Intern an owned vector
227    ///
228    /// If the slice behind the vector has already been interned, a reference
229    /// to the already / interned slice will be returned.
230    ///
231    /// If the slice has not yet been interned, the passed vector will be moved
232    /// into an `Arc<[T]>`, remembered for future calls to `intern()`, and
233    /// returned.
234    ///
235    /// # Example
236    /// ```rust
237    ///
238    /// # use refcount_interner::ArcInterner;
239    /// let mut interner = ArcInterner::new();
240    ///
241    /// let v = vec![1, 2, 3];
242    /// let x = interner.intern_vec(v);
243    ///
244    /// assert_eq!(x.as_ref(), &[1, 2, 3]);
245    /// ```
246    pub fn intern_vec(&mut self, t: Vec<T>) -> Arc<[T]> {
247        self.intern_boxed(t.into_boxed_slice())
248    }
249}
250
251impl ArcInterner<str> {
252    /// Intern a string slice
253    ///
254    /// This method can be used to intern string slices without boxing them.
255    ///
256    /// If the string slice has already been interned, a reference to the
257    /// already interned string slice will be returned.
258    ///
259    /// If the string slice has not yet been interned, the passed object will be
260    /// cloned into an `Arc<str>`, remembered for future calls to `intern()`,
261    /// and returned.
262    ///
263    /// # Example
264    /// ```rust
265    /// # use refcount_interner::ArcInterner;
266    /// let mut interner = ArcInterner::new();
267    ///
268    /// let x = interner.intern_str("hello");
269    ///
270    /// assert_eq!(x.as_ref(), "hello");
271    /// ```
272    pub fn intern_str(&mut self, t: &str) -> Arc<str> {
273        if let Some(value) = self.0.get(t) {
274            value.clone()
275        } else {
276            let value: Arc<str> = Arc::from(t);
277            self.0.insert(value.clone());
278            value
279        }
280    }
281
282    /// Intern an owned string
283    ///
284    /// If the string has already been interned, a reference to the already
285    /// interned string slice will be returned.
286    ///
287    /// If the string has not yet been interned, the passed string will be moved
288    /// into an `Arc<str>`, remembered for future calls to `intern()`, and
289    /// returned.
290    ///
291    /// # Example
292    /// ```rust
293    ///
294    /// # use refcount_interner::ArcInterner;
295    /// let mut interner = ArcInterner::new();
296    ///
297    /// let s = String::from("hello");
298    /// let x = interner.intern_string(s);
299    ///
300    /// assert_eq!(x.as_ref(), "hello");
301    /// ```
302    pub fn intern_string(&mut self, t: String) -> Arc<str> {
303        self.intern_boxed(t.into_boxed_str())
304    }
305}