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