From 2c1a2860b8945d473f61a65d5c5175f8685bbf57 Mon Sep 17 00:00:00 2001 From: Elizabeth Mattijsen Date: Wed, 22 Nov 2017 23:41:16 +0100 Subject: [PATCH] Add While/Until iterators - While: pass on values until the first false value returned by block - Until: don't pass values on until the first true value returned by block --- src/core/Rakudo/Iterator.pm | 68 +++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/core/Rakudo/Iterator.pm b/src/core/Rakudo/Iterator.pm index a39d57b7de7..53060d12ca8 100644 --- a/src/core/Rakudo/Iterator.pm +++ b/src/core/Rakudo/Iterator.pm @@ -3318,6 +3318,41 @@ class Rakudo::Iterator { }.new(iterator, with, unique) } + # Returns an iterator that takes a source iterator and a Callable. It + # passes on all values from the source iterator from the moment the + # Callable returns a trueish value. + method Until(\iter, &cond) { + class :: does Iterator { + has $!iter; + has $!cond; + + method SET-SELF(\iter, \cond) { + $!iter := iter; + $!cond := cond; + self + } + method new(\iter,\cond) { nqp::create(self).SET-SELF(iter,cond) } + + method pull-one() is raw { + nqp::if( + $!cond, + nqp::stmts( + nqp::until( + nqp::eqaddr((my $pulled := $!iter.pull-one),IterationEnd) + || $!cond($pulled), + nqp::null + ), + ($!cond := nqp::null), + $pulled + ), + $!iter.pull-one + ) + } + method is-lazy() { $!iter.is-lazy } + method sink-all(--> IterationEnd) { $!iter.sink-all } + }.new(iter, &cond) + } + # Returns an iterator from a given iterator where the occurrence of # a Whatever value indicates that last value seen from the source # iterator should be repeated indefinitely until either another @@ -3376,6 +3411,39 @@ class Rakudo::Iterator { }.new(source) } + # Returns an iterator that takes a source iterator and a Callable. It + # passes on values from the source iterator while the Callable returns + # a trueish value. Once a falsish value is returnedm, the iterator ends. + method While(\iter, &cond) { + class :: does Iterator { + has $!iter; + has &!cond; + has $!done; + + method SET-SELF(\iter, \cond) { + $!iter := iter; + &!cond := cond; + $!done := nqp::null; + self + } + method new(\iter,\cond) { nqp::create(self).SET-SELF(iter,cond) } + + method pull-one() is raw { + nqp::ifnull( + $!done, + nqp::if( + nqp::eqaddr((my $pulled := $!iter.pull-one),IterationEnd) + || nqp::isfalse(&!cond($pulled)), + ($!done := IterationEnd), + $pulled + ) + ) + } + method is-lazy() { $!iter.is-lazy } + method sink-all(--> IterationEnd) { $!iter.sink-all } + }.new(iter, &cond) + } + # Returns an iterator that handles all properties of a -while- with # a condition. Takes a Callable to be considered the body of the loop, # and a Callable for the condition..