Struct ContiguousMemoryStorage

Source
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>

Source

pub fn new(capacity: usize) -> Self

Creates a new ContiguousMemory instance with the specified capacity, aligned as platform dependant alignment of usize.

Source

pub fn new_aligned( capacity: usize, alignment: usize, ) -> Result<Self, LayoutError>

Creates a new ContiguousMemory instance with the specified capacity and alignment.

Source

pub fn new_for_layout(layout: Layout) -> Self

Creates a new ContiguousMemory instance with the provided layout.

Source

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.

Source

pub fn get_layout(&self) -> Layout

Returns the layout of the memory region containing stored data.

Source

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.

Source

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

See: ContiguousMemoryStorage::resize

Source

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

See: ContiguousMemoryStorage::resize

Source

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

See: ContiguousMemoryStorage::resize

Source

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:

§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.

Source

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.

Source

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.

Source

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.

Source

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>

Source

pub fn get_base(&self) -> *const ()

Returns the base address of the allocated memory.

Source

pub fn can_push<T: StoreRequirements>(&self) -> bool

Returns true if provided generic type T can be stored without growing the container.

Source

pub fn can_push_value<T: StoreRequirements>(&self, value: &T) -> bool

Returns true if the provided value can be stored without growing the container.

Source

pub fn can_push_layout(&self, layout: Layout) -> bool

Returns true if the provided layout can be stored without growing the container.

Source

pub fn shrink_to_fit(&mut self) -> usize

Shrinks the allocated memory to fit the currently stored data and returns the new capacity.

Source

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>

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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>

Source

pub fn get_base(&self) -> *const ()

Returns the base address of the allocated memory.

Source

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");
Source

pub fn can_push_value<T: StoreRequirements>(&self, value: &T) -> bool

Returns true if the provided value can be stored without growing the container.

Source

pub fn can_push_layout(&self, layout: Layout) -> bool

Returns true if the provided layout can be stored without growing the container.

Source

pub fn shrink_to_fit(&mut self) -> usize

Shrinks the allocated memory to fit the currently stored data and returns the new capacity.

Source

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.

Source

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.

Source

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.

Source

pub fn forget(self) -> (*const (), Layout)

Forgets this container without dropping it and returns its base address and Layout.

For details on safety see Safety section of default implementation.

Trait Implementations§

Source§

impl<Impl: ImplDetails> Clone for ContiguousMemoryStorage<Impl>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<Impl: ImplDetails> Debug for ContiguousMemoryStorage<Impl>
where Impl::StorageState: Debug,

Available on crate feature debug only.
Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<Impl: ImplDetails> Deref for ContiguousMemoryStorage<Impl>

Source§

type Target = ContiguousMemoryState<Impl>

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Self::Target

Dereferences the value.

Auto Trait Implementations§

§

impl<Impl> Freeze for ContiguousMemoryStorage<Impl>
where <Impl as ImplBase>::StorageState: Freeze,

§

impl<Impl> RefUnwindSafe for ContiguousMemoryStorage<Impl>
where <Impl as ImplBase>::StorageState: RefUnwindSafe,

§

impl<Impl> Send for ContiguousMemoryStorage<Impl>
where <Impl as ImplBase>::StorageState: Send,

§

impl<Impl> Sync for ContiguousMemoryStorage<Impl>
where <Impl as ImplBase>::StorageState: Sync,

§

impl<Impl> Unpin for ContiguousMemoryStorage<Impl>
where <Impl as ImplBase>::StorageState: Unpin,

§

impl<Impl> UnwindSafe for ContiguousMemoryStorage<Impl>
where <Impl as ImplBase>::StorageState: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.