pub struct ContiguousMemoryStorage<Impl: ImplDetails = ImplDefault> { /* private fields */ }
Expand description
A memory container for efficient allocation and storage of contiguous data.
This collection manages a contiguous block of memory, allowing for storage of arbitrary data types while ensuring that stored items are placed adjacently and ensuring they’re properly alligned.
Type argument Impl
specifies implementation details for the behavior of
this struct.
Note that this structure is a smart abstraction over underlying data,
copying it creates a copy which represents the same internal state. If you
need to copy the memory region into a new container see:
ContiguousMemoryStorage::copy_data
Implementations§
Source§impl<Impl: ImplDetails> ContiguousMemoryStorage<Impl>
impl<Impl: ImplDetails> ContiguousMemoryStorage<Impl>
Sourcepub fn new(capacity: usize) -> Self
pub fn new(capacity: usize) -> Self
Creates a new ContiguousMemory
instance with the specified capacity
,
aligned as platform dependant alignment of usize
.
Sourcepub fn new_aligned(
capacity: usize,
alignment: usize,
) -> Result<Self, LayoutError>
pub fn new_aligned( capacity: usize, alignment: usize, ) -> Result<Self, LayoutError>
Creates a new ContiguousMemory
instance with the specified capacity
and alignment
.
Sourcepub fn new_for_layout(layout: Layout) -> Self
pub fn new_for_layout(layout: Layout) -> Self
Creates a new ContiguousMemory
instance with the provided layout
.
Sourcepub fn get_capacity(&self) -> usize
pub fn get_capacity(&self) -> usize
Returns the current capacity of the memory container.
The capacity represents the size of the memory block that has been allocated for storing data. It may be larger than the amount of data currently stored within the container.
Sourcepub fn get_layout(&self) -> Layout
pub fn get_layout(&self) -> Layout
Returns the layout of the memory region containing stored data.
Sourcepub fn resize(
&mut self,
new_capacity: usize,
) -> Result<Option<*mut u8>, ContiguousMemoryError>
pub fn resize( &mut self, new_capacity: usize, ) -> Result<Option<*mut u8>, ContiguousMemoryError>
Resizes the memory container to the specified new_capacity
, optionally
returning the new base address of the stored items - if None
is
returned the base address of the memory block is the same.
Shrinking the container is generally performed in place by freeing tailing memory space, but growing it can move the data in memory to find a location that can fit it.
Unsafe implementation should match on the returned value and update any existing pointers accordingly.
§Errors
ContiguousMemoryError::Unshrinkable
error is returned when
attempting to shrink the memory container, but previously stored data
prevents the container from being shrunk to the desired capacity.
In a concurrent implementation ContiguousMemoryError::Lock
is
returned if the mutex holding the base address or the
AllocationTracker
is poisoned.
Sourcepub fn reserve(
&mut self,
additional: usize,
) -> Result<Option<*mut ()>, ContiguousMemoryError>
pub fn reserve( &mut self, additional: usize, ) -> Result<Option<*mut ()>, ContiguousMemoryError>
Reserves exactly additional
bytes.
After calling this function, new capacity will be equal to:
self.get_capacity() + additional
.
§Errors
Sourcepub fn reserve_type<V>(
&mut self,
) -> Result<Option<*mut ()>, ContiguousMemoryError>
pub fn reserve_type<V>( &mut self, ) -> Result<Option<*mut ()>, ContiguousMemoryError>
Reserves exactly additional bytes required to store a value of type V
.
After calling this function, new capacity will be equal to:
self.get_capacity() + size_of::<V>()
.
§Errors
Sourcepub fn reserve_type_count<V>(
&mut self,
count: usize,
) -> Result<Option<*mut ()>, ContiguousMemoryError>
pub fn reserve_type_count<V>( &mut self, count: usize, ) -> Result<Option<*mut ()>, ContiguousMemoryError>
Reserves exactly additional bytes required to store count
number of
values of type V
.
After calling this function, new capacity will be equal to:
self.get_capacity() + size_of::<V>() * count
.
§Errors
Sourcepub fn push<T: StoreRequirements>(&mut self, value: T) -> Impl::PushResult<T>
pub fn push<T: StoreRequirements>(&mut self, value: T) -> Impl::PushResult<T>
Stores a value
of type T
in the contiguous memory block and returns
a reference or a pointer pointing to it.
Value type argument T
is used to deduce type size and returned
reference dropping behavior.
Returned value is implementation specific:
Implementation | Result | Alias |
---|---|---|
Default | ContiguousEntryRef<T> | CERef |
Concurrent | SyncContiguousEntryRef<T> | SCERef |
Unsafe | *mut T | N/A |
§Errors
§Concurrent implementation
Concurrent implementation returns a
LockingError::Poisoned
error
when the AllocationTracker
associated with the memory container is
poisoned.
§Unsafe implementation
Unsafe implementation returns a ContiguousMemoryError::NoStorageLeft
indicating that the container couldn’t store the provided data with
current size.
Memory block can still be grown by calling ContiguousMemory::resize
,
but it can’t be done automatically as that would invalidate all the
existing pointers without any indication.
Sourcepub fn push_persisted<T: StoreRequirements>(
&mut self,
value: T,
) -> Impl::PushResult<T>where
Impl::ReferenceType<T>: EntryRef,
pub fn push_persisted<T: StoreRequirements>(
&mut self,
value: T,
) -> Impl::PushResult<T>where
Impl::ReferenceType<T>: EntryRef,
Stores a value
of type T
in the contiguous memory block and returns
a reference to it which doesn’t mark the memory segment as free when
dropped.
See ContiguousMemoryStorage::push
for details.
Sourcepub unsafe fn push_raw<T: StoreRequirements>(
&mut self,
data: *const T,
layout: Layout,
) -> Impl::PushResult<T>
pub unsafe fn push_raw<T: StoreRequirements>( &mut self, data: *const T, layout: Layout, ) -> Impl::PushResult<T>
Works same as push
but takes a pointer and
layout.
Pointer type is used to deduce the destruction behavior for
implementations that return a reference, but can be disabled by casting
the provided pointer into *const ()
type and then calling
transmute
on the returned reference:
let value = vec!["ignore", "drop", "for", "me"];
let erased = &value as *const Vec<&str> as *const ();
let layout = Layout::new::<Vec<&str>>();
let stored: CERef<Vec<&str>> = unsafe {
mem::transmute(storage.push_raw(erased, layout))
};
§Safety
This function is unsafe because it clones memory from provided pointer which means it could cause a segmentation fault if the pointer is invalid.
Further, it also allows escaping type drop glue because it takes type
Layout
as a separate argument.
Sourcepub unsafe fn push_raw_persisted<T: StoreRequirements>(
&mut self,
data: *const T,
layout: Layout,
) -> Impl::PushResult<T>where
Impl::ReferenceType<T>: EntryRef,
pub unsafe fn push_raw_persisted<T: StoreRequirements>(
&mut self,
data: *const T,
layout: Layout,
) -> Impl::PushResult<T>where
Impl::ReferenceType<T>: EntryRef,
Variant of push_raw
which returns a
reference that doesn’t mark the used memory segment as free when
dropped.
Sourcepub fn assume_stored<T: StoreRequirements>(
&self,
position: usize,
) -> Impl::LockResult<Impl::ReferenceType<T>>
pub fn assume_stored<T: StoreRequirements>( &self, position: usize, ) -> Impl::LockResult<Impl::ReferenceType<T>>
Assumes value is stored at the provided relative position
in
managed memory and returns a pointer or a reference to it.
§Example
let mut storage = UnsafeContiguousMemory::new(128);
let initial_position = storage.push(278u32).unwrap();
// ...other code...
let base_addr = storage.get_base();
storage.resize(512);
let new_position: *mut u32 = storage.assume_stored(
initial_position as usize - base_addr as usize
);
unsafe {
assert_eq!(*new_position, 278u32);
}
§Safety
This functions isn’t unsafe because creating an invalid pointer isn’t considered unsafe. Responsibility for guaranteeing safety falls on code that’s dereferencing the pointer.
Source§impl ContiguousMemoryStorage<ImplDefault>
impl ContiguousMemoryStorage<ImplDefault>
Sourcepub fn can_push<T: StoreRequirements>(&self) -> bool
pub fn can_push<T: StoreRequirements>(&self) -> bool
Returns true
if provided generic type T
can be stored without
growing the container.
Sourcepub fn can_push_value<T: StoreRequirements>(&self, value: &T) -> bool
pub fn can_push_value<T: StoreRequirements>(&self, value: &T) -> bool
Returns true
if the provided value
can be stored without growing the
container.
Sourcepub fn can_push_layout(&self, layout: Layout) -> bool
pub fn can_push_layout(&self, layout: Layout) -> bool
Returns true
if the provided layout
can be stored without growing
the container.
Sourcepub fn shrink_to_fit(&mut self) -> usize
pub fn shrink_to_fit(&mut self) -> usize
Shrinks the allocated memory to fit the currently stored data and returns the new capacity.
Sourcepub fn forget(self) -> (*const (), Layout)
pub fn forget(self) -> (*const (), Layout)
Forgets this container without dropping it and returns its base address
and Layout
.
§Safety
Calling this method will create a memory leak because the smart pointer
to state will not be dropped even when all of the created references go
out of scope. As this method takes ownership of the container, calling
it also ensures that dereferencing pointers created by
as_ptr
,
as_ptr_mut
,
into_ptr
, and
into_ptr_mut
ContiguousEntryRef
methods is guaranteed to be safe.
This method isn’t unsafe as leaking data doesn’t cause undefined behavior. (see details)
Source§impl ContiguousMemoryStorage<ImplConcurrent>
impl ContiguousMemoryStorage<ImplConcurrent>
Sourcepub fn get_base(&self) -> Result<*const (), LockingError>
pub fn get_base(&self) -> Result<*const (), LockingError>
Returns the base address of the allocated memory or a
LockingError::Poisoned
error if the mutex holding the base address
has been poisoned.
This function will block the current thread until base address RwLock doesn’t become readable.
Sourcepub fn can_push<T: StoreRequirements>(&self) -> Result<bool, LockingError>
pub fn can_push<T: StoreRequirements>(&self) -> Result<bool, LockingError>
Returns true
if provided generic type T
can be stored without
growing the container or a LockingError::Poisoned
error if
allocation tracker mutex has been poisoned.
This function will block the current thread until internal allocation tracked doesn’t become available.
Sourcepub fn can_push_value<T: StoreRequirements>(
&self,
value: &T,
) -> Result<bool, LockingError>
pub fn can_push_value<T: StoreRequirements>( &self, value: &T, ) -> Result<bool, LockingError>
Returns true
if the provided value
can be stored without growing the
container or a LockingError::Poisoned
error if allocation tracker
mutex has been poisoned.
This function will block the current thread until internal allocation tracked doesn’t become available.
Sourcepub fn can_push_layout(&self, layout: Layout) -> Result<bool, LockingError>
pub fn can_push_layout(&self, layout: Layout) -> Result<bool, LockingError>
Returns true
if the provided layout
can be stored without growing
the container or a LockingError::Poisoned
error if allocation
tracker mutex has been poisoned.
This function will block the current thread until internal allocation tracked doesn’t become available.
Sourcepub fn shrink_to_fit(&mut self) -> Result<usize, LockingError>
pub fn shrink_to_fit(&mut self) -> Result<usize, LockingError>
Shrinks the allocated memory to fit the currently stored data and returns the new capacity.
This function will block the current thread until internal allocation tracked doesn’t become available.
Sourcepub fn forget(self) -> Result<(*const (), Layout), LockingError>
pub fn forget(self) -> Result<(*const (), Layout), LockingError>
Forgets this container without dropping it and returns its base address
and Layout
, or a LockingError::Poisoned
error if base address
RwLock
has been poisoned.
For details on safety see Safety section of default implementation.
Source§impl ContiguousMemoryStorage<ImplUnsafe>
impl ContiguousMemoryStorage<ImplUnsafe>
Sourcepub fn can_push<T: StoreRequirements>(&self) -> bool
pub fn can_push<T: StoreRequirements>(&self) -> bool
Returns true
if the provided value can be stored without growing the
container.
It’s usually clearer to try storing the value directly and then handle the case where it wasn’t stored through error matching.
§Example
let mut storage = UnsafeContiguousMemory::new(0);
let value = [2, 4, 8, 16];
if !storage.can_push::<Vec<i32>>() {
storage.resize(storage.get_capacity() + size_of_val(&value));
// ...update old pointers...
}
let stored_value =
storage.push(value).expect("unable to store after growing the container");
Sourcepub fn can_push_value<T: StoreRequirements>(&self, value: &T) -> bool
pub fn can_push_value<T: StoreRequirements>(&self, value: &T) -> bool
Returns true
if the provided value
can be stored without growing the
container.
Sourcepub fn can_push_layout(&self, layout: Layout) -> bool
pub fn can_push_layout(&self, layout: Layout) -> bool
Returns true
if the provided layout
can be stored without growing
the container.
Sourcepub fn shrink_to_fit(&mut self) -> usize
pub fn shrink_to_fit(&mut self) -> usize
Shrinks the allocated memory to fit the currently stored data and returns the new capacity.
Sourcepub fn copy_data(&self) -> Self
pub fn copy_data(&self) -> Self
Clones the allocated memory region into a new ContiguousMemoryStorage.
This function isn’t unsafe, even though it ignores presence of Copy
bound on stored data, because it doesn’t create any pointers.
Sourcepub unsafe fn free_typed<T>(&mut self, position: *mut T)
pub unsafe fn free_typed<T>(&mut self, position: *mut T)
Allows freeing a memory range stored at provided position
.
Type of the position pointer T
determines the size of the freed chunk.
§Safety
This function is considered unsafe because it can mark a memory range as free while a valid reference is pointing to it from another place in code.
Sourcepub unsafe fn free<T>(&mut self, position: *mut T, size: usize)
pub unsafe fn free<T>(&mut self, position: *mut T, size: usize)
Allows freeing a memory range stored at provided position
with the
specified size
.
§Safety
This function is considered unsafe because it can mark a memory range as free while a valid reference is pointing to it from another place in code.
Trait Implementations§
Source§impl<Impl: ImplDetails> Clone for ContiguousMemoryStorage<Impl>
impl<Impl: ImplDetails> Clone for ContiguousMemoryStorage<Impl>
Source§impl<Impl: ImplDetails> Debug for ContiguousMemoryStorage<Impl>where
Impl::StorageState: Debug,
Available on crate feature debug
only.
impl<Impl: ImplDetails> Debug for ContiguousMemoryStorage<Impl>where
Impl::StorageState: Debug,
debug
only.