Skip to content

Commit

Permalink
Added "remove()". Disabled "SliceArray" for now (code is still there,…
Browse files Browse the repository at this point in the history
… just not imported).
  • Loading branch information
DoctorWhoof committed Oct 19, 2024
1 parent 024a42f commit 8c6159e
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 49 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "slice_map"
version = "0.1.7"
version = "0.1.8"
edition = "2021"
description = "A generic container to store a single type of data into unevenly sized slices."
repository = "https://github.com/DoctorWhoof/slice_map.git"
Expand All @@ -12,7 +12,7 @@ categories = ["no-std"]

[features]
vec = []
array = []
# array = []
default = ["vec"]

[package.metadata.docs.rs]
Expand Down
19 changes: 9 additions & 10 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
SliceMap provides a container that allows iterating directly all of its items, or iterating slices of uneven sizes.
### Update:
Removed "SliceArray" for now. Focusing on a solid SliceVec implementation, then will reinstate SliceArray and update it to match SliceVec's features.

Two implementations are provided out of the box, [SliceVec] and [SliceArray], but you can extend [SliceMap] to use your own storage by implementing the [Storage] trait.
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.

One implementation is provided out of the box, [SliceVec], but you can extend [SliceMap] to use your own storage by implementing the [Storage] trait.

### Examples

