Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional support for SmallVec #8

Merged
merged 5 commits into from
Sep 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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