Skip to content

Commit

Permalink
SlotMap, SecondaryMap or SparseSecondaryMap as storage. Removed no_st…
Browse files Browse the repository at this point in the history
…d (for now)
  • Loading branch information
DoctorWhoof committed Nov 21, 2024
1 parent 6e9bf11 commit 66791dd
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 30 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ description = "A generic container to store a single type of data into unevenly
repository = "https://github.com/DoctorWhoof/slice_map.git"
documentation = "https://docs.rs/slice_map/latest/slice_map/"
license = "MIT"
categories = ["no-std"]
# categories = ["no-std"]

[dependencies]
slotmap = { version = "1.0.7", default-features = false }
# slotmap = { version = "1.0.7", default-features = false }
slotmap = { version = "1.0.7" }

[package.metadata.docs.rs]
all-features = true
14 changes: 9 additions & 5 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
### 0.1.8 Update
Dramatically simplified from a generic SliceMap that supported different storages to a more concrete SliceMap that always uses Vec<V> for values and SlotMap<SliceKey, Range<u32>> for slice ranges. This now allows removing slices and the existing Slice Keys remain valid (except for the removed one), thanks to the SlotMap.
### 0.2.4 Update
SliceMap is a project driven by another personal project, and its design follows the needs of that project. As a result, I had to go back to the idea of a Generic SliceMap that uses a Storage trait to pick different Storage structs.

Instead of [SliceMap] you should use the new type aliases, [SlotSliceMap] for SlotMap storage, [SecSliceMap] for SecondaryMap and [SparseSliceMap] for SparseSecondaryMap respectively.

To allow using [SparseSecondaryMap] this crate is not "no_std" anymore, but I plan to make that an optional feature and restore its no_std status!

### Description

[SliceMap] provides a container that allows iterating directly all of its items, or iterating through non-overlapping slices of varying sizes. You can only insert new items in groups that will become a new slice.
[SliceMap] and its type aliases provides a container that allows iterating directly all of its items, or iterating through non-overlapping slices of varying sizes. You can only insert new items in groups that will become a new slice.

### Example

A good use would be storing the points for polygons with different point counts, but in a way where all those points are laid out continuously in memory. Each slice of points can be iterated separately and is effectively a new polygon. Drawing all polygons at once can be very CPU cache-friendly.

