From 94ba19f7e5ece517ca48ac16bf385bee2650b018 Mon Sep 17 00:00:00 2001 From: Elizabeth Mattijsen Date: Wed, 12 Jun 2019 14:01:46 +0200 Subject: [PATCH] Introducing/Using the CachedIterator role This is CachedIterator role is a refinement of the PredictiveIterator role. The difference is that a CachedIterator role is supposed to supply a "cache" method that will be called to set the cache of the Seq as soon as the iterator is being used. By having R:Iterator.ReifiedArrayIterator and R:Iterator.ReifiedListIterator consume this role, makes the following code work again: given Seq.new((1,2,3).iterator) { dd .elems; dd .all; dd .all } # 3 # all(1, 2, 3) # all(1, 2, 3) which was broken by: https://github.com/rakudo/rakudo/commit/9107215a99f106835a121d8446d97d11fc017758 --- src/core/Iterator.pm6 | 8 ++++++++ src/core/Rakudo/Iterator.pm6 | 10 ++++++++-- src/core/Seq.pm6 | 8 +++++++- 3 files changed, 23 insertions(+), 3 deletions(-) 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(