bitvec/
mem.rs

1#![doc = include_str!("../doc/mem.md")]
2
3use core::{
4	cell::Cell,
5	mem,
6};
7
8use funty::Unsigned;
9use radium::marker::BitOps;
10
11#[doc = include_str!("../doc/mem/BitRegister.md")]
12pub trait BitRegister: Unsigned + BitOps {
13	/// The number of bits required to store an index in the range `0 .. BITS`.
14	const INDX: u8 = bits_of::<Self>().trailing_zeros() as u8;
15	/// A mask over all bits that can be used as an index within the element.
16	/// This is the value with the least significant `INDX`-many bits set high.
17	const MASK: u8 = bits_of::<Self>() as u8 - 1;
18	/// The literal `!0`.
19	const ALL: Self;
20}
21
22/// Marks certain fundamentals as processor registers.
23macro_rules! register {
24	($($t:ty),+ $(,)?) => { $(
25		impl BitRegister for $t {
26			const ALL: Self = !0;
27		}
28	)+ };
29}
30
31register!(u8, u16, u32);
32
33/** `u64` can only be used as a register on processors whose word size is at
34least 64 bits.
35
36This implementation is not present on targets with 32-bit processor words.
37**/
38#[cfg(target_pointer_width = "64")]
39impl BitRegister for u64 {
40	const ALL: Self = !0;
41}
42
43register!(usize);
44
45/// Counts the number of bits in a value of type `T`.
46pub const fn bits_of<T>() -> usize {
47	core::mem::size_of::<T>().saturating_mul(<u8>::BITS as usize)
48}
49
50#[doc = include_str!("../doc/mem/elts.md")]
51pub const fn elts<T>(bits: usize) -> usize {
52	let width = bits_of::<T>();
53	if width == 0 {
54		return 0;
55	}
56	bits / width + (bits % width != 0) as usize
57}
58
59/// Tests if a type has alignment equal to its size.
60#[doc(hidden)]
61#[cfg(not(tarpaulin_include))]
62pub const fn aligned_to_size<T>() -> bool {
63	mem::align_of::<T>() == mem::size_of::<T>()
64}
65
66/// Tests if two types have identical layouts (size and alignment are equal).
67#[doc(hidden)]
68#[cfg(not(tarpaulin_include))]
69pub const fn layout_eq<T, U>() -> bool {
70	mem::align_of::<T>() == mem::align_of::<U>()
71		&& mem::size_of::<T>() == mem::size_of::<U>()
72}
73
74#[doc(hidden)]
75#[repr(transparent)]
76#[doc = include_str!("../doc/mem/BitElement.md")]
77#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
78pub struct BitElement<T = usize> {
79	pub elem: T,
80}
81
82/// Creates a `BitElement` implementation for an integer and its atomic/cell
83/// variants.
84macro_rules! element {
85	($($size:tt, $bare:ty => $atom:ident);+ $(;)?) => { $(
86		impl BitElement<$bare> {
87			/// Creates a new element wrapper from a raw integer.
88			pub const fn new(elem: $bare) -> Self {
89				Self {
90					elem,
91				}
92			}
93		}
94
95		impl BitElement<Cell<$bare>> {
96			/// Creates a new element wrapper from a raw integer.
97			pub const fn new(elem: $bare) -> Self {
98				Self {
99					elem: Cell::new(elem),
100				}
101			}
102		}
103
104		radium::if_atomic!( if atomic($size) {
105			use core::sync::atomic::$atom;
106			impl BitElement<$atom> {
107				/// Creates a new element wrapper from a raw integer.
108				pub const fn new(elem: $bare) -> Self {
109					Self {
110						elem: <$atom>::new(elem),
111					}
112				}
113			}
114		});
115	)+ };
116}
117
118element! {
119	8, u8 => AtomicU8;
120	16, u16 => AtomicU16;
121	32, u32 => AtomicU32;
122}
123
124#[cfg(target_pointer_width = "64")]
125element!(64, u64 => AtomicU64);
126
127element!(size, usize => AtomicUsize);
128
129#[cfg(test)]
130mod tests {
131	use super::*;
132	use crate::access::*;
133
134	#[test]
135	fn integer_properties() {
136		assert!(aligned_to_size::<u8>());
137		assert!(aligned_to_size::<BitSafeU8>());
138		assert!(layout_eq::<u8, BitSafeU8>());
139
140		assert!(aligned_to_size::<u16>());
141		assert!(aligned_to_size::<BitSafeU16>());
142		assert!(layout_eq::<u16, BitSafeU16>());
143
144		assert!(aligned_to_size::<u32>());
145		assert!(aligned_to_size::<BitSafeU32>());
146		assert!(layout_eq::<u32, BitSafeU32>());
147
148		assert!(aligned_to_size::<usize>());
149		assert!(aligned_to_size::<BitSafeUsize>());
150		assert!(layout_eq::<usize, BitSafeUsize>());
151
152		#[cfg(target_pointer_width = "64")]
153		{
154			assert!(aligned_to_size::<u64>());
155			assert!(aligned_to_size::<BitSafeU64>());
156			assert!(layout_eq::<u64, BitSafeU64>());
157		}
158	}
159}