]>
Commit | Line | Data |
---|---|---|
5e7ed085 | 1 | use crate::stable_hasher::{HashStable, StableHasher}; |
5099ac24 FG |
2 | use std::cmp::Ordering; |
3 | use std::hash::{Hash, Hasher}; | |
4 | use std::ops::Deref; | |
5 | use std::ptr; | |
6 | ||
7 | mod private { | |
8 | #[derive(Clone, Copy, Debug)] | |
9 | pub struct PrivateZst; | |
10 | } | |
11 | ||
12 | /// A reference to a value that is interned, and is known to be unique. | |
13 | /// | |
14 | /// Note that it is possible to have a `T` and a `Interned<T>` that are (or | |
15 | /// refer to) equal but different values. But if you have two different | |
16 | /// `Interned<T>`s, they both refer to the same value, at a single location in | |
17 | /// memory. This means that equality and hashing can be done on the value's | |
18 | /// address rather than the value's contents, which can improve performance. | |
19 | /// | |
20 | /// The `PrivateZst` field means you can pattern match with `Interned(v, _)` | |
21 | /// but you can only construct a `Interned` with `new_unchecked`, and not | |
22 | /// directly. | |
23 | #[derive(Debug)] | |
5e7ed085 | 24 | #[rustc_pass_by_value] |
5099ac24 FG |
25 | pub struct Interned<'a, T>(pub &'a T, pub private::PrivateZst); |
26 | ||
27 | impl<'a, T> Interned<'a, T> { | |
28 | /// Create a new `Interned` value. The value referred to *must* be interned | |
29 | /// and thus be unique, and it *must* remain unique in the future. This | |
30 | /// function has `_unchecked` in the name but is not `unsafe`, because if | |
31 | /// the uniqueness condition is violated condition it will cause incorrect | |
32 | /// behaviour but will not affect memory safety. | |
33 | #[inline] | |
34 | pub const fn new_unchecked(t: &'a T) -> Self { | |
35 | Interned(t, private::PrivateZst) | |
36 | } | |
37 | } | |
38 | ||
39 | impl<'a, T> Clone for Interned<'a, T> { | |
40 | fn clone(&self) -> Self { | |
41 | *self | |
42 | } | |
43 | } | |
44 | ||
45 | impl<'a, T> Copy for Interned<'a, T> {} | |
46 | ||
47 | impl<'a, T> Deref for Interned<'a, T> { | |
48 | type Target = T; | |
49 | ||
50 | #[inline] | |
51 | fn deref(&self) -> &T { | |
52 | self.0 | |
53 | } | |
54 | } | |
55 | ||
56 | impl<'a, T> PartialEq for Interned<'a, T> { | |
57 | #[inline] | |
58 | fn eq(&self, other: &Self) -> bool { | |
59 | // Pointer equality implies equality, due to the uniqueness constraint. | |
60 | ptr::eq(self.0, other.0) | |
61 | } | |
62 | } | |
63 | ||
64 | impl<'a, T> Eq for Interned<'a, T> {} | |
65 | ||
5e7ed085 | 66 | impl<'a, T: PartialOrd> PartialOrd for Interned<'a, T> { |
5099ac24 | 67 | fn partial_cmp(&self, other: &Interned<'a, T>) -> Option<Ordering> { |
5e7ed085 FG |
68 | // Pointer equality implies equality, due to the uniqueness constraint, |
69 | // but the contents must be compared otherwise. | |
70 | if ptr::eq(self.0, other.0) { | |
71 | Some(Ordering::Equal) | |
72 | } else { | |
73 | let res = self.0.partial_cmp(&other.0); | |
74 | debug_assert_ne!(res, Some(Ordering::Equal)); | |
75 | res | |
76 | } | |
5099ac24 FG |
77 | } |
78 | } | |
79 | ||
80 | impl<'a, T: Ord> Ord for Interned<'a, T> { | |
81 | fn cmp(&self, other: &Interned<'a, T>) -> Ordering { | |
82 | // Pointer equality implies equality, due to the uniqueness constraint, | |
83 | // but the contents must be compared otherwise. | |
84 | if ptr::eq(self.0, other.0) { | |
85 | Ordering::Equal | |
86 | } else { | |
87 | let res = self.0.cmp(&other.0); | |
88 | debug_assert_ne!(res, Ordering::Equal); | |
89 | res | |
90 | } | |
91 | } | |
92 | } | |
93 | ||
94 | impl<'a, T> Hash for Interned<'a, T> { | |
95 | #[inline] | |
96 | fn hash<H: Hasher>(&self, s: &mut H) { | |
97 | // Pointer hashing is sufficient, due to the uniqueness constraint. | |
98 | ptr::hash(self.0, s) | |
99 | } | |
100 | } | |
101 | ||
5e7ed085 FG |
102 | impl<T, CTX> HashStable<CTX> for Interned<'_, T> |
103 | where | |
104 | T: HashStable<CTX>, | |
105 | { | |
106 | fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { | |
107 | self.0.hash_stable(hcx, hasher); | |
108 | } | |
109 | } | |
110 | ||
5099ac24 FG |
111 | #[cfg(test)] |
112 | mod tests; |