Skip to content

Commit

Permalink
Introduce Iterator.skip-one
Browse files Browse the repository at this point in the history
A method that can be overriden if you're writing an iterator that can
be significantly cheaper when skipping a generated value.  Use case,
the :10nth parameter with Str.match (aka, give me only the 10th match).
By default, it is just a slightly more expensive .pull-one.

Also use let Iterator.skip-at-least-pull-one use skip-one, as well
as in Rakudo::Internals.SeqSkipNFromIterator .
  • Loading branch information
lizmat committed Oct 20, 2016
1 parent 74d0e36 commit 71a01e9
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 32 deletions.
27 changes: 18 additions & 9 deletions src/core/Iterator.pm
Expand Up @@ -8,6 +8,14 @@ my role Iterator {
# methods in this role, they'll all end up falling back to using this.
method pull-one() { ... }

# Skip one value from the iterator. Should return a true-like value to
# indicate the skip was successful. Override this method if you can
# make an iterator that has significantly less to do when skipping a
# generated value.
method skip-one() {
nqp::not_i(nqp::eqaddr(self.pull-one,IterationEnd))
}

# Has the iterator produce a certain number of values and push them into
# the target. The only time the iterator may push less values than asked
# for is when it reaches the end of the iteration. It may never push more
Expand Down Expand Up @@ -68,17 +76,18 @@ my role Iterator {

# Skip the given number of values produced before returning the next
# pulled value. Given 0 it is an expensive way to do .pull-one
method skip-at-least-pull-one(\todrop) is raw {
method skip-at-least-pull-one(\toskip) is raw {
nqp::stmts(
(my int $topull = todrop + 1),
nqp::while(
nqp::isge_i(($topull = nqp::sub_i($topull,1)),0),
nqp::if(
nqp::eqaddr((my $pulled := self.pull-one),IterationEnd),
($topull = 0),
)
(my int $left = toskip),
nqp::while( # skipping
nqp::isge_i(($left = nqp::sub_i($left,1)),0) && self.skip-one,
Nil
),
$pulled
nqp::if(
nqp::islt_i($left,0), # could skip all?
self.pull-one,
IterationEnd
)
)
}

Expand Down
41 changes: 18 additions & 23 deletions src/core/Rakudo/Internals.pm
Expand Up @@ -308,34 +308,29 @@ my class Rakudo::Internals {
method new(\i,\s) { nqp::create(self)!SET-SELF(i,s) }
method pull-one() is raw {
nqp::if(
nqp::islt_i($!skipping,-1),
IterationEnd, # exhausted before
nqp::stmts( # not exhausted yet
nqp::if(
$!iterator,
nqp::stmts(
nqp::while(
nqp::isgt_i($!skipping,0),
nqp::until( # still skipping
nqp::iseq_i($!skipping,0),
nqp::if(
nqp::eqaddr($!iterator.pull-one,IterationEnd),
nqp::stmts( # exhausted now
($!skipping = -1),
(return IterationEnd)
),
($!skipping = nqp::sub_i($!skipping,1)),
nqp::if(
$!iterator.skip-one,
($!skipping = nqp::sub_i($!skipping,1)), # skipped ok
nqp::stmts( # exhausted
($!iterator := Mu),
(return IterationEnd)
)
)
),
nqp::stmts( # no longer skipping
nqp::if(
nqp::eqaddr(
(my $pulled := $!iterator.pull-one),
IterationEnd
),
($!skipping = -1),
nqp::if( # done skipping
nqp::eqaddr(
(my $pulled := $!iterator.pull-one),
IterationEnd
),
$pulled
)
)
($!iterator := Mu) # exhausted
),
$pulled
),
IterationEnd # exhausted before
)
}
}.new(iterator,skipping))
Expand Down

0 comments on commit 71a01e9

Please sign in to comment.