/rust/registry/src/index.crates.io-6f17d22bba15001f/bitvec-1.0.1/src/access.rs
Line | Count | Source (jump to first uncovered line) |
1 | | #![doc = include_str!("../doc/access.md")] |
2 | | |
3 | | use core::sync::atomic::Ordering; |
4 | | |
5 | | use funty::Integral; |
6 | | use radium::Radium; |
7 | | |
8 | | use crate::{ |
9 | | index::{ |
10 | | BitIdx, |
11 | | BitMask, |
12 | | }, |
13 | | mem::BitRegister, |
14 | | order::BitOrder, |
15 | | }; |
16 | | |
17 | | #[doc = include_str!("../doc/access/BitAccess.md")] |
18 | | pub trait BitAccess: Radium |
19 | | where <Self as Radium>::Item: BitRegister |
20 | | { |
21 | | /// Clears bits within a memory element to `0`. |
22 | | /// |
23 | | /// The mask provided to this method must be constructed from indices that |
24 | | /// are valid in the caller’s context. As the mask is already computed by |
25 | | /// the caller, this does not take an ordering type parameter. |
26 | | /// |
27 | | /// ## Parameters |
28 | | /// |
29 | | /// - `mask`: A mask of any number of bits. This is a selection mask: all |
30 | | /// bits in the mask that are set to `1` will set the corresponding bit in |
31 | | /// `*self` to `0`. |
32 | | /// |
33 | | /// ## Returns |
34 | | /// |
35 | | /// The prior value of the memory element. |
36 | | /// |
37 | | /// ## Effects |
38 | | /// |
39 | | /// All bits in `*self` corresponding to `1` bits in the `mask` are cleared |
40 | | /// to `0`; all others retain their original value. |
41 | | /// |
42 | | /// Do not invert the `mask` prior to calling this function. [`BitMask`] is |
43 | | /// a selection type, not a bitwise-operation argument. |
44 | | /// |
45 | | /// [`BitMask`]: crate::index::BitMask |
46 | | #[inline] |
47 | 180k | fn clear_bits(&self, mask: BitMask<Self::Item>) -> Self::Item { |
48 | 180k | self.fetch_and(!mask.into_inner(), Ordering::Relaxed) |
49 | 180k | } <core::cell::Cell<u8> as bitvec::access::BitAccess>::clear_bits Line | Count | Source | 47 | 180k | fn clear_bits(&self, mask: BitMask<Self::Item>) -> Self::Item { | 48 | 180k | self.fetch_and(!mask.into_inner(), Ordering::Relaxed) | 49 | 180k | } |
Unexecuted instantiation: <_ as bitvec::access::BitAccess>::clear_bits |
50 | | |
51 | | /// Sets bits within a memory element to `1`. |
52 | | /// |
53 | | /// The mask provided to this method must be constructed from indices that |
54 | | /// are valid in the caller’s context. As the mask is already computed by |
55 | | /// the caller, this does not take an ordering type parameter. |
56 | | /// |
57 | | /// ## Parameters |
58 | | /// |
59 | | /// - `mask`: A mask of any number of bits. This is a selection mask: all |
60 | | /// bits in the mask that are set to `1` will set the corresponding bit in |
61 | | /// `*self` to `1`. |
62 | | /// |
63 | | /// ## Returns |
64 | | /// |
65 | | /// The prior value of the memory element. |
66 | | /// |
67 | | /// ## Effects |
68 | | /// |
69 | | /// All bits in `*self` corresponding to `1` bits in the `mask` are set to |
70 | | /// `1`; all others retain their original value. |
71 | | #[inline] |
72 | 180k | fn set_bits(&self, mask: BitMask<Self::Item>) -> Self::Item { |
73 | 180k | self.fetch_or(mask.into_inner(), Ordering::Relaxed) |
74 | 180k | } <core::cell::Cell<u8> as bitvec::access::BitAccess>::set_bits Line | Count | Source | 72 | 180k | fn set_bits(&self, mask: BitMask<Self::Item>) -> Self::Item { | 73 | 180k | self.fetch_or(mask.into_inner(), Ordering::Relaxed) | 74 | 180k | } |
Unexecuted instantiation: <_ as bitvec::access::BitAccess>::set_bits |
75 | | |
76 | | /// Inverts bits within a memory element. |
77 | | /// |
78 | | /// The mask provided to this method must be constructed from indices that |
79 | | /// are valid in the caller’s context. As the mask is already computed by |
80 | | /// the caller, this does not take an ordering type parameter. |
81 | | /// |
82 | | /// ## Parameters |
83 | | /// |
84 | | /// - `mask`: A mask of any number of bits. This is a selection mask: all |
85 | | /// bits in the mask that are set to `1` will invert the corresponding bit |
86 | | /// in `*self`. |
87 | | /// |
88 | | /// ## Returns |
89 | | /// |
90 | | /// The prior value of the memory element. |
91 | | /// |
92 | | /// ## Effects |
93 | | /// |
94 | | /// All bits in `*self` corresponding to `1` bits in the `mask` are |
95 | | /// inverted; all others retain their original value. |
96 | | #[inline] |
97 | 0 | fn invert_bits(&self, mask: BitMask<Self::Item>) -> Self::Item { |
98 | 0 | self.fetch_xor(mask.into_inner(), Ordering::Relaxed) |
99 | 0 | } |
100 | | |
101 | | /// Writes a value to one bit in a memory element, returning the previous |
102 | | /// value. |
103 | | /// |
104 | | /// ## Type Parameters |
105 | | /// |
106 | | /// - `O`: An ordering of bits in a memory element that translates the |
107 | | /// `index` into a real position. |
108 | | /// |
109 | | /// ## Parameters |
110 | | /// |
111 | | /// - `index`: The semantic index of the bit in `*self` to modify. |
112 | | /// - `value`: The new bit value to write into `*self` at the `index`. |
113 | | /// |
114 | | /// ## Returns |
115 | | /// |
116 | | /// The bit previously stored in `*self` at `index`. These operations are |
117 | | /// required to load the `*self` value from memory in order to operate, and |
118 | | /// so always have the prior value available for use. This can reduce |
119 | | /// spurious loads throughout the crate. |
120 | | /// |
121 | | /// ## Effects |
122 | | /// |
123 | | /// `*self` is updated with the bit at `index` set to `value`; all other |
124 | | /// bits remain unchanged. |
125 | | #[inline] |
126 | 32.9k | fn write_bit<O>(&self, index: BitIdx<Self::Item>, value: bool) -> bool |
127 | 32.9k | where O: BitOrder { |
128 | 32.9k | let select = index.select::<O>().into_inner(); |
129 | 32.9k | select |
130 | 32.9k | & if value { |
131 | 3.53k | self.fetch_or(select, Ordering::Relaxed) |
132 | | } |
133 | | else { |
134 | 29.4k | self.fetch_and(!select, Ordering::Relaxed) |
135 | 32.9k | } != <Self::Item>::ZERO |
136 | 32.9k | } <core::cell::Cell<u8> as bitvec::access::BitAccess>::write_bit::<bitvec::order::Msb0> Line | Count | Source | 126 | 32.9k | fn write_bit<O>(&self, index: BitIdx<Self::Item>, value: bool) -> bool | 127 | 32.9k | where O: BitOrder { | 128 | 32.9k | let select = index.select::<O>().into_inner(); | 129 | 32.9k | select | 130 | 32.9k | & if value { | 131 | 3.53k | self.fetch_or(select, Ordering::Relaxed) | 132 | | } | 133 | | else { | 134 | 29.4k | self.fetch_and(!select, Ordering::Relaxed) | 135 | 32.9k | } != <Self::Item>::ZERO | 136 | 32.9k | } |
Unexecuted instantiation: <_ as bitvec::access::BitAccess>::write_bit::<_> |
137 | | |
138 | | /// Gets the function that will write `value` into all bits under a mask. |
139 | | /// |
140 | | /// This is useful for preparing bulk operations that all write the same |
141 | | /// data into memory, and only need to provide the shape of memory to write. |
142 | | /// |
143 | | /// ## Parameters |
144 | | /// |
145 | | /// - `value`: The bit that will be written by the returned function. |
146 | | /// |
147 | | /// ## Returns |
148 | | /// |
149 | | /// A function which writes `value` into memory at a given address and under |
150 | | /// a given mask. If `value` is `false`, then this produces [`clear_bits`]; |
151 | | /// if it is `true`, then this produces [`set_bits`]. |
152 | | /// |
153 | | /// [`clear_bits`]: Self::clear_bits |
154 | | /// [`set_bits`]: Self::set_bits |
155 | | #[inline] |
156 | 0 | fn get_writers( |
157 | 0 | value: bool, |
158 | 0 | ) -> for<'a> fn(&'a Self, BitMask<Self::Item>) -> Self::Item { |
159 | 0 | if value { |
160 | 0 | Self::set_bits |
161 | | } |
162 | | else { |
163 | 0 | Self::clear_bits |
164 | | } |
165 | 0 | } |
166 | | } |
167 | | |
168 | | impl<A> BitAccess for A |
169 | | where |
170 | | A: Radium, |
171 | | A::Item: BitRegister, |
172 | | { |
173 | | } |
174 | | |
175 | | #[doc = include_str!("../doc/access/BitSafe.md")] |
176 | | pub trait BitSafe { |
177 | | /// The element type being guarded against improper mutation. |
178 | | /// |
179 | | /// This is only present as an extra proof that the type graph has a |
180 | | /// consistent view of the underlying memory. |
181 | | type Mem: BitRegister; |
182 | | |
183 | | /// The memory-access type this guards. |
184 | | /// |
185 | | /// This is exposed as an associated type so that `BitStore` can name it |
186 | | /// without having to re-select it based on crate configuration. |
187 | | type Rad: Radium<Item = Self::Mem>; |
188 | | |
189 | | /// The zero constant. |
190 | | const ZERO: Self; |
191 | | |
192 | | /// Loads the value from memory, allowing for the possibility that other |
193 | | /// handles have write permissions to it. |
194 | | fn load(&self) -> Self::Mem; |
195 | | } |
196 | | |
197 | | /// Constructs a shared-mutable guard type that disallows mutation *through it*. |
198 | | macro_rules! safe { |
199 | | ($($t:ident => $w:ident => $r:ty);+ $(;)?) => { $( |
200 | | #[derive(Debug)] |
201 | | #[repr(transparent)] |
202 | | #[doc = include_str!("../doc/access/impl_BitSafe.md")] |
203 | | pub struct $w { |
204 | | inner: <Self as BitSafe>::Rad, |
205 | | } |
206 | | |
207 | | impl $w { |
208 | | /// Allow construction of the safed value by forwarding to its |
209 | | /// interior constructor. |
210 | | /// |
211 | | /// This type is not public API, and general use has no reason to |
212 | | /// construct values of it directly. It is provided for convenience |
213 | | /// as a crate internal. |
214 | 0 | pub(crate) const fn new(value: $t) -> Self { |
215 | 0 | Self { inner: <<Self as BitSafe>::Rad>::new(value) } |
216 | 0 | } Unexecuted instantiation: <bitvec::access::BitSafeU8>::new Unexecuted instantiation: <bitvec::access::BitSafeU16>::new Unexecuted instantiation: <bitvec::access::BitSafeU32>::new Unexecuted instantiation: <bitvec::access::BitSafeU64>::new Unexecuted instantiation: <bitvec::access::BitSafeUsize>::new |
217 | | } |
218 | | |
219 | | impl BitSafe for $w { |
220 | | type Mem = $t; |
221 | | |
222 | | #[cfg(feature = "atomic")] |
223 | | type Rad = $r; |
224 | | |
225 | | #[cfg(not(feature = "atomic"))] |
226 | | type Rad = core::cell::Cell<$t>; |
227 | | |
228 | | const ZERO: Self = Self::new(0); |
229 | | |
230 | | #[inline] |
231 | 0 | fn load(&self) -> Self::Mem { |
232 | 0 | self.inner.load(Ordering::Relaxed) |
233 | 0 | } Unexecuted instantiation: <bitvec::access::BitSafeU8 as bitvec::access::BitSafe>::load Unexecuted instantiation: <bitvec::access::BitSafeU16 as bitvec::access::BitSafe>::load Unexecuted instantiation: <bitvec::access::BitSafeU32 as bitvec::access::BitSafe>::load Unexecuted instantiation: <bitvec::access::BitSafeU64 as bitvec::access::BitSafe>::load Unexecuted instantiation: <bitvec::access::BitSafeUsize as bitvec::access::BitSafe>::load |
234 | | } |
235 | | )+ }; |
236 | | } |
237 | | |
238 | | safe! { |
239 | | u8 => BitSafeU8 => radium::types::RadiumU8; |
240 | | u16 => BitSafeU16 => radium::types::RadiumU16; |
241 | | u32 => BitSafeU32 => radium::types::RadiumU32; |
242 | | } |
243 | | |
244 | | #[cfg(target_pointer_width = "64")] |
245 | | safe!(u64 => BitSafeU64 => radium::types::RadiumU64); |
246 | | |
247 | | safe!(usize => BitSafeUsize => radium::types::RadiumUsize); |
248 | | |
249 | | #[cfg(test)] |
250 | | mod tests { |
251 | | use core::cell::Cell; |
252 | | |
253 | | use super::*; |
254 | | use crate::prelude::*; |
255 | | |
256 | | #[test] |
257 | | fn touch_memory() { |
258 | | let data = Cell::new(0u8); |
259 | | let accessor = &data; |
260 | | let aliased = unsafe { &*(&data as *const _ as *const BitSafeU8) }; |
261 | | |
262 | | assert!(!BitAccess::write_bit::<Lsb0>( |
263 | | accessor, |
264 | | BitIdx::new(1).unwrap(), |
265 | | true |
266 | | )); |
267 | | assert_eq!(aliased.load(), 2); |
268 | | assert!(BitAccess::write_bit::<Lsb0>( |
269 | | accessor, |
270 | | BitIdx::new(1).unwrap(), |
271 | | false |
272 | | )); |
273 | | assert_eq!(aliased.load(), 0); |
274 | | } |
275 | | |
276 | | #[test] |
277 | | #[cfg(not(miri))] |
278 | | fn sanity_check_prefetch() { |
279 | | use core::cell::Cell; |
280 | | assert_eq!( |
281 | | <Cell<u8> as BitAccess>::get_writers(false) as *const (), |
282 | | <Cell<u8> as BitAccess>::clear_bits as *const () |
283 | | ); |
284 | | |
285 | | assert_eq!( |
286 | | <Cell<u8> as BitAccess>::get_writers(true) as *const (), |
287 | | <Cell<u8> as BitAccess>::set_bits as *const () |
288 | | ); |
289 | | } |
290 | | } |