Skip to content

Commit

Permalink
Implement two-way iterators and peekables
Browse files Browse the repository at this point in the history
  • Loading branch information
blt-r committed Apr 10, 2023
1 parent f129237 commit 6be798a
Show file tree
Hide file tree
Showing 3 changed files with 296 additions and 22 deletions.
104 changes: 82 additions & 22 deletions src/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ use crate::str_utils::{
last_line_start_byte_idx, line_to_byte_idx, trim_line_break,
};
use crate::tree::{Count, Node, TextInfo};
use crate::two_way_peekable::{TwoWayIterator, TwoWayPeekable};

//==========================================================

Expand Down Expand Up @@ -211,16 +212,20 @@ impl<'a> Bytes<'a> {
self
}

/// Return peekable version of the iterator
#[inline(always)]
pub fn two_way_peekable(self) -> TwoWayPeekable<Self> {
// this is needed, so that users can call `.two_way_peekable()` without importing TwoWayIterator
TwoWayIterator::two_way_peekable(self)
}

/// Advances the iterator backwards and returns the previous value.
///
/// Runs in amortized O(1) time and worst-case O(log N) time.
#[inline(always)]
pub fn prev(&mut self) -> Option<u8> {
if !self.is_reversed {
self.prev_impl()
} else {
self.next_impl()
}
// this is needed, so that users can call `.prev()` without importing TwoWayIterator
TwoWayIterator::prev(self)
}

#[inline]
Expand Down Expand Up @@ -298,6 +303,16 @@ impl<'a> Iterator for Bytes<'a> {
}
}

impl<'a> TwoWayIterator for Bytes<'a> {
fn prev(&mut self) -> Option<Self::Item> {
if !self.is_reversed {
self.prev_impl()
} else {
self.next_impl()
}
}
}

impl<'a> ExactSizeIterator for Bytes<'a> {}

//==========================================================
Expand Down Expand Up @@ -441,16 +456,20 @@ impl<'a> Chars<'a> {
self
}

/// Return peekable version of the iterator
#[inline(always)]
pub fn two_way_peekable(self) -> TwoWayPeekable<Self> {
// this is needed, so that users can call `.two_way_peekable()` without importing TwoWayIterator
TwoWayIterator::two_way_peekable(self)
}

/// Advances the iterator backwards and returns the previous value.
///
/// Runs in amortized O(1) time and worst-case O(log N) time.
#[inline(always)]
pub fn prev(&mut self) -> Option<char> {
if !self.is_reversed {
self.prev_impl()
} else {
self.next_impl()
}
// this is needed, so that users can call `.prev()` without importing TwoWayIterator
TwoWayIterator::prev(self)
}

#[inline]
Expand Down Expand Up @@ -536,6 +555,20 @@ impl<'a> Iterator for Chars<'a> {
}
}

impl<'a> TwoWayIterator for Chars<'a> {
/// Advances the iterator backwards and returns the previous value.
///
/// Runs in amortized O(1) time and worst-case O(log N) time.
#[inline(always)]
fn prev(&mut self) -> Option<Self::Item> {
if !self.is_reversed {
self.prev_impl()
} else {
self.next_impl()
}
}
}

impl<'a> ExactSizeIterator for Chars<'a> {}

//==========================================================
Expand Down Expand Up @@ -751,17 +784,20 @@ impl<'a> Lines<'a> {
self
}

/// Return peekable version of the iterator
#[inline(always)]
pub fn two_way_peekable(self) -> TwoWayPeekable<Self> {
// this is needed, so that users can call `.two_way_peekable()` without importing TwoWayIterator
TwoWayIterator::two_way_peekable(self)
}

/// Advances the iterator backwards and returns the previous value.
///
/// Runs in O(1) time with respect to rope length and O(N) time with
/// respect to line length.
/// Runs in amortized O(1) time and worst-case O(log N) time.
#[inline(always)]
pub fn prev(&mut self) -> Option<RopeSlice<'a>> {
if self.is_reversed {
self.next_impl()
} else {
self.prev_impl()
}
// this is needed, so that users can call `.prev()` without importing TwoWayIterator
TwoWayIterator::prev(self)
}

fn prev_impl(&mut self) -> Option<RopeSlice<'a>> {
Expand Down Expand Up @@ -1244,6 +1280,16 @@ impl<'a> Iterator for Lines<'a> {
}
}

impl<'a> TwoWayIterator for Lines<'a> {
fn prev(&mut self) -> Option<Self::Item> {
if !self.is_reversed {
self.prev_impl()
} else {
self.next_impl()
}
}
}

impl ExactSizeIterator for Lines<'_> {}

//==========================================================
Expand Down Expand Up @@ -1535,16 +1581,20 @@ impl<'a> Chunks<'a> {
self
}

/// Return peekable version of the iterator
#[inline(always)]
pub fn two_way_peekable(self) -> TwoWayPeekable<Self> {
// this is needed, so that users can call `.two_way_peekable()` without importing TwoWayIterator
TwoWayIterator::two_way_peekable(self)
}

/// Advances the iterator backwards and returns the previous value.
///
/// Runs in amortized O(1) time and worst-case O(log N) time.
#[inline(always)]
pub fn prev(&mut self) -> Option<&'a str> {
if !self.is_reversed {
self.prev_impl()
} else {
self.next_impl()
}
// this is needed, so that users can call `.prev()` without importing TwoWayIterator
TwoWayIterator::prev(self)
}

fn prev_impl(&mut self) -> Option<&'a str> {
Expand Down Expand Up @@ -1713,6 +1763,16 @@ impl<'a> Iterator for Chunks<'a> {
}
}

impl<'a> TwoWayIterator for Chunks<'a> {
fn prev(&mut self) -> Option<Self::Item> {
if !self.is_reversed {
self.prev_impl()
} else {
self.next_impl()
}
}
}

#[cfg(test)]
mod tests {
#![allow(clippy::while_let_on_iterator)]
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ mod tree;

pub mod iter;
pub mod str_utils;
pub mod two_way_peekable;

use std::ops::Bound;

Expand Down
Loading

0 comments on commit 6be798a

Please sign in to comment.