Skip to content

Commit

Permalink
Make sure @a.reverse creates proper containers for holes
Browse files Browse the repository at this point in the history
- rename R:I.ReifiedListReverse to R:I.ReifiedReverse
  as it's now also for Arrays specifically
- add support for descriptors
- expand nqp::null handling to creating container when needed
  • Loading branch information
lizmat committed May 2, 2020
1 parent e9468d6 commit ca49c15
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 11 deletions.
8 changes: 8 additions & 0 deletions src/core.c/Array.pm6
Expand Up @@ -419,6 +419,14 @@ my class Array { # declared in BOOTSTRAP
multi method flat(Array:U:) { self }
multi method flat(Array:D:) { Seq.new(self.iterator) }

method reverse(Array:D: --> Seq:D) is nodal {
self.is-lazy # reifies
?? Failure.new(X::Cannot::Lazy.new(:action<reverse>))
!! Seq.new: nqp::getattr(self,List,'$!reified')
?? Rakudo::Iterator.ReifiedReverse(self, $!descriptor)
!! Rakudo::Iterator.Empty
}

multi method List(Array:D: :$view --> List:D) {
nqp::if(
self.is-lazy, # can't make a List
Expand Down
2 changes: 1 addition & 1 deletion src/core.c/List.pm6
Expand Up @@ -1132,7 +1132,7 @@ my class List does Iterable does Positional { # declared in BOOTSTRAP
self.is-lazy # reifies
?? Failure.new(X::Cannot::Lazy.new(:action<reverse>))
!! Seq.new: $!reified
?? Rakudo::Iterator.ReifiedListReverse(self)
?? Rakudo::Iterator.ReifiedReverse(self, Mu)
!! Rakudo::Iterator.Empty
}

Expand Down
34 changes: 25 additions & 9 deletions src/core.c/Rakudo/Iterator.pm6
Expand Up @@ -2927,42 +2927,58 @@ class Rakudo::Iterator {
ReifiedListIterator.new(list)
}

# Return an iterator for a List that has been completely reified
# already, but that will produce values in reverse order.
my class ReifiedListReverseIterator does PredictiveIterator {
# Return an iterator for a List/Array that has been completely reified,
# or an IterationBuffer, that will produce values in reverse order. Takes
# a descriptor to create correct values for holes in the List/Array, use
# Mu to have holes returned as Nil.
my class ReifiedReverseIterator does PredictiveIterator {
has $!reified;
has $!descriptor;
has int $!i;

method !SET-SELF(\list) {
method !SET-SELF(\list, Mu \descriptor) {
$!reified := nqp::istype(list,List)
?? nqp::getattr(list,List,'$!reified')
!! list;
$!descriptor := nqp::eqaddr(descriptor,Mu)
?? nqp::null()
!! descriptor;
($!i = nqp::elems($!reified))
?? self
!! Rakudo::Iterator.Empty
}
method new(\list) { nqp::create(self)!SET-SELF(list) }
method new(\list, Mu \des) { nqp::create(self)!SET-SELF(list, des) }

method !hole(int $i) is raw {
nqp::isnull($!descriptor)
?? Nil
!! nqp::p6scalarfromdesc(
ContainerDescriptor::BindArrayPos.new(
$!descriptor, $!reified, $i
)
)
}

method pull-one() is raw {
nqp::isge_i(($!i = nqp::sub_i($!i,1)),0)
?? nqp::ifnull(nqp::atpos($!reified,$!i),Nil)
?? nqp::ifnull(nqp::atpos($!reified,$!i),self!hole($!i))
!! IterationEnd
}
method push-all(\target --> IterationEnd) {
my $reified := $!reified; # lexicals are faster than attributes
my int $i = $!i;
nqp::while( # doesn't sink
nqp::isge_i(($i = nqp::sub_i($i,1)),0),
target.push(nqp::ifnull(nqp::atpos($reified,$i),Nil))
target.push(nqp::ifnull(nqp::atpos($reified,$i),self!hole($i)))
);
$!i = $i;
}
method skip-one() { nqp::isge_i(($!i = nqp::sub_i($!i,1)),0) }
method count-only(--> Int:D) { $!i + nqp::islt_i($!i,0) }
method sink-all(--> IterationEnd) { $!i = -1 }
}
method ReifiedListReverse(\list) {
ReifiedListReverseIterator.new(list)
method ReifiedReverse(\list, Mu \descriptor) {
ReifiedReverseIterator.new(list, descriptor)
}

# Return a lazy iterator that will repeat the values of a given
Expand Down
2 changes: 1 addition & 1 deletion src/core.c/Seq.pm6
Expand Up @@ -116,7 +116,7 @@ my class Seq is Cool does Iterable does Sequence {
Failure.new(X::Cannot::Lazy.new(:action<reverse>)),
nqp::stmts(
$iterator.push-all(my \buffer := nqp::create(IterationBuffer)),
Seq.new: Rakudo::Iterator.ReifiedListReverse(buffer)
Seq.new: Rakudo::Iterator.ReifiedReverse(buffer, Mu)
)
)
}
Expand Down

0 comments on commit ca49c15

Please sign in to comment.