Skip to content

Instantly share code, notes, and snippets.

@niner
Last active August 29, 2015 14:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save niner/b8d88fca93b77ead569f to your computer and use it in GitHub Desktop.
Save niner/b8d88fca93b77ead569f to your computer and use it in GitHub Desktop.
multi sub HYPER(&operator, Iterable:D \left, Iterable:D \right, :$dwim-left, :$dwim-right) {
my @result;
my \left-iterator = left.iterator;
my \right-iterator = right.iterator;
# Check whether any side is lazy. They must not be to proceed.
if left-iterator.is-lazy {
X::HyperOp::Infinite.new(:side<both>, :&operator).throw if right-iterator.is-lazy;
X::HyperOp::Infinite.new(:side<left>, :&operator).throw;
}
X::HyperOp::Infinite.new(:side<right>, :&operator).throw if right-iterator.is-lazy;
my class DwimIterator does Iterator {
has $!source;
has $!buffer;
has $!ended;
has $!whatever;
has $!i;
has $!elems;
method new(\source, $ended is rw) {
my $iter := self.CREATE;
nqp::bindattr($iter, self, '$!source', source);
nqp::bindattr($iter, self, '$!buffer', IterationBuffer.new);
nqp::bindattr($iter, self, '$!ended', $ended);
nqp::bindattr($iter, self, '$!whatever', False);
nqp::bindattr($iter, self, '$!i', 0);
nqp::bindattr($iter, self, '$!elems', 0);
$iter
}
method pull-one() is rw {
if ($!ended) {
if ($!whatever) {
$!buffer.AT-POS($!elems - 1);
}
else {
$!buffer.AT-POS((($!i := $!i + 1) - 1) % $!elems);
}
}
else {
my \value := $!source.pull-one;
if value =:= IterationEnd {
$!ended = True;
if $!elems == 0 {
value
}
else {
self.pull-one()
}
}
elsif nqp::istype(value, Whatever) {
$!whatever := True;
$!ended = True;
self.pull-one()
}
else {
$!elems := $!elems + 1;
$!buffer.push(value);
value
}
}
}
}
# Prepare some variables
my $left-ended = False;
my $right-ended = False;
my \lefti := DwimIterator.new(left-iterator, $left-ended);
my \righti := DwimIterator.new(right-iterator, $right-ended);
my $i = 0;
loop {
my \leftv := lefti.pull-one;
my \rightv := righti.pull-one;
last if ($dwim-left and $dwim-right)
?? ($left-ended and $right-ended)
!! (($dwim-left or $left-ended) and ($dwim-right or $right-ended));
@result[$i++] := HYPER(&operator, leftv, rightv, :$dwim-left, :$dwim-right);
}
# Coerce to the original type
my $type = left.WHAT;
return nqp::iscont(left) ?? List.new(|@result.eager).item !! List.new(|@result.eager) if nqp::istype($type, Seq);
nqp::iscont(left) ?? $type(|@result.eager).item !! $type(|@result.eager)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment