#![feature(const_generics)]
mod zeroable;
use std::alloc::{alloc, alloc_zeroed, dealloc, Layout};
use std::ops::{Index, IndexMut, Range};
pub use crate::zeroable::Zeroable;
pub struct Array<T> {
size: usize,
ptr: *mut T,
}
unsafe impl<T: Sync> Sync for Array<T>{}
unsafe impl<T: Send> Send for Array<T>{}
impl<T> Array<T> {
pub fn iter<'a>(&'a self) -> ArrayIter<'a, T> {
ArrayIter{
arr: &self,
iter: 0usize
}
}
pub fn to_slice<'a>(&'a self) -> &'a [T] {
unsafe { std::slice::from_raw_parts(self.ptr as *const T, self.size) }
}
pub fn to_slice_mut<'a>(&'a mut self) -> &'a mut [T] {
unsafe { std::slice::from_raw_parts_mut(self.ptr, self.size) }
}
pub fn len(&self) -> usize {
self.size
}
}
impl<T> Array<T>
where T: Zeroable {
pub fn zero(size: usize) -> Self {
let objsize = std::mem::size_of::<T>();
let layout = Layout::from_size_align(size * objsize, 8).unwrap();
let ptr = unsafe {
alloc_zeroed(layout) as *mut T
};
Self{size, ptr}
}
}
impl<T> Array<T>
where T: Default + Copy {
pub fn new(size: usize) -> Self {
let objsize = std::mem::size_of::<T>();
let layout = Layout::from_size_align(size * objsize, 8).unwrap();
let ptr = unsafe {
alloc(layout) as *mut T
};
let default: T = Default::default();
for i in 0..size {
unsafe {
(*(ptr.wrapping_offset(i as isize))) = default;
}
}
Self{size, ptr}
}
}
impl<T> Array<T>
where T: Clone {
pub fn new_from_template(size: usize, template: &T) -> Self {
let objsize = std::mem::size_of::<T>();
let layout = Layout::from_size_align(size * objsize, 8).unwrap();
let ptr = unsafe {
alloc(layout) as *mut T
};
for i in 0..size {
unsafe {
ptr.wrapping_offset(i as isize).write(template.clone());
}
}
Self{size, ptr}
}
}
impl<T> Index<usize> for Array<T> {
type Output = T;
fn index<'a>(&'a self, idx: usize) -> &'a Self::Output {
&self.to_slice()[idx]
}
}
impl<T> IndexMut<usize> for Array<T> {
fn index_mut<'a>(&'a mut self, idx: usize) -> &'a mut Self::Output {
&mut self.to_slice_mut()[idx]
}
}
impl<T> Index<Range<usize>> for Array<T> {
type Output = [T];
fn index<'a>(&'a self, idx: Range<usize>) -> &'a Self::Output {
&self.to_slice()[idx]
}
}
impl<T> IndexMut<Range<usize>> for Array<T> {
fn index_mut<'a>(&'a mut self, idx: Range<usize>) -> &'a mut Self::Output {
&mut self.to_slice_mut()[idx]
}
}
impl<T> Drop for Array<T> {
fn drop(&mut self) {
let objsize = std::mem::size_of::<T>();
let layout = Layout::from_size_align(self.size * objsize, 8).unwrap();
unsafe {
for i in 0..(self.size as isize) {
std::ptr::drop_in_place(self.ptr.wrapping_offset(i));
}
dealloc(self.ptr as *mut u8, layout);
}
}
}
impl<'a, T> IntoIterator for &'a Array<T> {
type Item = &'a T;
type IntoIter = ArrayIter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
pub struct ArrayIter<'a, T> {
arr: &'a Array<T>,
iter: usize
}
impl<'a, T> Iterator for ArrayIter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
match self.iter < self.arr.len() {
true => {
self.iter += 1;
Some(&self.arr[self.iter - 1])
},
false => None
}
}
}
impl<'a, T> ExactSizeIterator for ArrayIter<'a, T> {
fn len(&self) -> usize {
self.arr.size - self.iter
}
}
#[cfg(test)]
mod test {
use std::thread;
use std::sync::{Arc, Mutex};
use super::*;
#[test]
fn test_default() {
let arr: Array<f32> = Array::new(4 << 20); assert_eq!(arr[4 << 20 - 1], 0.0);
}
#[test]
fn test_template() {
let template: [u64; 256] = [65u64; 256];
let arr: Array<[u64; 256]> = Array::new_from_template(4096, &template);
assert_eq!(arr[4095][255], 65);
}
#[derive(Clone)]
struct Unaligned {
a: u64,
b: u16
}
#[test]
fn test_unaligned() {
let unaligned_template = Unaligned{a: 15, b:32};
let arr: Array<Unaligned> = Array::new_from_template(5, &unaligned_template);
assert_eq!(arr[3].a, 15);
assert_eq!(arr[3].b, 32);
assert_eq!(arr[4].a, 15);
assert_eq!(arr[4].b, 32);
}
#[test]
fn test_zeroed() {
let arr: Array<[usize; 4096]> = Array::zero(4096);
assert_eq!(arr[4095][4095], 0);
}
#[test]
fn test_async() {
let arr: Array<usize> = Array::zero(5);
let tid = thread::spawn(move || {
assert_eq!(arr[3], 0);
});
let _ = tid.join();
}
#[test]
fn test_mut_async() {
let arr: Arc<Mutex<Array<usize>>> = Arc::new(Mutex::new(Array::zero(5)));
{
let mut arr = (&*arr).lock().unwrap();
arr[4] = 1;
}
let carr = arr.clone();
let tid = thread::spawn(move || {
let mut arr = (&*carr).lock().unwrap();
assert_eq!(arr[4], 1);
arr[4] = 0;
});
tid.join().unwrap();
assert_eq!((&*arr).lock().unwrap()[4], 0);
}
#[test]
fn test_loop() {
let arr: Array<usize> = Array::new_from_template(5, &5);
let mut cnt = 0;
for _ in arr.iter() {
cnt += 1;
}
assert_eq!(cnt, 5);
}
#[test]
fn test_copy_from() {
let mut arr: Array<usize> = Array::new_from_template(5, &5);
let from: [usize; 5] = [1usize; 5];
arr.to_slice_mut().copy_from_slice(&from);
assert_eq!(arr[4], 1);
}
#[test]
fn test_range() {
let arr: Array<usize> = Array::zero(10);
let mut cnt = 0;
for _i in &arr[0..5] {
cnt += 1;
}
assert_eq!(cnt, 5);
}
#[test]
fn test_range_mut() {
let mut arr: Array<usize> = Array::zero(10);
let slice = &mut arr[0..5];
for i in slice {
*i = 5;
}
assert_eq!(arr[4], 5);
}
#[test]
fn test_sync() {
let arr = Array::new_from_template(1, &&1usize);
std::thread::spawn(move || {
let _ = arr[0].clone();
}).join().unwrap();
}
}