]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_data_structures/src/tagged_ptr/copy.rs
New upstream version 1.59.0+dfsg1
[rustc.git] / compiler / rustc_data_structures / src / tagged_ptr / copy.rs
1 use super::{Pointer, Tag};
2 use crate::stable_hasher::{HashStable, StableHasher};
3 use std::fmt;
4 use std::marker::PhantomData;
5 use std::num::NonZeroUsize;
6
7 /// A `Copy` TaggedPtr.
8 ///
9 /// You should use this instead of the `TaggedPtr` type in all cases where
10 /// `P: Copy`.
11 ///
12 /// If `COMPARE_PACKED` is true, then the pointers will be compared and hashed without
13 /// unpacking. Otherwise we don't implement PartialEq/Eq/Hash; if you want that,
14 /// wrap the TaggedPtr.
15 pub struct CopyTaggedPtr<P, T, const COMPARE_PACKED: bool>
16 where
17 P: Pointer,
18 T: Tag,
19 {
20 packed: NonZeroUsize,
21 data: PhantomData<(P, T)>,
22 }
23
24 impl<P, T, const COMPARE_PACKED: bool> Copy for CopyTaggedPtr<P, T, COMPARE_PACKED>
25 where
26 P: Pointer,
27 T: Tag,
28 P: Copy,
29 {
30 }
31
32 impl<P, T, const COMPARE_PACKED: bool> Clone for CopyTaggedPtr<P, T, COMPARE_PACKED>
33 where
34 P: Pointer,
35 T: Tag,
36 P: Copy,
37 {
38 fn clone(&self) -> Self {
39 *self
40 }
41 }
42
43 // We pack the tag into the *upper* bits of the pointer to ease retrieval of the
44 // value; a left shift is a multiplication and those are embeddable in
45 // instruction encoding.
46 impl<P, T, const COMPARE_PACKED: bool> CopyTaggedPtr<P, T, COMPARE_PACKED>
47 where
48 P: Pointer,
49 T: Tag,
50 {
51 const TAG_BIT_SHIFT: usize = usize::BITS as usize - T::BITS;
52 const ASSERTION: () = {
53 assert!(T::BITS <= P::BITS);
54 // Used for the transmute_copy's below
55 assert!(std::mem::size_of::<&P::Target>() == std::mem::size_of::<usize>());
56 };
57
58 pub fn new(pointer: P, tag: T) -> Self {
59 // Trigger assert!
60 let () = Self::ASSERTION;
61 let packed_tag = tag.into_usize() << Self::TAG_BIT_SHIFT;
62
63 Self {
64 // SAFETY: We know that the pointer is non-null, as it must be
65 // dereferenceable per `Pointer` safety contract.
66 packed: unsafe {
67 NonZeroUsize::new_unchecked((P::into_usize(pointer) >> T::BITS) | packed_tag)
68 },
69 data: PhantomData,
70 }
71 }
72
73 pub(super) fn pointer_raw(&self) -> usize {
74 self.packed.get() << T::BITS
75 }
76 pub fn pointer(self) -> P
77 where
78 P: Copy,
79 {
80 // SAFETY: pointer_raw returns the original pointer
81 //
82 // Note that this isn't going to double-drop or anything because we have
83 // P: Copy
84 unsafe { P::from_usize(self.pointer_raw()) }
85 }
86 pub fn pointer_ref(&self) -> &P::Target {
87 // SAFETY: pointer_raw returns the original pointer
88 unsafe { std::mem::transmute_copy(&self.pointer_raw()) }
89 }
90 pub fn pointer_mut(&mut self) -> &mut P::Target
91 where
92 P: std::ops::DerefMut,
93 {
94 // SAFETY: pointer_raw returns the original pointer
95 unsafe { std::mem::transmute_copy(&self.pointer_raw()) }
96 }
97 #[inline]
98 pub fn tag(&self) -> T {
99 unsafe { T::from_usize(self.packed.get() >> Self::TAG_BIT_SHIFT) }
100 }
101 #[inline]
102 pub fn set_tag(&mut self, tag: T) {
103 let mut packed = self.packed.get();
104 let new_tag = T::into_usize(tag) << Self::TAG_BIT_SHIFT;
105 let tag_mask = (1 << T::BITS) - 1;
106 packed &= !(tag_mask << Self::TAG_BIT_SHIFT);
107 packed |= new_tag;
108 self.packed = unsafe { NonZeroUsize::new_unchecked(packed) };
109 }
110 }
111
112 impl<P, T, const COMPARE_PACKED: bool> std::ops::Deref for CopyTaggedPtr<P, T, COMPARE_PACKED>
113 where
114 P: Pointer,
115 T: Tag,
116 {
117 type Target = P::Target;
118 fn deref(&self) -> &Self::Target {
119 self.pointer_ref()
120 }
121 }
122
123 impl<P, T, const COMPARE_PACKED: bool> std::ops::DerefMut for CopyTaggedPtr<P, T, COMPARE_PACKED>
124 where
125 P: Pointer + std::ops::DerefMut,
126 T: Tag,
127 {
128 fn deref_mut(&mut self) -> &mut Self::Target {
129 self.pointer_mut()
130 }
131 }
132
133 impl<P, T, const COMPARE_PACKED: bool> fmt::Debug for CopyTaggedPtr<P, T, COMPARE_PACKED>
134 where
135 P: Pointer,
136 P::Target: fmt::Debug,
137 T: Tag + fmt::Debug,
138 {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 f.debug_struct("CopyTaggedPtr")
141 .field("pointer", &self.pointer_ref())
142 .field("tag", &self.tag())
143 .finish()
144 }
145 }
146
147 impl<P, T> PartialEq for CopyTaggedPtr<P, T, true>
148 where
149 P: Pointer,
150 T: Tag,
151 {
152 fn eq(&self, other: &Self) -> bool {
153 self.packed == other.packed
154 }
155 }
156
157 impl<P, T> Eq for CopyTaggedPtr<P, T, true>
158 where
159 P: Pointer,
160 T: Tag,
161 {
162 }
163
164 impl<P, T> std::hash::Hash for CopyTaggedPtr<P, T, true>
165 where
166 P: Pointer,
167 T: Tag,
168 {
169 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
170 self.packed.hash(state);
171 }
172 }
173
174 impl<P, T, HCX, const COMPARE_PACKED: bool> HashStable<HCX> for CopyTaggedPtr<P, T, COMPARE_PACKED>
175 where
176 P: Pointer + HashStable<HCX>,
177 T: Tag + HashStable<HCX>,
178 {
179 fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
180 unsafe {
181 Pointer::with_ref(self.pointer_raw(), |p: &P| p.hash_stable(hcx, hasher));
182 }
183 self.tag().hash_stable(hcx, hasher);
184 }
185 }