Here's a simpler example with i32 values:
```rust
use slice_map::MainSliceMap;
use slice_map::SlotSliceMap;

slotmap::new_key_type!{
pub struct TestKey;
}

let mut slices = MainSliceMap::<TestKey, i32>::default();
let mut slices = SlotSliceMap::<TestKey, i32>::default();

// Adding items returns a SliceKey
let _a = slices.add_items([1, 2, 3, 4, 5]);
Expand Down
59 changes: 42 additions & 17 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![no_std]
// #![no_std]
#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/readme.md"))]

// Tests.
Expand All @@ -13,13 +13,13 @@ mod iter;
pub use iter::*;

use core::{marker::PhantomData, ops::Range};
use slotmap::{Key, SecondaryMap, SlotMap};
use slotmap::{Key, SecondaryMap, SlotMap, SparseSecondaryMap};

extern crate alloc;
use alloc::vec::Vec;

/// This generic SliceMap needs to be provided a Key type, a Value type and a Storage type.
/// Use [MainSliceMap] and [SecSliceMap] for storage using SlotMap and SecondarySlotMap, respectively.
/// Use [SlotSliceMap] and [SecSliceMap] for storage using SlotMap and SecondarySlotMap, respectively.
#[derive(Default, Debug, Clone)]
pub struct SliceMap<K, V, S>
where
Expand Down Expand Up @@ -65,18 +65,6 @@ where
&self.items
}

/// Creates a new slice with all items from an iterator of owned V items.
/// Will panic if the capacity of [u32::MAX] items is reached.
pub fn add_items<ITER>(&mut self, new_items: ITER) -> K
where
ITER: IntoIterator<Item = V>,
{
let start: u32 = self.items.len().try_into().unwrap();
self.items.extend(new_items);
let end: u32 = self.items.len().try_into().unwrap();
self.slices.insert(start..end)
}

/// How many items are contained in all slices.
pub fn items_len(&self) -> usize {
self.items.len()
Expand Down Expand Up @@ -139,7 +127,24 @@ where
}

/// SliceMap that uses [slotmap::SlotMap] for range storage
pub type MainSliceMap<K, V> = SliceMap<K, V, SlotMap<K, Range<u32>>>;
pub type SlotSliceMap<K, V> = SliceMap<K, V, SlotMap<K, Range<u32>>>;

impl<K, V> SlotSliceMap<K, V>
where
K: Key,
{
/// Creates a new slice with all items from an iterator of owned V items.
/// Will panic if the capacity of [u32::MAX] items is reached.
pub fn add_items<ITER>(&mut self, new_items: ITER) -> K
where
ITER: IntoIterator<Item = V>,
{
let start: u32 = self.items.len().try_into().unwrap();
self.items.extend(new_items);
let end: u32 = self.items.len().try_into().unwrap();
self.slices.insert(start..end)
}
}

/// SliceMap that uses [slotmap::SecondaryMap] for range storage
pub type SecSliceMap<K, V> = SliceMap<K, V, SecondaryMap<K, Range<u32>>>;
Expand All @@ -150,7 +155,27 @@ where
{
/// Creates a new slice with all items from an iterator of owned V items.
/// Will panic if the capacity of [u32::MAX] items is reached.
pub fn add_items_with_key<ITER>(&mut self, new_items: ITER, key:K)
pub fn add_items<ITER>(&mut self, key: K, new_items: ITER)
where
ITER: IntoIterator<Item = V>,
{
let start: u32 = self.items.len().try_into().unwrap();
self.items.extend(new_items);
let end: u32 = self.items.len().try_into().unwrap();
self.slices.insert(key, start..end);
}
}

/// SliceMap that uses [slotmap::SparseSecondaryMap] for range storage
pub type SparseSliceMap<K, V> = SliceMap<K, V, SparseSecondaryMap<K, Range<u32>>>;

impl<K, V> SparseSliceMap<K, V>
where
K: Key,
{
/// Creates a new slice with all items from an iterator of owned V items.
/// Will panic if the capacity of [u32::MAX] items is reached.
pub fn add_items<ITER>(&mut self, key: K, new_items: ITER)
where
ITER: IntoIterator<Item = V>,
{
Expand Down
8 changes: 4 additions & 4 deletions src/test.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::MainSliceMap;
use crate::SlotSliceMap;
use slotmap::new_key_type;

extern crate alloc;
Expand All @@ -14,7 +14,7 @@ new_key_type! {

#[test]
fn test_basic() {
let mut slicemap = MainSliceMap::<TestKey, i32>::new();
let mut slicemap = SlotSliceMap::<TestKey, i32>::new();
let max_slices = 10;
let mut item_count = 1;
let mut item_len = 0;
Expand All @@ -31,7 +31,7 @@ fn test_basic() {

#[test]
fn test_remove() {
let mut slicemap = MainSliceMap::<TestKey, i32>::new();
let mut slicemap = SlotSliceMap::<TestKey, i32>::new();

let a = slicemap.add_items([1, 2, 3, 4, 5]);
let b = slicemap.add_items([6, 7]);
Expand Down Expand Up @@ -83,7 +83,7 @@ fn test_remove() {
#[test]
fn non_default_values() {
struct Test; // No default implementation
let mut slices = MainSliceMap::<TestKey, Test>::new();
let mut slices = SlotSliceMap::<TestKey, Test>::new();
slices.add_items([Test, Test, Test]);
slices.add_items([Test]);
assert_eq!(slices.items_len(), 4);
Expand Down
40 changes: 38 additions & 2 deletions src/traits.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use alloc::boxed::Box;
use slotmap::{SlotMap, SecondaryMap, Key};
use slotmap::{Key, SecondaryMap, SlotMap, SparseSecondaryMap};

/// Trait to abstract operations on storage of slices (SlotMap or SecondaryMap)
/// Trait to abstract operations on storage of slices
pub trait SliceStorage<K, V>: Default {
fn insert(&mut self, value: V) -> K;
fn remove(&mut self, key: K) -> Option<V>;
Expand Down Expand Up @@ -81,3 +81,39 @@ where
Box::new(self.values_mut())
}
}


impl<K, V> SliceStorage<K, V> for SparseSecondaryMap<K, V>
where
K: Key,
{
#[inline(always)]
fn insert(&mut self, _value: V) -> K {
panic!("SecondaryMap does not support insert; keys must be pre-created")
}

#[inline(always)]
fn remove(&mut self, key: K) -> Option<V> {
self.remove(key)
}

#[inline(always)]
fn get(&self, key: K) -> Option<&V> {
self.get(key)
}

#[inline(always)]
fn iter(&self) -> Box<dyn Iterator<Item = (K, &V)> + '_> {
Box::new(self.iter())
}

#[inline(always)]
fn values(&self) -> Box<dyn Iterator<Item = &V> + '_> {
Box::new(self.values())
}

#[inline(always)]
fn values_mut(&mut self) -> Box<dyn Iterator<Item = &mut V> + '_> {
Box::new(self.values_mut())
}
}

0 comments on commit 66791dd

Please sign in to comment.