Skip to content

Commit

Permalink
Merge pull request #7 from billythedummy/opt/iter-indexed-key-order
Browse files Browse the repository at this point in the history
IterIndexed key order
  • Loading branch information
billythedummy authored Aug 28, 2023
2 parents 88c49e1 + 2b16b70 commit 232a9ac
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 46 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- `init_at_alloc()` fn to allow large `ConstLru`s to be initialized at pre-allocated memory without causing stack overflows.

### Changed

- `IterIndexed` now iterates in key-order instead of lru-order. This should result in slightly faster `.clone()`s

## [0.1.0] - 2023-08-23

Initial release
4 changes: 0 additions & 4 deletions src/iters/double_ended_iter_cursors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,4 @@ impl<I: PrimInt + Unsigned, const CAP: usize> DoubleEndedIterCursors<I, CAP> {
pub fn get_from_head(&self) -> I {
self.from_head
}

pub fn get_from_tail(&self) -> I {
self.from_tail
}
}
2 changes: 1 addition & 1 deletion src/iters/into_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl<K, V, const CAP: usize, I: PrimInt + Unsigned> DoubleEndedIterator for Into
// when const_lru drops

// index safety: from_tail is < CAP so prevs[i] wont panic
// but might = CAP, but in that case len = 0
// but might = CAP, but in that case len = 0 so mustve ended
self.const_lru.tail = self.const_lru.prevs[i];
self.const_lru.len = self.const_lru.len - I::one();
Some(self.get_entry(i))
Expand Down
37 changes: 0 additions & 37 deletions src/iters/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,40 +59,3 @@ impl<'a, K, V, const CAP: usize, I: PrimInt + Unsigned> DoubleEndedIterator
Some(self.get_entry(i))
}
}

/// Iterator that also returns the index of the current element
///
/// Used for internal implementation
pub struct IterIndexed<'a, K, V, const CAP: usize, I: PrimInt + Unsigned>(Iter<'a, K, V, CAP, I>);

impl<'a, K, V, const CAP: usize, I: PrimInt + Unsigned> IterIndexed<'a, K, V, CAP, I> {
pub fn new(const_lru: &'a ConstLru<K, V, CAP, I>) -> Self {
Self(Iter::new(const_lru))
}
}

impl<'a, K, V, const CAP: usize, I: PrimInt + Unsigned> Iterator for IterIndexed<'a, K, V, CAP, I> {
type Item = (I, &'a K, &'a V);

fn next(&mut self) -> Option<Self::Item> {
// consume then increment
let i = self.0.cursors.get_from_head();
self.0.next().map(|(k, v)| (i, k, v))
}

// TODO: look into https://doc.rust-lang.org/std/iter/trait.TrustedLen.html when it lands in stable
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(CAP))
}
}

impl<'a, K, V, const CAP: usize, I: PrimInt + Unsigned> DoubleEndedIterator
for IterIndexed<'a, K, V, CAP, I>
{
fn next_back(&mut self) -> Option<Self::Item> {
// decrement then consume
self.0
.next_back()
.map(|(k, v)| (self.0.cursors.get_from_tail(), k, v))
}
}
61 changes: 58 additions & 3 deletions src/iters/iter_key_order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,15 @@ impl<'a, K, V, const CAP: usize, I: PrimInt + Unsigned> IterKeyOrder<'a, K, V, C
}
}

/// Assumes bs_i is in bounds
/// returns const_lru.bs_index[bs_i]
fn get_index(&self, bs_i: I) -> I {
self.const_lru.bs_index[bs_i.to_usize().unwrap()]
}

/// Assumes bs_i is in bounds
fn get_entry(&mut self, bs_i: I) -> (&'a K, &'a V) {
let i = self.const_lru.bs_index[bs_i.to_usize().unwrap()]
.to_usize()
.unwrap();
let i = self.get_index(bs_i).to_usize().unwrap();
let key = unsafe { self.const_lru.keys[i].assume_init_ref() };
let val = unsafe { self.const_lru.values[i].assume_init_ref() };
(key, val)
Expand Down Expand Up @@ -77,3 +82,53 @@ impl<'a, K, V, const CAP: usize, I: PrimInt + Unsigned> DoubleEndedIterator
Some(res)
}
}

/// Iterator that also returns the index of the current element
///
/// Used for internal implementation, currently only used to impl clone()
pub struct IterIndexed<'a, K, V, const CAP: usize, I: PrimInt + Unsigned>(
IterKeyOrder<'a, K, V, CAP, I>,
);

impl<'a, K, V, const CAP: usize, I: PrimInt + Unsigned> IterIndexed<'a, K, V, CAP, I> {
pub fn new(const_lru: &'a ConstLru<K, V, CAP, I>) -> Self {
Self(IterKeyOrder::new(const_lru))
}
}

impl<'a, K, V, const CAP: usize, I: PrimInt + Unsigned> Iterator for IterIndexed<'a, K, V, CAP, I> {
type Item = (I, &'a K, &'a V);

fn next(&mut self) -> Option<Self::Item> {
if self.0.has_ended() {
return None;
}
// consume then increment
// next() modifies from_smallest_bsi, so read index out first
let i = self.0.get_index(self.0.from_smallest_bsi);
let (k, v) = self.0.next().unwrap();
Some((i, k, v))
}

// TODO: look into https://doc.rust-lang.org/std/iter/trait.TrustedLen.html when it lands in stable
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}

// TODO: look into https://doc.rust-lang.org/std/iter/trait.TrustedLen.html when it lands in stable
impl<'a, K, V, const CAP: usize, I: PrimInt + Unsigned> ExactSizeIterator
for IterIndexed<'a, K, V, CAP, I>
{
}

impl<'a, K, V, const CAP: usize, I: PrimInt + Unsigned> DoubleEndedIterator
for IterIndexed<'a, K, V, CAP, I>
{
fn next_back(&mut self) -> Option<Self::Item> {
// decrement then consume
self.0
.next_back()
.map(|(k, v)| (self.0.get_index(self.0.from_largest_bsi), k, v))
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub use iters::iter_key_order::IterKeyOrder;
pub use iters::iter_key_order_mut::IterKeyOrderMut;
pub use iters::iter_mut::IterMut;

use iters::iter::IterIndexed;
use iters::iter_key_order::IterIndexed;
use iters::iter_maybe_uninit::IterMaybeUninit;

/// Constant capacity key-addressed LRU cache.
Expand Down

0 comments on commit 232a9ac

Please sign in to comment.