master
Avril 5 years ago
parent b8b2793d2b
commit fd42d90499
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -1,7 +1,7 @@
[package]
name = "malloc-array"
description = "libc heap array allocator"
version = "1.1.1"
version = "1.2.1"
authors = ["Avril <flanchan@cumallover.me>"]
edition = "2018"
license = "GPL-3.0-or-later"

@ -26,6 +26,39 @@ drop(array); // This is now safe.
[replace_and_forget]: https://docs.rs/malloc-array/1.0.0/malloc_array/struct.HeapArray.html#method.replace_and_forget
#### Alternatively initialising with iterator
The library also provides the `InitIter` type, which is a mutable iterator for `HeapArray<T>` that allows you to safely initialise porentially uninitialised elements.
``` rust
let mut array = heap![String; 10];
for mut init in array.initialise()
{
init.set(format!("string!"));
// Also see docs for `init::Init` type.
}
drop(array); // This is now safe.
```
##### Filling the iterator
The iterator also provides methods to fill itself of uninitialised values.
###### Fill with `Clone`
``` rust
array.initialise().fill("value".to_owned());
```
###### Fill with lambda
``` rust
array.initialise().fill_with(|| "value".to_owned());
```
###### Fill with `Default`
``` rust
array.initialise().fill_default();
```
###### Uninitialise the memory
Since it is unknown if the type `T` supports zero-initialisation, zeroing the memory is counted as making it uninitialised.
``` rust
array.initialise().uninit(); //Sets all the rest of the iterator bytes to 0.
```
### Creating initialised arrays.
These are created with `malloc()` and set with `replace_and_forget` (or, for the special case of `u8` sized types, `memset`).
``` rust
@ -44,7 +77,7 @@ These are created with either `malloc(0)`, or if the `zst_noalloc` feature is en
heap![];
```
`zst_noalloc` is enabled by default and causes instances with `len_bytes() == 0` to have `NULL` internal pointers instead of dangling ones returned by `malloc(0)`.
This behaviour my not be desireable and if it is not, disable the default featues.
This behaviour may not be desireable and if it is not, disable the default featues.
### Dropping on free
Arrays created this way are dropped in a way that ensures each element is also dropped. For anything implementing the `Copy` trait, this is redundant.

