Skip to content

Commit

Permalink
add Backend::iter (#65)
Browse files Browse the repository at this point in the history
This allows for simpler iteration of StringInterner.
  • Loading branch information
Robbepop authored May 1, 2024
1 parent 9043aaf commit 0a2a6c8
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 6 deletions.
14 changes: 12 additions & 2 deletions src/backend/bucket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,20 @@ use core::{iter::Enumerate, marker::PhantomData, slice};
/// - **Allocations:** The number of allocations performed by the backend.
/// - **Footprint:** The total heap memory consumed by the backend.
/// - **Contiguous:** True if the returned symbols have contiguous values.
/// - **Iteration:** Efficiency of iterating over the interned strings.
///
/// Rating varies between **bad**, **ok**, **good** and **best**.
///
/// | Scenario | Rating |
/// |:------------|:--------:|
/// | Fill | **good** |
/// | Resolve | **ok** |
/// | Resolve | **best** |
/// | Allocations | **good** |
/// | Footprint | **ok** |
/// | Supports `get_or_intern_static` | **yes** |
/// | `Send` + `Sync` | **yes** |
/// | Contiguous | **yes** |
/// | Iteration | **best** |
#[derive(Debug)]
pub struct BucketBackend<S = DefaultSymbol> {
spans: Vec<InternedStr>,
Expand Down Expand Up @@ -81,6 +83,9 @@ where
S: Symbol,
{
type Symbol = S;
type Iter<'a> = Iter<'a, S>
where
Self: 'a;

#[cfg_attr(feature = "inline-more", inline)]
fn with_capacity(cap: usize) -> Self {
Expand Down Expand Up @@ -124,6 +129,11 @@ where
// that required invariants are checked.
unsafe { self.spans.get_unchecked(symbol.to_usize()).as_str() }
}

#[inline]
fn iter(&self) -> Self::Iter<'_> {
Iter::new(self)
}
}

impl<S> BucketBackend<S>
Expand Down Expand Up @@ -202,7 +212,7 @@ where

#[cfg_attr(feature = "inline-more", inline)]
fn into_iter(self) -> Self::IntoIter {
Self::IntoIter::new(self)
self.iter()
}
}

Expand Down
12 changes: 11 additions & 1 deletion src/backend/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use core::{marker::PhantomData, mem, str};
/// - **Allocations:** The number of allocations performed by the backend.
/// - **Footprint:** The total heap memory consumed by the backend.
/// - **Contiguous:** True if the returned symbols have contiguous values.
/// - **Iteration:** Efficiency of iterating over the interned strings.
///
/// Rating varies between **bad**, **ok**, **good** and **best**.
///
Expand All @@ -31,6 +32,7 @@ use core::{marker::PhantomData, mem, str};
/// | Supports `get_or_intern_static` | **no** |
/// | `Send` + `Sync` | **yes** |
/// | Contiguous | **no** |
/// | Iteration | **bad** |
#[derive(Debug)]
pub struct BufferBackend<S = DefaultSymbol> {
len_strings: usize,
Expand Down Expand Up @@ -153,6 +155,9 @@ where
S: Symbol,
{
type Symbol = S;
type Iter<'a> = Iter<'a, S>
where
Self: 'a;

#[cfg_attr(feature = "inline-more", inline)]
fn with_capacity(capacity: usize) -> Self {
Expand Down Expand Up @@ -189,6 +194,11 @@ where
// that required invariants are checked.
unsafe { self.resolve_index_to_str_unchecked(symbol.to_usize()) }
}

#[inline]
fn iter(&self) -> Self::Iter<'_> {
Iter::new(self)
}
}

/// Encodes the value using variable length encoding into the buffer.
Expand Down Expand Up @@ -434,7 +444,7 @@ where

