Skip to content

Commit

Permalink
Add optional support for SmallVec as underlying peekable queue (#8)
Browse files Browse the repository at this point in the history
Current version does not enable smallvec by default because it currently still requires a nightly compiler.
With the recent stabilization of liballoc, smallvec may add support for the stable compiler in combination with no_std soon =).
  • Loading branch information
foresterre committed Sep 12, 2019
1 parent 26c48be commit 7d549d5
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 13 deletions.
2 changes: 2 additions & 0 deletions .ci/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cargo build --verbose --all
cargo test --verbose --all
3 changes: 3 additions & 0 deletions .ci/test_nightly.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.ci/test.sh
cargo +nightly build --verbose --all --features smallvec
cargo +nightly test --verbose --all --features smallvec
33 changes: 23 additions & 10 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
language: rust
rust:
- stable
- nightly
os:
- linux
- windows
before_install:
- if [ $TRAVIS_OS_NAME=linux ]; then chmod +x -R .ci; fi

matrix:
allow_failures:
- rust: nightly
- env: ALLOW_FAILURE=1
fast_finish: true
script:
- cargo build --verbose --all
- cargo test --verbose --all
include:
- name: "stable->linux"
rust: stable
os: linux
script: .ci/test.sh
- name: "stable->windows"
rust: stable
os: windows
script: .ci/test.sh
- name : "nightly->linux"
rust: nightly
os: linux
env: ALLOW_FAILURE=1
script: .ci/test_nightly.sh
- name: "nightly->windows"
rust: nightly
os: windows
env: ALLOW_FAILURE=1
script: .ci/test_nightly.sh
11 changes: 10 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,13 @@ keywords = ["peek", "lookahead", "iterator", "peekable", "look-ahead"]
categories = ["no-std"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

[features]
default = []

# smallvec with no-std requires nightly.
# see https://github.com/servo/rust-smallvec/issues/160
[dependencies.smallvec]
version = "0.6.10"
optional = true
default-features = false
35 changes: 33 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@
//! allows you to peek at the next element and no further. This crate aims to take that limitation
//! away.
//!
//! **Peekable queue:**
//!
//! To enable peeking at multiple elements ahead of consuming a next element, the iterator uses a
//! traversable queue which holds the elements which you can peek at, but have not been
//! consumed (yet).
//! By default the underlying data structure of this queue is a Vec. By enabling the `smallvec`
//! feature, you can opt-in to use SmallVec as the underlying queue data structure. SmallVec uses
//! the stack for a limited amount of elements and will only allocate on the heap if this maximum
//! amount of elements is reached. SmallVec support for `no_std` is experimental and currently
//! [requires] a nightly compiler.
//!
//! **Usage example:**
//!
//! ```rust
Expand Down Expand Up @@ -65,15 +76,21 @@
//!
//! [`Peekable`]: https://doc.rust-lang.org/core/iter/struct.Peekable.html
//! [`PeekView::peek`]: trait.PeekView.html#tymethod.peek
//! [requires]: https://github.com/servo/rust-smallvec/issues/160

/// We do need to allocate to save and store elements which are in the future compared to our last
/// iterator element. Perhaps in the future we could optimize this slightly by using the stack for
/// a limited amount of elements.
extern crate alloc;

/// We use a Vec to queue iterator elements.
/// We use a Vec to queue iterator elements if the smallvec feature is disabled.
#[cfg(not(feature = "smallvec"))]
use alloc::vec::Vec;

/// If the smallvec feature is enabled, we use a SmallVec to queue iterator elements instead of a Vec.
#[cfg(feature = "smallvec")]
use smallvec::SmallVec;

/// Trait which allows one to create an iterator which allows us to peek multiple times forward.
pub trait CreatePeekMoreIterator: Iterator + Sized {
/// Create an iterator where we can look (peek) forward multiple times from an existing iterator.
Expand All @@ -84,12 +101,23 @@ impl<I: Iterator> CreatePeekMoreIterator for I {
fn peekmore(self) -> PeekMoreIterator<I> {
PeekMoreIterator {
iterator: self,

#[cfg(not(feature = "smallvec"))]
queue: Vec::new(),

#[cfg(feature = "smallvec")]
queue: SmallVec::new(),

needle: 0usize,
}
}
}

/// Default stack size for SmallVec.
/// Admittedly the current size is chosen quite arbitrarily.
#[cfg(feature = "smallvec")]
const DEFAULT_STACK_SIZE: usize = 256;

/// This iterator makes it possible to peek multiple times without consuming a value.
/// In reality the underlying iterator will be consumed, but the values will be stored in a local
/// vector. This vector allows us to shift to visible element (the 'view').
Expand All @@ -102,7 +130,10 @@ pub struct PeekMoreIterator<I: Iterator> {
/// The queue represent the items of our iterator which have not been consumed, but have been
/// prepared to view ('peek') without consuming them. Once an element is consumed, we can no longer
/// view an item in the queue.
#[cfg(not(feature = "smallvec"))]
queue: Vec<Option<I::Item>>,
#[cfg(feature = "smallvec")]
queue: SmallVec<[Option<I::Item>; DEFAULT_STACK_SIZE]>,

/// The needle helps us determine which item we currently have in view.
/// Within these docs, it is also sometimes known as the peek view, peek view handle and peek view
Expand Down Expand Up @@ -484,7 +515,7 @@ mod tests {
assert_eq!(v2, Some(&&2));

let _ = iter.reset_view();
let v1again = iter.peek();;
let v1again = iter.peek();
assert_eq!(v1again, Some(&&1));

let v2again = iter.peek_next();
Expand Down

0 comments on commit 7d549d5

Please sign in to comment.