Skip to content

Commit

Permalink
Fix bugs on resizing
Browse files Browse the repository at this point in the history
Remove prelude module
Cleanup documentation

Signed-off-by: Tin Svagelj <tin.svagelj@live.com>
  • Loading branch information
Caellian committed Sep 16, 2023
1 parent ea81008 commit 99fca58
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 82 deletions.
37 changes: 37 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,43 @@
"args": [],
"cwd": "${workspaceFolder}"
},
{
"type": "lldb",
"request": "launch",
"name": "Debug example 'failing'",
"cargo": {
"args": [
"build",
"--example=failing",
"--package=contiguous-mem"
],
"filter": {
"name": "failing",
"kind": "example"
}
},
"args": [],
"cwd": "${workspaceFolder}"
},
{
"type": "lldb",
"request": "launch",
"name": "Debug unit tests in example 'failing'",
"cargo": {
"args": [
"test",
"--no-run",
"--example=failing",
"--package=contiguous-mem"
],
"filter": {
"name": "failing",
"kind": "example"
}
},
"args": [],
"cwd": "${workspaceFolder}"
},
{
"type": "lldb",
"request": "launch",
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,13 @@ on access.

## Use cases

- Ensuring stored data is placed adjacently in memory. ([example](./examples/game_loading.rs))
- Storing differently typed/sized data. ([example](./examples/default_impl.rs))
- Ensuring stored data is placed adjacently in memory. ([example](./examples/game_loading.rs))
- Note that for this use case implementations other than unsafe aren't ideal
for ensuring cache locality as returned references are smart pointers which
will be stored elsewhere in memory. Other implementations are however useful
for constructing contiguous data from code which would require complicated
memory management otherwise.

## Tradeoffs

Expand Down Expand Up @@ -79,7 +84,7 @@ contiguous_mem = { version = "0.4.*", default-features = false, features = ["no_
### Usage

```rust
use contiguous_mem::prelude::*;
use contiguous_mem::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Data {
Expand Down
2 changes: 1 addition & 1 deletion examples/default_impl.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use contiguous_mem::prelude::*;
use contiguous_mem::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Data {
Expand Down
2 changes: 1 addition & 1 deletion examples/game_loading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{
};

use byteorder::{ReadBytesExt, WriteBytesExt, LE};
use contiguous_mem::prelude::*;
use contiguous_mem::*;

pub enum IndexOrPtr<T> {
Index(u32),
Expand Down
2 changes: 1 addition & 1 deletion examples/ptr_metadata.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![feature(ptr_metadata)]

use contiguous_mem::prelude::*;
use contiguous_mem::*;

trait Greetable {
fn print_hello(&self);
Expand Down
2 changes: 1 addition & 1 deletion examples/sync_impl.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use contiguous_mem::prelude::*;
use contiguous_mem::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Data {
Expand Down
2 changes: 1 addition & 1 deletion examples/unsafe_impl.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use contiguous_mem::prelude::*;
use contiguous_mem::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Data {
Expand Down
55 changes: 33 additions & 22 deletions src/details.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,8 @@ pub trait ImplBase: Sized {
const USES_LOCKS: bool = false;
}

/// A marker struct representing the behavior specialization that does not
/// require thread-safety. This implementation skips mutexes, making it faster
/// but unsuitable for concurrent usage.
/// Implementation that's not thread-safe but performs faster as it avoids
/// mutexes and locks.
///
/// For example usage of default implementation see: [`ContiguousMemory`](crate::ContiguousMemory)
#[cfg_attr(feature = "debug", derive(Debug))]
Expand All @@ -63,9 +62,7 @@ impl ImplBase for ImplDefault {
type LockResult<T> = T;
}

/// A marker struct representing the behavior specialization for thread-safe
/// operations. This implementation ensures that the container's operations can
/// be used safely in asynchronous contexts, utilizing mutexes to prevent data
/// Thread-safe implementation utilizing mutexes and locks to prevent data
/// races.
///
/// For example usage of default implementation see:
Expand All @@ -81,9 +78,7 @@ impl ImplBase for ImplConcurrent {
const USES_LOCKS: bool = true;
}

/// A marker struct representing the behavior specialization for unsafe
/// implementation. Should be used when the container is guaranteed to outlive
/// any pointers to data contained in represented memory block.
/// Implementation which provides direct (unsafe) access to stored entries.
///
/// For example usage of default implementation see:
/// [`UnsafeContiguousMemory`](crate::UnsafeContiguousMemory)
Expand Down Expand Up @@ -574,7 +569,7 @@ impl ReferenceDetails for ImplUnsafe {
pub trait StoreDataDetails: StorageDetails {
unsafe fn push_raw<T: StoreRequirements>(
state: &mut Self::StorageState,
data: *mut T,
data: *const T,
layout: Layout,
) -> Self::PushResult<T>;

Expand All @@ -587,7 +582,7 @@ pub trait StoreDataDetails: StorageDetails {
impl StoreDataDetails for ImplConcurrent {
unsafe fn push_raw<T: StoreRequirements>(
state: &mut Self::StorageState,
data: *mut T,
data: *const T,
layout: Layout,
) -> Result<SyncContiguousEntryRef<T>, LockingError> {
let (addr, range) = loop {
Expand All @@ -600,8 +595,19 @@ impl StoreDataDetails for ImplConcurrent {
break (found, taken);
}
Err(ContiguousMemoryError::NoStorageLeft) => {
match ImplConcurrent::resize_container(state, ImplConcurrent::get_capacity(&ImplConcurrent::deref_state(state).capacity) * 2) {
Ok(_) => {}
let curr_capacity =
ImplConcurrent::get_capacity(&ImplConcurrent::deref_state(state).capacity);
let new_capacity = curr_capacity
.saturating_mul(2)
.max(curr_capacity + layout.size());
match ImplConcurrent::resize_container(state, new_capacity) {
Ok(_) => {
match ImplConcurrent::resize_tracker(state, new_capacity) {
Ok(_) => {},
Err(ContiguousMemoryError::Lock(locking_err)) => return Err(locking_err),
Err(_) => unreachable!("unable to grow AllocationTracker"),
};
}
Err(ContiguousMemoryError::Lock(locking_err)) => return Err(locking_err),
Err(other) => unreachable!(
"reached unexpected error while growing the container to store data: {:?}",
Expand Down Expand Up @@ -638,7 +644,7 @@ impl StoreDataDetails for ImplConcurrent {
impl StoreDataDetails for ImplDefault {
unsafe fn push_raw<T: StoreRequirements>(
state: &mut Self::StorageState,
data: *mut T,
data: *const T,
layout: Layout,
) -> ContiguousEntryRef<T> {
let (addr, range) = loop {
Expand All @@ -653,8 +659,15 @@ impl StoreDataDetails for ImplDefault {
break (found, taken);
}
Err(ContiguousMemoryError::NoStorageLeft) => {
match ImplDefault::resize_container(state, ImplDefault::get_capacity(&ImplDefault::deref_state(state).capacity) * 2) {
Ok(_) => {},
let curr_capacity =
ImplDefault::get_capacity(&ImplDefault::deref_state(state).capacity);
let new_capacity = curr_capacity
.saturating_mul(2)
.max(curr_capacity + layout.size());
match ImplDefault::resize_container(state, new_capacity) {
Ok(_) => {
ImplDefault::resize_tracker(state, new_capacity).expect("unable to grow AllocationTracker");
},
Err(err) => unreachable!(
"reached unexpected error while growing the container to store data: {:?}",
err
Expand Down Expand Up @@ -682,10 +695,11 @@ impl StoreDataDetails for ImplDefault {
}

impl StoreDataDetails for ImplUnsafe {
/// Returns a raw pointer (`*mut T`) to the stored value or
/// Returns a raw pointer (`*mut T`) to the stored value or an error if no
/// free regions remain
unsafe fn push_raw<T: StoreRequirements>(
state: &mut Self::StorageState,
data: *mut T,
data: *const T,
layout: Layout,
) -> Result<*mut T, ContiguousMemoryError> {
let (addr, range) = loop {
Expand Down Expand Up @@ -718,14 +732,11 @@ impl StoreDataDetails for ImplUnsafe {
}

/// Trait representing requirements for implementation details of the
/// [`ContiguousMemoryStorage`](ContiguousMemoryStorage).
/// [`ContiguousMemoryStorage`](crate::ContiguousMemoryStorage).
///
/// This trait is implemented by:
/// - [`ImplDefault`]
/// - [`ImplConcurrent`]
/// - [`ImplUnsafe`]
///
/// As none of the underlying traits can't be implemented, changes to this trait
/// aren't considered breaking and won't affect semver.
pub trait ImplDetails: ImplBase + StorageDetails + ReferenceDetails + StoreDataDetails {}
impl<Impl: ImplBase + StorageDetails + ReferenceDetails + StoreDataDetails> ImplDetails for Impl {}
7 changes: 3 additions & 4 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,10 @@ pub enum ContiguousMemoryError {
pub enum LockSource {
/// Mutex containing the base memory offset was poisoned.
BaseAddress,
/// [`AllocationTracker`](crate::tracker::AllocationTracker) mutex was
/// poisoned.
/// `AllocationTracker` mutex was poisoned.
AllocationTracker,
/// Concurrent mutable access exclusion flag in
/// [`ReferenceState`](crate::refs) was poisoned.
/// Concurrent mutable access exclusion flag in `ReferenceState` was
/// poisoned.
Reference,
}

Expand Down
Loading

0 comments on commit 99fca58

Please sign in to comment.