Expand Down Expand Up @@ -33,13 +36,9 @@ for item in slicevec.iter_items(){
```

### Features:
#### "default"
The "vec" feature is enabled by default. If you want to use a no_std environment without Vecs, you can
disable default features and implement "[Storage]" for your desired container, which will allow you to create a SliceMap with it.

#### "vec"
Enables [SliceVec], which is a SliceMap implementation using Vecs for all its storage. This is the easiest to use option.

#### "array"
Enables [SliceArray], which is a "no_std" option that uses a simple ArrayVec with const generics for storage. This is more cumbersome to use, since the user has to provide the capacity for both the item storage and the slice range storage.

#### "default"
The "vec" feature is enabled by default. Make sure you use
```default-features = false, features = ["array"]```
in your cargo.toml if you wish to use slice_map in a no_std environment.
14 changes: 13 additions & 1 deletion src/array_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl<T, const ITEM_COUNT: usize> Storage<T> for ArrayVec<T, ITEM_COUNT> {
self.data.get(range)
}

fn iter_items(&self) -> core::slice::Iter<T> {
fn items(&self) -> core::slice::Iter<T> {
self.data.iter()
}

Expand All @@ -84,4 +84,16 @@ impl<T, const ITEM_COUNT: usize> Storage<T> for ArrayVec<T, ITEM_COUNT> {
self.extend(iter)?;
Ok(())
}

fn remove(&mut self, _index: impl Into<usize>) -> Option<T> {
todo!()
}

fn drain(&mut self, _range: impl core::ops::RangeBounds<usize>) {
todo!()
}

fn items_mut(&mut self) -> core::slice::IterMut<T> {
todo!()
}
}
11 changes: 6 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/readme.md"))]

// Main.
mod array_vec;
pub use array_vec::*;

mod slice_map;
pub use slice_map::*;

Expand All @@ -22,9 +19,13 @@ mod slice_vec;
pub use slice_vec::*;

// #[cfg(feature = "array")]
mod slice_array;
// mod slice_array;
// #[cfg(feature = "array")]
// pub use slice_array::*;
// #[cfg(feature = "array")]
// mod array_vec;
// #[cfg(feature = "array")]
pub use slice_array::*;
// pub use array_vec::*;

// Tests.

Expand Down
5 changes: 5 additions & 0 deletions src/slice_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,9 @@ where
pub fn iter_items(&self) -> impl Iterator<Item = &T> {
self.storage.iter_items()
}

#[inline(always)]
pub fn remove_slice(&mut self, index:usize) {
self.storage.remove_slice(index);
}
}
44 changes: 32 additions & 12 deletions src/slice_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ where
I: Storage<T>,
S: Storage<Slice>,
{
storage: I, // Generic storage
slices: S, // Ranges that map to individual item slices
pub(crate) items: I, // Generic items
pub(crate) slices: S, // Ranges that map to individual item slices
_marker: PhantomData<T>,
}

Expand All @@ -21,24 +21,24 @@ where
I: Storage<T>,
S: Storage<Slice>,
{
/// Returns a new SliceMap containing the provided storage object.
pub fn new(storage: I, slices: S) -> Self {
/// Returns a new SliceMap containing the provided items object.
pub fn new(items: I, slices: S) -> Self {
Self {
storage,
items,
slices,
_marker: PhantomData,
}
}

/// Clears the SliceMap.
pub fn clear(&mut self) {
self.storage.reset();
self.items.reset();
self.slices.reset();
}

/// How many items are contained in all slices.
pub fn items_len(&self) -> usize {
self.storage.len()
self.items.len()
}

/// How many slices are contained in the SliceMap.
Expand All @@ -53,13 +53,13 @@ where
ITER: IntoIterator<Item = T>,
{
let start: u32 = self
.storage
.items
.len()
.try_into()
.map_err(|_| "SliceMap: Capacity exceeded")?;
self.storage.extend_from_iter(new_items)?; // Extend the generic storage
self.items.extend_from_iter(new_items)?; // Extend the generic items
let end: u32 = self
.storage
.items
.len()
.try_into()
.map_err(|_| "SliceMap: Capacity exceeded")?;
Expand All @@ -70,7 +70,7 @@ where
/// Returns a slice with the desired range
pub fn get_slice(&self, index: usize) -> Option<&[T]> {
let range = self.slices.get_item(index)?;
self.storage.get_slice(Range {
self.items.get_slice(Range {
start: range.start as usize,
end: range.end as usize,
})
Expand All @@ -86,7 +86,27 @@ where

/// Returns an iterator for each individual item.
pub fn iter_items(&self) -> impl Iterator<Item = &T> {
self.storage.iter_items() // Returns an iterator over individual items in the storage
self.items.items() // Returns an iterator over individual items in the items
}

/// Removes a slice by index.
pub fn remove_slice(&mut self, slice_idx: usize) {
if slice_idx >= self.slices.len() {
return;
}
let range = self.slices.remove(slice_idx).unwrap();

// Remove the items in the range from items
self.items.drain(range.start as usize .. range.end as usize);

// Adjust the ranges of all subsequent slices
for slice in self.slices.items_mut() {
if slice.start >= range.end {
let offset = range.end - range.start;
slice.start = u32::try_from(slice.start - offset).expect("Index out of bounds");
slice.end = u32::try_from(slice.end - offset).expect("Index out of bounds");
}
}
}
}

Expand Down
32 changes: 31 additions & 1 deletion src/slice_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ where
self.storage.clear();
}

#[inline(always)]
pub fn items(&self) -> &Vec<T> {
&self.storage.items
}

#[inline(always)]
pub fn items_len(&self) -> usize {
self.storage.items_len()
Expand Down Expand Up @@ -63,6 +68,11 @@ where
pub fn iter_items(&self) -> impl Iterator<Item = &T> {
self.storage.iter_items()
}

#[inline(always)]
pub fn remove_slice(&mut self, index:usize) {
self.storage.remove_slice(index);
}
}

// Implement the Storage trait for Vec<T>.
Expand All @@ -83,7 +93,7 @@ impl<T> Storage<T> for Vec<T> {
}

#[inline(always)]
fn iter_items(&self) -> core::slice::Iter<T> {
fn items(&self) -> core::slice::Iter<T> {
self.iter()
}

Expand All @@ -104,4 +114,24 @@ impl<T> Storage<T> for Vec<T> {
self.push(item);
Ok(())
}

#[inline(always)]
fn remove(&mut self, index: impl Into<usize>) -> Option<T> {
let i:usize = index.into();
if i < self.len(){
Some(self.remove(i))
} else {
None
}
}

#[inline(always)]
fn drain(&mut self, range: impl core::ops::RangeBounds<usize>) {
self.drain(range);
}

#[inline(always)]
fn items_mut(&mut self) -> core::slice::IterMut<T> {
self.iter_mut()
}
}
7 changes: 5 additions & 2 deletions src/storage.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use core::ops::Range;
use core::ops::{Range, RangeBounds};

use crate::StrResult;

/// The required trait for any kind of storage used in a SliceMap.
pub trait Storage<T> {
fn len(&self) -> usize;
fn reset(&mut self);
fn iter_items(&self) -> core::slice::Iter<T>;
fn items(&self) -> core::slice::Iter<T>;
fn items_mut(&mut self) -> core::slice::IterMut<T>;
fn get_item(&self, index: impl Into<usize>) -> Option<&T>;
fn get_slice(&self, range: Range<usize>) -> Option<&[T]>;
fn push_item(&mut self, item: T) -> StrResult;
fn extend_from_iter<I: IntoIterator<Item = T>>(&mut self, iter: I) -> StrResult;
fn remove(&mut self, index: impl Into<usize>) -> Option<T>;
fn drain(&mut self, range: impl RangeBounds<usize>);
}
83 changes: 67 additions & 16 deletions src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ extern crate alloc;
use alloc::vec::Vec;

// Adds slices with numbers 1 to n, where n grows to max_slices
#[allow(unused)]
pub(crate) fn test_storage<I, S>(s: &mut SliceMap<i32, I, S>, max_slices: usize)
where
I: Storage<i32>,
Expand All @@ -15,7 +14,7 @@ where
let values: Vec<i32> = (1..=item_count as i32).into_iter().collect();
item_len += values.len();
item_count += 1;
s.add_items(values);
s.add_items(values).ok();
assert_eq!(s.items_len(), item_len);
assert_eq!(s.slices_len(), slice);
// println!("{:?}", s);
Expand All @@ -39,20 +38,72 @@ fn test_vec_default() {
test_storage(&mut slicemap.storage, 10);
}

#[test]
#[cfg(feature = "array")]
fn test_array_vec() {
use crate::ArrayVec;
let values: ArrayVec<i32, 100> = ArrayVec::default();
let ranges: ArrayVec<Slice, 10> = ArrayVec::default();
let mut slicemap = SliceMap::new(values, ranges);
test_storage(&mut slicemap, 10);
}

#[test]
#[cfg(feature = "array")]
fn test_array_default() {
use crate::ArrayVec;
let mut slicemap = SliceMap::<i32, ArrayVec<i32, 100>, ArrayVec<Slice, 10>>::default();
test_storage(&mut slicemap, 10);
#[cfg(feature = "vec")]
fn test_remove(){
use crate::SliceVec;
let mut slicevec = SliceVec::default();

slicevec.add_items([1, 2, 3, 4, 5]).ok();
slicevec.add_items([6, 7]).ok();
slicevec.add_items([8, 9, 10]).ok();

// Remove
slicevec.remove_slice(1);

// Iterating over slices
assert_eq!(slicevec.slices_len(), 2);
let mut slices = slicevec.iter_slices();
assert_eq!(slices.next().unwrap(), [1, 2, 3, 4, 5]);
assert_eq!(slices.next().unwrap(), [8, 9, 10]);
assert_eq!(slices.next(), None);

// Iterating over all items
let mut value = 1;
for (i, item) in slicevec.iter_items().enumerate(){
if i < 5 {
assert_eq!(value, *item);
} else {
assert_eq!(value + 2, *item);
}
value += 1
}

// Remove and test again
slicevec.remove_slice(0);
assert_eq!(slicevec.slices_len(), 1);
let mut slices = slicevec.iter_slices();
assert_eq!(slices.next().unwrap(), [8, 9, 10]);
assert_eq!(slices.next(), None);
let mut value = 8;
for item in slicevec.iter_items(){
assert_eq!(value, *item);
value += 1
}

// Empty
slicevec.remove_slice(0);
assert_eq!(slicevec.items_len(), 0);
assert_eq!(slicevec.slices_len(), 0);

}


// #[test]
// #[cfg(feature = "array")]
// fn test_array_vec() {
// use crate::ArrayVec;
// let values: ArrayVec<i32, 100> = ArrayVec::default();
// let ranges: ArrayVec<Slice, 10> = ArrayVec::default();
// let mut slicemap = SliceMap::new(values, ranges);
// test_storage(&mut slicemap, 10);
// }

// #[test]
// #[cfg(feature = "array")]
// fn test_array_default() {
// use crate::ArrayVec;
// let mut slicemap = SliceMap::<i32, ArrayVec<i32, 100>, ArrayVec<Slice, 10>>::default();
// test_storage(&mut slicemap, 10);
// }

0 comments on commit 8c6159e

Please sign in to comment.