#[cfg_attr(feature = "inline-more", inline)]
fn into_iter(self) -> Self::IntoIter {
Self::IntoIter::new(self)
self.iter()
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ pub trait Backend: Default {
/// The symbol used by the string interner backend.
type Symbol: Symbol;

/// The iterator over the symbols and their strings.
type Iter<'a>: Iterator<Item = (Self::Symbol, &'a str)>
where
Self: 'a;

/// Creates a new backend for the given capacity.
///
/// The capacity denotes how many strings are expected to be interned.
Expand Down Expand Up @@ -74,4 +79,7 @@ pub trait Backend: Default {
/// [`intern_static`](`Backend::intern_static`) methods of the same
/// interner backend.
unsafe fn resolve_unchecked(&self, symbol: Self::Symbol) -> &str;

/// Creates an iterator that yields all interned strings and their symbols.
fn iter(&self) -> Self::Iter<'_>;
}
11 changes: 10 additions & 1 deletion src/backend/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use core::{iter::Enumerate, marker::PhantomData, slice};
/// - **Allocations:** The number of allocations performed by the backend.
/// - **Footprint:** The total heap memory consumed by the backend.
/// - **Contiguous:** True if the returned symbols have contiguous values.
/// - **Iteration:** Efficiency of iterating over the interned strings.
///
/// Rating varies between **bad**, **ok**, **good** and **best**.
///
Expand Down Expand Up @@ -55,6 +56,9 @@ where
S: Symbol,
{
type Symbol = S;
type Iter<'a> = Iter<'a, S>
where
Self: 'a;

#[cfg_attr(feature = "inline-more", inline)]
fn with_capacity(cap: usize) -> Self {
Expand Down Expand Up @@ -87,6 +91,11 @@ where
// that required invariants are checked.
unsafe { self.strings.get_unchecked(symbol.to_usize()) }
}

#[inline]
fn iter(&self) -> Self::Iter<'_> {
Iter::new(self)
}
}

impl<S> Clone for SimpleBackend<S> {
Expand Down Expand Up @@ -120,7 +129,7 @@ where

#[cfg_attr(feature = "inline-more", inline)]
fn into_iter(self) -> Self::IntoIter {
Self::IntoIter::new(self)
self.iter()
}
}

Expand Down
12 changes: 11 additions & 1 deletion src/backend/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use core::{iter::Enumerate, marker::PhantomData, slice};
/// - **Allocations:** The number of allocations performed by the backend.
/// - **Footprint:** The total heap memory consumed by the backend.
/// - **Contiguous:** True if the returned symbols have contiguous values.
/// - **Iteration:** Efficiency of iterating over the interned strings.
///
/// Rating varies between **bad**, **ok**, **good** and **best**.
///
Expand All @@ -35,6 +36,7 @@ use core::{iter::Enumerate, marker::PhantomData, slice};
/// | Supports `get_or_intern_static` | **no** |
/// | `Send` + `Sync` | **yes** |
/// | Contiguous | **yes** |
/// | Iteration | **good** |
#[derive(Debug)]
pub struct StringBackend<S = DefaultSymbol> {
ends: Vec<usize>,
Expand Down Expand Up @@ -147,6 +149,9 @@ where
S: Symbol,
{
type Symbol = S;
type Iter<'a> = Iter<'a, S>
where
Self: 'a;

#[cfg_attr(feature = "inline-more", inline)]
fn with_capacity(cap: usize) -> Self {
Expand Down Expand Up @@ -181,6 +186,11 @@ where
// that required invariants are checked.
unsafe { self.span_to_str(self.symbol_to_span_unchecked(symbol)) }
}

#[inline]
fn iter(&self) -> Self::Iter<'_> {
Iter::new(self)
}
}

impl<'a, S> IntoIterator for &'a StringBackend<S>
Expand All @@ -192,7 +202,7 @@ where

#[cfg_attr(feature = "inline-more", inline)]
fn into_iter(self) -> Self::IntoIter {
Self::IntoIter::new(self)
self.iter()
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,12 @@ where
pub fn resolve(&self, symbol: <B as Backend>::Symbol) -> Option<&str> {
self.backend.resolve(symbol)
}

/// Returns an iterator that yields all interned strings and their symbols.
#[inline]
pub fn iter(&self) -> <B as Backend>::Iter<'_> {
self.backend.iter()
}
}

impl<B, H, T> FromIterator<T> for StringInterner<B, H>
Expand Down
4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,16 @@
//! - **Allocations:** The number of allocations performed by the backend.
//! - **Footprint:** The total heap memory consumed by the backend.
//! - **Contiguous:** True if the returned symbols have contiguous values.
//! - **Iteration:** Efficiency of iterating over the interned strings.
//!
//! | **Property** | **BucketBackend** | **StringBackend** | **BufferBackend** |
//! |:-------------|:-----------------:|:-----------------:|:-----------------:|
//! | **Fill** | ok | good | best |
//! | **Resolve** | ok | good | bad |
//! | **Resolve** | best | good | bad |
//! | Allocations | ok | good | best |
//! | Footprint | ok | good | best |
//! | Contiguous | yes | yes | no |
//! | Iteration | best | good | bad |
//!
//! ## When to use which backend?
//!
Expand Down

0 comments on commit 0a2a6c8

Please sign in to comment.