use std::marker;
use std::cell::UnsafeCell;
use std::fmt;
use std::mem;
use std::ptr;
use std::ops::{Deref, DerefMut};
const CACHE_LINE: usize = 32;
#[cfg_attr(feature = "nightly",
repr(simd))]
#[derive(Debug)]
struct Padding(u64, u64, u64, u64);
pub struct CachePadded<T> {
data: UnsafeCell<[usize; CACHE_LINE]>,
_marker: ([Padding; 0], marker::PhantomData<T>),
}
impl<T> fmt::Debug for CachePadded<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "CachePadded {{ ... }}")
}
}
unsafe impl<T: Send> Send for CachePadded<T> {}
unsafe impl<T: Sync> Sync for CachePadded<T> {}
pub unsafe trait ZerosValid {}
#[cfg(feature = "nightly")]
unsafe impl ZerosValid for .. {}
macro_rules! zeros_valid { ($( $T:ty )*) => ($(
unsafe impl ZerosValid for $T {}
)*)}
zeros_valid!(u8 u16 u32 u64 usize);
zeros_valid!(i8 i16 i32 i64 isize);
unsafe impl ZerosValid for ::std::sync::atomic::AtomicUsize {}
unsafe impl<T> ZerosValid for ::std::sync::atomic::AtomicPtr<T> {}
impl<T: ZerosValid> CachePadded<T> {
#[cfg(not(feature = "nightly"))]
pub fn zeroed() -> CachePadded<T> {
CachePadded {
data: UnsafeCell::new(([0; CACHE_LINE])),
_marker: ([], marker::PhantomData),
}
}
#[cfg(feature = "nightly")]
pub const fn zeroed() -> CachePadded<T> {
CachePadded {
data: UnsafeCell::new(([0; CACHE_LINE])),
_marker: ([], marker::PhantomData),
}
}
}
#[inline]
fn assert_valid<T>() {
assert!(mem::size_of::<T>() <= mem::size_of::<CachePadded<T>>());
assert!(mem::align_of::<T>() <= mem::align_of::<CachePadded<T>>());
}
impl<T> CachePadded<T> {
pub fn new(t: T) -> CachePadded<T> {
assert_valid::<T>();
let ret = CachePadded {
data: UnsafeCell::new(([0; CACHE_LINE])),
_marker: ([], marker::PhantomData),
};
unsafe {
let p: *mut T = mem::transmute(&ret.data);
ptr::write(p, t);
}
ret
}
}
impl<T> Deref for CachePadded<T> {
type Target = T;
fn deref(&self) -> &T {
assert_valid::<T>();
unsafe { mem::transmute(&self.data) }
}
}
impl<T> DerefMut for CachePadded<T> {
fn deref_mut(&mut self) -> &mut T {
assert_valid::<T>();
unsafe { mem::transmute(&mut self.data) }
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn cache_padded_store_u64() {
let x: CachePadded<u64> = CachePadded::new(17);
assert_eq!(*x, 17);
}
#[test]
fn cache_padded_store_pair() {
let x: CachePadded<(u64, u64)> = CachePadded::new((17, 37));
assert_eq!(x.0, 17);
assert_eq!(x.1, 37);
}
}