diff --git a/src/core/Iterator.pm6 b/src/core/Iterator.pm6 index 339b2835cbb..4b65eb4491f 100644 --- a/src/core/Iterator.pm6 +++ b/src/core/Iterator.pm6 @@ -131,4 +131,12 @@ my role PredictiveIterator does Iterator { method bool-only(--> Bool:D) { self.count-only.Bool } } +# The CachedIterator role is a refinement of the PredictiveIterator role for +# those cases when all values have been generated already. It prevents the +# already generated values from being cached yet again for a Sequence. +my role CachedIterator does PredictiveIterator { + # The "cache" method should return a List of the already generated values. + method cache(--> List:D) { ... } +} + # vim: ft=perl6 expandtab sw=4 diff --git a/src/core/Rakudo/Iterator.pm6 b/src/core/Rakudo/Iterator.pm6 index 2e7e8805570..00c6baf7ed1 100644 --- a/src/core/Rakudo/Iterator.pm6 +++ b/src/core/Rakudo/Iterator.pm6 @@ -2612,7 +2612,7 @@ class Rakudo::Iterator { # Return an iterator for an Array that has been completely reified # already. Returns a assignable container for elements don't exist # before the end of the reified array. - my class ReifiedArrayIterator does PredictiveIterator { + my class ReifiedArrayIterator does CachedIterator { has $!reified; has $!descriptor; has int $!i; @@ -2701,6 +2701,9 @@ class Rakudo::Iterator { - nqp::islt_i($!i,nqp::elems($!reified)) ) } + method cache(--> List:D) { + nqp::p6bindattrinvres(nqp::create(List),List,'$!reified',$!reified) + } method sink-all(--> IterationEnd) { $!i = nqp::elems($!reified) } } method ReifiedArray(\array, Mu \descriptor) { @@ -2710,7 +2713,7 @@ class Rakudo::Iterator { # Return an iterator for a List that has been completely reified # already. Returns an nqp::null for elements that don't exist # before the end of the reified list. - my class ReifiedListIterator does PredictiveIterator { + my class ReifiedListIterator does CachedIterator { has $!reified; has int $!i; @@ -2791,6 +2794,9 @@ class Rakudo::Iterator { - nqp::islt_i($!i,nqp::elems($!reified)) ) } + method cache(--> List:D) { + nqp::p6bindattrinvres(nqp::create(List),List,'$!reified',$!reified) + } method sink-all(--> IterationEnd) { $!i = nqp::elems($!reified) } } method ReifiedList(\list) { diff --git a/src/core/Seq.pm6 b/src/core/Seq.pm6 index f95e231c8b5..dbbb0e04149 100644 --- a/src/core/Seq.pm6 +++ b/src/core/Seq.pm6 @@ -19,7 +19,13 @@ my class Seq is Cool does Iterable does Sequence { nqp::if( nqp::isconcrete(my \iter = $!iter), nqp::stmts( - ($!iter := Iterator), + ($!iter := Iterator), # allow usage only once + nqp::if( + nqp::istype(iter,CachedIterator), + nqp::bindattr( # can set up cache now + self,::?CLASS,'$!list',nqp::decont(iter.cache) + ) + ), iter ), nqp::if(