diff --git a/Cargo.toml b/Cargo.toml index fa7ea9d..d07759e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "malloc-array" description = "libc heap array allocator" -version = "1.3.3" +version = "1.4.3" authors = ["Avril "] edition = "2018" license = "GPL-3.0-or-later" diff --git a/src/lib.rs b/src/lib.rs index 86a025d..ab3bd94 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,17 @@ extern crate jemalloc_sys; mod tests { use super::*; + #[test] + fn from_bytes() + { + unsafe { + let heap = HeapArray::::from_bytes(&[0xff,0xff,0xff,0xff,0,0,0,0,0xff,0xff,0xff,0xff]); + assert_eq!(heap[0], -1); + assert_eq!(heap[1], 0); + assert_eq!(heap[2], -1); + } + } + #[test] fn copy() { let heap = heap![unsafe 1u16; 10]; @@ -179,6 +190,7 @@ mod alloc; mod reinterpret; pub mod init; pub use init::InitIterExt; +pub mod store; use std::{ ops::{ @@ -201,6 +213,7 @@ use std::{ use crate::{ ptr::{ VoidPointer, + ConstVoidPointer, }, }; @@ -604,11 +617,37 @@ impl HeapArray } } + /// Copy memory in from a slice of bytes. + pub unsafe fn memory_from_bytes>(&mut self, from: U) -> usize + { + let from = from.as_ref(); + let size = std::cmp::min(from.len(), self.len_bytes()); + ptr::memcpy(self.ptr as VoidPointer, &from[0] as *const u8 as ConstVoidPointer, size); + size + } + + /// Copy memory in from a pointer to bytes. + pub unsafe fn memory_from_raw_bytes(&mut self, from: *const u8, size: usize) -> usize + { + let size = std::cmp::min(size, self.len_bytes()); + ptr::memcpy(self.ptr as VoidPointer, from as *const u8 as ConstVoidPointer, size); + size + } + + /// Copy memory in from a raw pointer. + pub unsafe fn memory_from_slice>(&mut self, from: U) -> usize + { + let from = from.as_ref(); + let size = std::cmp::min(from.len(), self.len()); + ptr::memcpy(self.ptr as VoidPointer, &from[0] as *const T as ConstVoidPointer, size * std::mem::size_of::()); + size + } + /// Copy memory in from a raw pointer. pub unsafe fn memory_from_raw(&mut self, from: *const T, size: usize) -> usize { let size = std::cmp::min(size, self.len()); - ptr::memcpy(self.ptr as VoidPointer, from as VoidPointer, size * std::mem::size_of::()); + ptr::memcpy(self.ptr as VoidPointer, from as *const T as ConstVoidPointer, size * std::mem::size_of::()); size } @@ -619,6 +658,31 @@ impl HeapArray inp.memory_from_raw(from, size); inp } + + /// Create a new instance with memory copied from a slice. + pub unsafe fn from_slice_copied>(from: U) -> Self + where T: Copy + { + let from = from.as_ref(); + Self::from_raw_copied(&from[0] as *const T, from.len()) + } + + /// Create a new instance with memory bytes copied from a raw pointer. + pub unsafe fn from_raw_bytes(from: *const u8, size: usize) -> Self + { + assert_eq!(size % Self::element_size(),0,"Cannot fit T into this size."); + + let mut inp = Self::new_uninit(size / Self::element_size()); + inp.memory_from_raw_bytes(from, size); + inp + } + + /// Create a new instance with memory bytes copied from a slice. + pub unsafe fn from_bytes>(from: U) -> Self + { + let from = from.as_ref(); + Self::from_raw_bytes(&from[0], from.len()) + } } impl Index for HeapArray diff --git a/src/store.rs b/src/store.rs new file mode 100644 index 0000000..ef2d57b --- /dev/null +++ b/src/store.rs @@ -0,0 +1,247 @@ +use crate::*; + +/// Statically typed pointer store. `free()`s and drops on drop. +#[derive(Debug)] +pub struct Store +{ + pointers: Vec<*mut T>, +} + +#[cfg(test)] +mod tests +{ + use super::*; + #[test] + fn store() + { + let mut store = Store::new(); + unsafe { + for _a in 0..10 { + let _ptr = store.ptr(alloc::malloc(100).unwrap()); + } + } + } + #[test] + fn dyn_store() + { + let mut store = DynStore::new(); + unsafe { + for _a in 0..10 { + let ptr = store.ptr(alloc::malloc(4).unwrap() as *mut u32); + *ptr = 100u32; + } + } + + } + #[test] + fn into_ha() + { + let mut store = Store::new(); + unsafe { + for a in 0..10 { + *store.ptr(alloc::malloc(4).unwrap() as *mut u32) = a; + } + } + let ha = store.into_heap_array(); + assert_eq!(ha.len(), 10); + assert_eq!(&ha[..], &[0,1,2,3,4,5,6,7,8,9]); + } +} + +impl Store +{ + /// Create a new pointer store. + pub fn new() -> Self + { + Self{pointers:Vec::new()} + } + + /// Add a pointer to the store. + pub fn ptr(&mut self, ptr: *mut T) -> *mut T + { + self.pointers.push(ptr); + ptr + } + + /// Remove a pointer from the store. + pub fn remove(&mut self, ptr: *mut T) + { + while let Some(i) = self.pointers.iter().position(|x| *x == ptr) + { + self.pointers.remove(i); + } + } + + /// Consumes the instance and returns the pointers without freeing them. + pub fn into_raw_parts(mut self) -> Vec<*mut T> + { + std::mem::replace(&mut self.pointers, Vec::new()) + } + + /// Consume a vector of pointers and return a new `Store`. + pub fn from_raw_parts(pointers: Vec<*mut T>) -> Self + { + Self { + pointers, + } + } + + /// Free all the pointers in the store without calling their destructors (if the have any). + pub fn free(mut self) + { + for &mut x in self.pointers.iter_mut() + { + unsafe { + alloc::free(x as VoidPointer); + } + } + self.pointers.clear() + } + + /// Move all data from all pointers into a new `HeapArray` instance and free the old pointers. + pub fn into_heap_array(mut self) -> HeapArray + { + let mut output = heap![T; self.pointers.len()]; + for (mut init, old) in output.initialise().zip(std::mem::replace(&mut self.pointers, Vec::new()).into_iter()) + { + unsafe { + init.put(ptr::take(old)); + alloc::free(old as *mut ()); + } + } + output + } +} + +impl std::ops::Drop for Store +{ + fn drop(&mut self) + { + for &mut ptr in self.pointers.iter_mut() + { + unsafe { + drop(ptr::take(ptr)); + alloc::free(ptr as VoidPointer); + } + } + self.pointers.clear(); + } +} + +/// Dynamically typed pointer store. Frees on drop. +#[derive(Debug)] +pub struct DynStore +{ + pointers: Vec, +} + +impl DynStore +{ + /// Create a new pointer store. + pub fn new() -> Self + { + Self{pointers:Vec::new()} + } + + /// Add a pointer to the store. + pub fn ptr(&mut self, ptr: *mut T) -> *mut T + { + self.pointers.push(ptr as VoidPointer); + ptr + } + + /// Remove a pointer from the store. + pub fn remove(&mut self, ptr: *mut T) + { + while let Some(i) = self.pointers.iter().position(|x| *x == ptr as VoidPointer) + { + self.pointers.remove(i); + } + } + + /// Consumes the instance and returns the pointers without freeing them. + pub fn into_raw_parts(mut self) -> Vec<*mut ()> + { + std::mem::replace(&mut self.pointers, Vec::new()) + } + + /// Consume a vector of pointers and return a new `Store`. + pub fn from_raw_parts(pointers: Vec<*mut ()>) -> Self + { + Self { + pointers, + } + } + + + /// Free all the pointers in the store without calling their destructors (if the have any). + pub fn free(mut self) + { + for &mut x in self.pointers.iter_mut() + { + unsafe { + alloc::free(x); + } + } + self.pointers.clear() + } + +} + +impl std::ops::Drop for DynStore +{ + fn drop(&mut self) + { + for &mut ptr in self.pointers.iter_mut() + { + unsafe { + drop(ptr::take(ptr)); + alloc::free(ptr); + } + } + self.pointers.clear(); + } +} + +impl IntoIterator for Store +{ + type Item = *mut T; + type IntoIter = std::vec::IntoIter; + + fn into_iter(mut self) -> Self::IntoIter + { + std::mem::replace(&mut self.pointers, Vec::new()).into_iter() + } +} + +impl IntoIterator for DynStore +{ + type Item = *mut (); + type IntoIter = std::vec::IntoIter; + + fn into_iter(mut self) -> Self::IntoIter + { + std::mem::replace(&mut self.pointers, Vec::new()).into_iter() + } +} + +use std::iter::FromIterator; +impl FromIterator<*mut T> for Store +{ + fn from_iter>(iter: I) -> Self + { + Self { + pointers: Vec::from_iter(iter) + } + } +} + +impl FromIterator<*mut T> for DynStore +{ + fn from_iter>(iter: I) -> Self + { + Self { + pointers: Vec::from_iter(iter.into_iter().map(|x| x as *mut ())) + } + } +}