diff --git a/proptest-regressions/catlist.txt b/proptest-regressions/catlist.txt
new file mode 100644
index 0000000..062dfe5
--- /dev/null
+++ b/proptest-regressions/catlist.txt
@@ -0,0 +1,8 @@
+# Seeds for failure cases proptest has generated in the past. It is
+# automatically read and these particular cases re-run before any
+# novel cases are generated.
+#
+# It is recommended to check this file in to source control so that
+# everyone who runs the test benefits from these saved cases.
+xs 1521201504 2491638753 2310477127 4115254882 # shrinks to ref vec = [0, 1]
+xs 1224529149 1514071443 2994934181 4293729051 # shrinks to ref xs = [, ref ys = [1, 0]
diff --git a/src/catlist.rs b/src/catlist.rs
index f551418..b6f4e6a 100644
--- a/src/catlist.rs
+++ b/src/catlist.rs
@@ -609,9 +609,7 @@ impl CatList {
/// Get an iterator over a list.
#[inline]
pub fn iter(&self) -> Iter {
- Iter {
- current: self.clone(),
- }
+ Iter::new(self)
}
/// Construct a list which is the reverse of the current list.
@@ -904,38 +902,108 @@ impl Debug for CatList {
/// An iterator over lists with values of type `A`.
pub struct Iter {
- current: CatList,
+ fwd_stack: Vec<(Arc>, usize)>,
+ fwd_current: Arc>,
+ fwd_head_index: usize,
+ fwd_tail_index: usize,
+ rev_stack: Vec<(Arc>, usize)>,
+ rev_current: Arc>,
+ rev_head_index: usize,
+ rev_tail_index: usize,
+ remaining: usize,
+}
+
+impl Iter {
+ fn new(list: RL) -> Self
+ where
+ RL: Shared>,
+ {
+ let l = list.shared();
+ let mut stack = Vec::new();
+ let mut item = l.clone();
+ while let Some(last) = item.tail.last() {
+ stack.push((item, 1));
+ item = last;
+ }
+ assert!(item.tail.is_empty());
+ Iter {
+ remaining: l.len(),
+ fwd_current: l.clone(),
+ fwd_stack: Vec::new(),
+ fwd_head_index: 0,
+ fwd_tail_index: 0,
+ rev_current: item,
+ rev_stack: stack,
+ rev_head_index: 0,
+ rev_tail_index: 0,
+ }
+ }
}
impl Iterator for Iter {
type Item = Arc;
fn next(&mut self) -> Option {
- // FIXME immutable ops are slower than necessary here,
- // how about a good old fashioned incrementing pointer?
- match self.current.pop_front() {
- None => None,
- Some((a, d)) => {
- self.current = d;
- Some(a)
- }
+ if self.remaining == 0 {
+ None
+ } else if self.fwd_current.head.len() > self.fwd_head_index {
+ let item =
+ &self.fwd_current.head[(self.fwd_current.head.len() - 1) - self.fwd_head_index];
+ self.fwd_head_index += 1;
+ self.remaining -= 1;
+ Some(item.clone())
+ } else if let Some(list) = self.fwd_current.tail.get(self.fwd_tail_index) {
+ self.fwd_stack
+ .push((self.fwd_current.clone(), self.fwd_tail_index + 1));
+ self.fwd_current = list;
+ self.fwd_head_index = 0;
+ self.fwd_tail_index = 0;
+ self.next()
+ } else if let Some((list, index)) = self.fwd_stack.pop() {
+ self.fwd_head_index = list.head.len();
+ self.fwd_tail_index = index;
+ self.fwd_current = list;
+ self.next()
+ } else {
+ None
}
}
fn size_hint(&self) -> (usize, Option) {
- let l = self.current.len();
- (l, Some(l))
+ (self.remaining, Some(self.remaining))
}
}
impl DoubleEndedIterator for Iter {
fn next_back(&mut self) -> Option {
- match self.current.pop_back() {
- None => None,
- Some((a, q)) => {
- self.current = q;
- Some(a)
- }
+ if self.remaining == 0 {
+ None
+ } else if self.rev_current.tail.len() > self.rev_tail_index {
+ println!("pushing from tail");
+ let list = self.rev_current
+ .tail
+ .get((self.rev_current.tail.len() - 1) - self.rev_tail_index)
+ .unwrap();
+ self.rev_stack
+ .push((self.rev_current.clone(), self.rev_tail_index + 1));
+ self.rev_current = list;
+ self.rev_head_index = 0;
+ self.rev_tail_index = 0;
+ self.next_back()
+ } else if self.rev_current.head.len() > self.rev_head_index {
+ println!("yielding from head");
+ let item = &self.rev_current.head[self.rev_head_index];
+ self.rev_head_index += 1;
+ self.remaining -= 1;
+ Some(item.clone())
+ } else if let Some((list, index)) = self.rev_stack.pop() {
+ println!("popping from stack");
+ self.rev_head_index = 0;
+ self.rev_tail_index = index;
+ self.rev_current = list;
+ self.next_back()
+ } else {
+ None
}
}
}
@@ -947,7 +1015,7 @@ impl IntoIterator for CatList {
type IntoIter = Iter;
fn into_iter(self) -> Self::IntoIter {
- Iter { current: self }
+ Iter::new(self)
}
}