@ -3,12 +3,14 @@ use std::{
marker::PhantomData,
};
/// Iterator for initialising potentially uninitialised `HeapArray<T>`.
pub struct InitIter<'a, T>
{
from: &'a mut HeapArray<T>,
current_idex: usize,
}
/// A safe wrapper to initialise potentially uninitialised data.
pub struct Init<'a, T>
{
ptr: *mut T,
@ -25,6 +27,17 @@ impl<'a, T> InitIter<'a, T>
current_idex,
}
}
/// Consumes the instance, zeroing all remaining bytes in the iterator.
pub fn uninit(self)
{
let len = self.from.len_bytes() - (self.current_idex * HeapArray::<T>::element_size());
if len > 0 {
unsafe {
ptr::memset(self.from.as_mut_ptr().offset(self.current_idex as isize) as *mut u8, 0, len);
}
}
}
}
impl<'a, T> Iterator for InitIter<'a, T>
@ -48,16 +61,71 @@ impl<'a, T> Iterator for InitIter<'a, T>
}
}
pub trait InitIterExt<T>
{
/// Fill the rest of the iterator with a `clone()`d value.
fn fill(self, value: T) where T: Clone;
/// Fill the rest of the iterator with output from a function.
fn fill_with<F>(self, func: F) where F: FnMut() -> T;
/// Fill the rest of the iterator with `default()`
fn fill_default(self) where T: Default;
}
impl<'a, T,I> InitIterExt<T> for I
where I: Iterator<Item=Init<'a, T>>,
T: 'a
{
fn fill(self, value: T)
where T:Clone
{
for mut x in self
{
if !x.is_init() {
x.put(value.clone());
}
}
}
fn fill_with<F>(self, mut func: F)
where F: FnMut() -> T
{
for mut x in self
{
if !x.is_init() {
x.put(func());
}
}
}
fn fill_default(self)
where T:Default
{
for mut x in self
{
if !x.is_init() {
x.put(Default::default());
}
}
}
}
impl<'a, T> Init<'a, T>
{
/// Has the value been set with `put()` or `assume_init()` yet?
pub fn is_init(&self) -> bool
{
self.init_ok
}
/// Assume the value has been initialised.
pub unsafe fn assume_init(&mut self)
{
self.init_ok = true;
}
/// Initialise or reset the value and then return a mutable reference to it.
pub fn put(&mut self, value: T) -> &mut T
{
if self.init_ok {
@ -72,6 +140,8 @@ impl<'a, T> Init<'a, T>
&mut (*self.ptr)
}
}
/// Get a reference to the value if it has been initialised.
pub fn get(&self) -> Option<&T>
{
unsafe {
@ -82,6 +152,8 @@ impl<'a, T> Init<'a, T>
}
}
}
/// Get a mutable reference to the value if it has been initialised.
pub fn get_mut(&mut self) -> Option<&mut T>
{
unsafe {

@ -7,11 +7,15 @@ use std::{
marker::{
Send,Sync,
},
ops::{
Drop,
},
};
use ptr::{
VoidPointer,
};
/// An iterator that consumes `HeapArray<T>` instance and ensures all memory is appropriately freed when consumed or dropped.
pub struct IntoIter<T>
{
start: *mut T,
@ -20,7 +24,7 @@ pub struct IntoIter<T>
}
unsafe impl<T: Send> Send for IntoIter<T>{}
unsafe impl<T: Sync> Sync for IntoIter<T>{}
unsafe impl<T: Sync> Sync for IntoIter<T>{} //this is probably fine right?
impl<T> IntoIter<T>
{
@ -39,6 +43,31 @@ impl<T> IntoIter<T>
self.start = ptr::null();
}
}
fn drain_if_needed(&mut self)
{
if self.start != ptr::null() {
unsafe {
if self.current_offset<self.sz {
for i in self.current_offset..self.sz
{
drop(ptr::take(self.start.offset(i as isize)));
}
}
alloc::free(self.start as VoidPointer);
}
self.start = ptr::null();
}
}
}
impl<T> Drop for IntoIter<T>
{
fn drop(&mut self)
{
self.drain_if_needed();
}
}
impl<T> Iterator for IntoIter<T>

@ -75,6 +75,10 @@ mod tests {
{
assert_eq!(&x[..6], "string");
}
let non = heap!["strings".to_owned(), "strings!!!".to_owned()];
let iter = non.into_iter();
drop(iter);
}
#[test]
@ -117,11 +121,36 @@ mod tests {
{
string.put("Hiya".to_owned());
}
assert_eq!(array.len(), 32);
for x in array.into_iter()
{
assert_eq!(x, "Hiya");
}
let mut array = heap![String; 10];
array.initialise().fill("wowe".to_owned());
for x in array.into_iter()
{
assert_eq!(x, "wowe");
}
let mut array = heap![String; 10];
array.initialise().fill_with(|| "wow".to_owned());
for x in array.into_iter()
{
assert_eq!(x, "wow");
}
let mut array = heap![String; 10];
array.initialise().fill_default();
for x in array.into_iter()
{
assert_eq!(x, "");
}
}
}
@ -129,6 +158,7 @@ mod ptr;
mod alloc;
mod reinterpret;
pub mod init;
pub use init::InitIterExt;
use std::{
ops::{
@ -270,7 +300,7 @@ impl<T> HeapArray<T>
std::mem::size_of::<T>() == 1
}
/// Create an iterator for safely setting potentially uninitialised values within the instance.
pub fn initialise<'a>(&'a mut self) -> init::InitIter<'a, T>
{
init::InitIter::new(self, 0)
@ -441,7 +471,7 @@ impl<T> HeapArray<T>
self.free();
}
/// Coerce of clone memory from a boxed slice.
/// Coerce or clone memory from a boxed slice.
pub fn from_boxed_slice(bx: Box<[T]>) -> Self
{
#[cfg(feature="assume_libc")]

Loading…
Cancel
Save