Struct contiguous_mem::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. This struct also implements StoreData for all of the
details which specifies underlying logic for storing items.
Note that this structure is a smart abstraction over underlying data, copying it creates a copy which represents the same internal state.
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.
Examples found in repository?
8 9 10 11 12 13 14 15 16 17 18 19 20
fn main() {
// Create a ContiguousMemory instance with a capacity of 1024 bytes and 1-byte alignment
let mut memory = ContiguousMemory::new(1024);
// Store data in the memory container
let data = Data { value: 42 };
let stored_number: ContiguousMemoryRef<u64> = memory.store(22u64);
let stored_data: ContiguousMemoryRef<Data> = memory.store(data);
// Retrieve and use the stored data
assert_eq!(*stored_data.get(), data);
assert_eq!(*stored_number.get(), 22);
}More examples
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
fn main() {
// Create a ContiguousMemory instance with a capacity of 1024 bytes and 1-byte alignment
let mut memory = UnsafeContiguousMemory::new(1024);
// Store data in the memory container
let data = Data { value: 42 };
let stored_number: *mut u64 = memory
.store(22u64)
.expect("there should be enough space to store a number");
let stored_data: *mut Data = memory
.store(data)
.expect("there should be enough space to store Data");
// Retrieve and use the stored data
unsafe {
assert_eq!(*stored_data, data);
assert_eq!(*stored_number, 22);
}
}8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
fn main() {
let storage = SyncContiguousMemory::new(4096);
let mut sent_storage = storage.clone();
let writer_one =
std::thread::spawn(move || sent_storage.store(22u64).expect("unable to store number"));
let data = Data { value: 42 };
let mut sent_storage = storage.clone();
let writer_two = std::thread::spawn(move || {
sent_storage
.store(Data { value: 42 })
.expect("unable to store Data")
});
let stored_number: SyncContiguousMemoryRef<u64> =
writer_one.join().expect("unable to join number thread");
let mut stored_number_clone = stored_number.clone();
let stored_data: SyncContiguousMemoryRef<Data> =
writer_two.join().expect("unable to join Data thread");
let number_ref = stored_number
.get()
.expect("number ref poisoned on first use");
let stored_data = stored_data.get().expect("Data ref poisoned on first use");
// note that number is still locked here
assert!(
stored_number_clone.try_get_mut().is_err(),
"number reference should not be writable as the number is currently borrowed"
);
assert_eq!(*number_ref, 22);
assert_eq!(*stored_data, data);
}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 get_base(&self) -> Impl::LockResult<*mut u8>
pub fn get_base(&self) -> Impl::LockResult<*mut u8>
Returns the base address (*mut u8) of the allocated memory.
Errors
For concurrent implementation this function can return LockingError::Poisoned if the mutex holding the base address has been poisoned.
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.
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
This function can return the following errors:
-
ContiguousMemoryError::Unshrinkable: Returned when attempting to shrink the memory container, but the stored data prevents the container from being shrunk to the desired capacity. -
ContiguousMemoryError::Lock: Returned if the mutex holding the base address or theAllocationTrackeris poisoned.
sourcepub fn shrink_to_fit(&mut self) -> Result<(), ContiguousMemoryError>
pub fn shrink_to_fit(&mut self) -> Result<(), ContiguousMemoryError>
Shrinks the allocated memory to fit the currently stored data.
sourcepub fn store<T: StoreRequirements>(
&mut self,
value: T
) -> <Impl as StorageDetails>::StoreResult<T>where
Self: StoreData<Impl>,
pub fn store<T: StoreRequirements>( &mut self, value: T ) -> <Impl as StorageDetails>::StoreResult<T>where Self: StoreData<Impl>,
Stores a value of type T in the contiguous memory block.
Value type is used to deduce type size and returned reference dropping behavior.
Returned value is implementation specific:
- For concurrent implementation it is
Result<SyncContiguousMemoryRef<T>, LockingError>, - For default implementation it is
ContiguousMemoryRef<T>, - For fixed implementation it is
Result<*mut u8, ContiguousMemoryError>.
Examples found in repository?
8 9 10 11 12 13 14 15 16 17 18 19 20
fn main() {
// Create a ContiguousMemory instance with a capacity of 1024 bytes and 1-byte alignment
let mut memory = ContiguousMemory::new(1024);
// Store data in the memory container
let data = Data { value: 42 };
let stored_number: ContiguousMemoryRef<u64> = memory.store(22u64);
let stored_data: ContiguousMemoryRef<Data> = memory.store(data);
// Retrieve and use the stored data
assert_eq!(*stored_data.get(), data);
assert_eq!(*stored_number.get(), 22);
}More examples
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
fn main() {
// Create a ContiguousMemory instance with a capacity of 1024 bytes and 1-byte alignment
let mut memory = UnsafeContiguousMemory::new(1024);
// Store data in the memory container
let data = Data { value: 42 };
let stored_number: *mut u64 = memory
.store(22u64)
.expect("there should be enough space to store a number");
let stored_data: *mut Data = memory
.store(data)
.expect("there should be enough space to store Data");
// Retrieve and use the stored data
unsafe {
assert_eq!(*stored_data, data);
assert_eq!(*stored_number, 22);
}
}8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
fn main() {
let storage = SyncContiguousMemory::new(4096);
let mut sent_storage = storage.clone();
let writer_one =
std::thread::spawn(move || sent_storage.store(22u64).expect("unable to store number"));
let data = Data { value: 42 };
let mut sent_storage = storage.clone();
let writer_two = std::thread::spawn(move || {
sent_storage
.store(Data { value: 42 })
.expect("unable to store Data")
});
let stored_number: SyncContiguousMemoryRef<u64> =
writer_one.join().expect("unable to join number thread");
let mut stored_number_clone = stored_number.clone();
let stored_data: SyncContiguousMemoryRef<Data> =
writer_two.join().expect("unable to join Data thread");
let number_ref = stored_number
.get()
.expect("number ref poisoned on first use");
let stored_data = stored_data.get().expect("Data ref poisoned on first use");
// note that number is still locked here
assert!(
stored_number_clone.try_get_mut().is_err(),
"number reference should not be writable as the number is currently borrowed"
);
assert_eq!(*number_ref, 22);
assert_eq!(*stored_data, data);
}sourcepub fn can_store<T: StoreRequirements>(
&self,
value: &T
) -> Result<bool, ContiguousMemoryError>
pub fn can_store<T: StoreRequirements>( &self, value: &T ) -> Result<bool, ContiguousMemoryError>
Returns true if the provided value can be stored.
If the AllocationTracker can’t be immutably accesed, a
ContiguousMemoryError::TrackerInUse error is returned.
For concurrent implementation a ContiguousMemoryError::Lock is
returned under same conditions.
Unsafe implementation never fails.
source§impl ContiguousMemoryStorage<ImplUnsafe>
impl ContiguousMemoryStorage<ImplUnsafe>
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.
Trait Implementations§
source§impl<Impl: ImplDetails> Clone for ContiguousMemoryStorage<Impl>
impl<Impl: ImplDetails> Clone for ContiguousMemoryStorage<Impl>
source§impl<Impl: ImplDetails> Deref for ContiguousMemoryStorage<Impl>
impl<Impl: ImplDetails> Deref for ContiguousMemoryStorage<Impl>
source§impl StoreData<ImplConcurrent> for ContiguousMemoryStorage<ImplConcurrent>
impl StoreData<ImplConcurrent> for ContiguousMemoryStorage<ImplConcurrent>
source§unsafe fn store_data<T: StoreRequirements>(
&mut self,
data: *mut T,
layout: Layout
) -> Result<SyncContiguousMemoryRef<T>, LockingError>
unsafe fn store_data<T: StoreRequirements>( &mut self, data: *mut T, layout: Layout ) -> Result<SyncContiguousMemoryRef<T>, LockingError>
Returns a SyncContiguousMemoryRef pointing to the stored value, or a
LockingError::Poisoned error when the AllocationTracker
associated with the memory container is poisoned.
source§impl StoreData<ImplDefault> for ContiguousMemoryStorage<ImplDefault>
impl StoreData<ImplDefault> for ContiguousMemoryStorage<ImplDefault>
source§unsafe fn store_data<T: StoreRequirements>(
&mut self,
data: *mut T,
layout: Layout
) -> ContiguousMemoryRef<T>
unsafe fn store_data<T: StoreRequirements>( &mut self, data: *mut T, layout: Layout ) -> ContiguousMemoryRef<T>
Returns a ContiguousMemoryRef pointing to the stored value.
source§impl StoreData<ImplUnsafe> for ContiguousMemoryStorage<ImplUnsafe>
impl StoreData<ImplUnsafe> for ContiguousMemoryStorage<ImplUnsafe>
source§unsafe fn store_data<T: StoreRequirements>(
&mut self,
data: *mut T,
layout: Layout
) -> Result<*mut T, ContiguousMemoryError>
unsafe fn store_data<T: StoreRequirements>( &mut self, data: *mut T, layout: Layout ) -> Result<*mut T, ContiguousMemoryError>
Returns a raw pointer (*mut T) to the stored value or 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.