Skip to content

Commit

Permalink
feat: improve expand* API of Ribbon
Browse files Browse the repository at this point in the history
  • Loading branch information
nfejzic committed Oct 7, 2023
1 parent 5e3bce1 commit 52d8473
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 21 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ribbon"
version = "0.6.0"
version = "0.7.0"
edition = "2021"
authors = ["Nadir Fejzic <nadirfejzo@gmail.com>"]
description = "Tape machine for peeking through windows of iterators."
Expand Down
38 changes: 32 additions & 6 deletions src/band.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
//! Implementation of statically sized data structures that implement the [`Ribbon`] trait.

use std::iter::Peekable;

use crate::{ribbon, Ribbon};

/// A fix-sized [`Ribbon`] backed up by an array of `N` elements. It cannot grow over the given
/// fixed length, and instead drops and/or returns items if no space is available at the given
/// moment.
///
/// [`Ribbon`]: crate::Ribbon
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug)]
pub struct Band<const LEN: usize, I>
where
I: Iterator,
{
iter: I,
iter: Peekable<I>,
tape: [Option<I::Item>; LEN],
head: usize,
len: usize,
Expand All @@ -27,7 +29,7 @@ where
let tape = [0; LEN].map(|_| None);

Band {
iter,
iter: iter.peekable(),
tape,
head: 0,
len: 0,
Expand Down Expand Up @@ -80,13 +82,37 @@ where

/// Expands the `Band` by consuming the next available item and appending it to the end.
/// Drops the first element if the `Band` is already at full capacity.
fn expand(&mut self) {
fn expand(&mut self) -> bool {
if self.is_full() {
self.slide();
} else {
self.tape[self.len] = self.iter.next();
}

if let Some(item) = self.iter.next() {
self.tape[self.len] = Some(item);
self.len += 1;
return true;
}

return false;
}

fn expand_while<F>(&mut self, f: F) -> bool
where
F: Fn(&I::Item) -> bool,
{
let mut expanded = false;
loop {
match self.iter.peek() {
Some(item) if f(item) => {
expanded = true;

self.expand();
}
_ => break,
}
}

expanded
}

fn pop_front(&mut self) -> Option<I::Item> {
Expand Down
60 changes: 51 additions & 9 deletions src/ribbon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,32 @@ pub trait Ribbon<T> {
fn progress(&mut self) -> Option<T>;

/// Expands the `Ribbon` by consuming the next available item and appending it to the tail.
/// Returns `true` if `Ribbon` is expanded.
///
/// # Example
///
///```
/// use ribbon::{Ribbon, Tape};
///
/// let mut tape = Tape::new(0..10);
/// let mut tape = Tape::new(0..2);
///
/// tape.expand();
/// assert!(tape.expand());
/// assert_eq!(tape.len(), 1);
/// assert_eq!(tape.peek_front(), Some(&0));
/// assert_eq!(tape.peek_back(), Some(&0));
///
/// tape.expand();
/// assert!(tape.expand());
/// assert_eq!(tape.len(), 2);
/// assert_eq!(tape.peek_front(), Some(&0));
/// assert_eq!(tape.peek_back(), Some(&1));
///
/// // no more elements, expansion fails
/// assert_eq!(tape.expand(), false);
/// ```
fn expand(&mut self);
fn expand(&mut self) -> bool;

/// Expands the `Ribbon` by consuming the `n` next available item and appending it to the end.
/// Expands the `Ribbon` by consuming the `n` next available item and appending them to the end.
/// Returns `true` if `Ribbon` is expanded by at least one element.
///
/// # Example
///
Expand All @@ -54,22 +59,59 @@ pub trait Ribbon<T> {
///
/// let mut tape = Tape::new(0..10);
///
/// tape.expand_n(5);
/// assert!(tape.expand_n(5));
/// assert_eq!(tape.len(), 5);
/// assert_eq!(tape.peek_front(), Some(&0));
/// assert_eq!(tape.peek_back(), Some(&4));
///
/// tape.expand_n(7);
/// assert!(tape.expand_n(7));
/// assert_eq!(tape.len(), 10);
/// assert_eq!(tape.peek_front(), Some(&0));
/// assert_eq!(tape.peek_back(), Some(&9));
///
/// // not expanding anymore, returns false
/// assert_eq!(tape.expand_n(1), false);
/// ```
fn expand_n(&mut self, n: usize) {
fn expand_n(&mut self, n: usize) -> bool {
let mut expanded = false;
for _ in 0..n {
self.expand();
expanded |= self.expand();

if !expanded {
break;
}
}

expanded
}

/// Expands the `Ribbon` by consuming items from the iterator while some condition holds and
/// appending them to the end. Returns `true` if `Ribbon` is expanded by at least one element.
///
/// # Example
///
///```
/// use ribbon::{Ribbon, Tape};
///
/// let mut tape = Tape::new(0..10);
///
/// assert!(tape.expand_while(|item| *item < 5));
/// assert_eq!(tape.len(), 5);
/// assert_eq!(tape.peek_front(), Some(&0));
/// assert_eq!(tape.peek_back(), Some(&4));
///
/// assert!(tape.expand_while(|item| *item < 6));
/// assert_eq!(tape.len(), 6);
/// assert_eq!(tape.peek_front(), Some(&0));
/// assert_eq!(tape.peek_back(), Some(&5));
///
/// // no more elements smaller than 6, expansion fails
/// assert_eq!(tape.expand_while(|item| *item < 6), false);
/// ```
fn expand_while<F>(&mut self, f: F) -> bool
where
F: Fn(&T) -> bool;

/// Removes the item stored at the head of `Ribbon` and returns it (if available).
///
/// # Example
Expand Down
32 changes: 27 additions & 5 deletions src/tape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//!
//! [`Ribbon`]: crate::Ribbon

use std::collections::VecDeque;
use std::{collections::VecDeque, iter::Peekable};

use crate::Ribbon;

Expand All @@ -12,12 +12,12 @@ use crate::Ribbon;
///
/// [`VecDeque`]: std::collections::VecDeque
/// [`Ribbon`]: crate::Ribbon
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug)]
pub struct Tape<I>
where
I: Iterator,
{
iter: I,
iter: Peekable<I>,
tape: VecDeque<I::Item>,
}

Expand All @@ -31,7 +31,7 @@ where
I: Iterator,
{
Tape {
iter,
iter: iter.peekable(),
tape: VecDeque::new(),
}
}
Expand All @@ -50,12 +50,34 @@ where
head
}

fn expand(&mut self) {
fn expand(&mut self) -> bool {
if let Some(item) = self.iter.next() {
self.tape.push_back(item);
true
} else {
false
}
}

fn expand_while<F>(&mut self, f: F) -> bool
where
F: Fn(&I::Item) -> bool,
{
let mut expanded = false;

loop {
match self.iter.peek() {
Some(item) if f(item) => {
expanded = true;
self.expand();
}
_ => break,
}
}

expanded
}

fn pop_front(&mut self) -> Option<I::Item> {
self.tape.pop_front()
}
Expand Down

0 comments on commit 52d8473

Please sign in to comment.