Created
August 24, 2015 07:44
-
-
Save laben/fdfe48a4c14ddb26e060 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
multi sub HYPER(&operator, Iterable:D \left, Iterable:D \right, :$dwim-left, :$dwim-right) { | |
my @result; | |
my \lefti := left.iterator; | |
my \righti := right.iterator; | |
# Check whether any side is lazy. They must not be to proceed. | |
if lefti.is-lazy { | |
X::HyperOp::Infinite.new(:side<both>, :&operator).throw if righti.is-lazy; | |
X::HyperOp::Infinite.new(:side<left>, :&operator).throw; | |
} | |
X::HyperOp::Infinite.new(:side<right>, :&operator).throw if righti.is-lazy; | |
# Prepare some variables | |
my $left-ended = False; | |
my $right-ended = False; | |
my $left-elems = 0; | |
my $right-elems = 0; | |
my $elems = 0; | |
my \leftb := IterationBuffer.new; | |
my \rightb := IterationBuffer.new; | |
# First, we do the non dwimmy results and keep count of elements passed | |
# We end this loop as soon as the shorter has been cycled through | |
# TODO Whatever as last elem makes the list infinitely prolungable with the elem before the Whatever | |
loop { | |
my \leftv := lefti.pull-one; | |
my \rightv := righti.pull-one; | |
$left-ended = leftv =:= IterationEnd; | |
$right-ended = rightv =:= IterationEnd; | |
leftb.push(leftv) unless $left-ended; | |
rightb.push(rightv) unless $right-ended; | |
last if $left-ended || $right-ended; | |
@result[$elems++] := HYPER(&operator, leftv, rightv, :$dwim-left, :$dwim-right); | |
} | |
$left-elems = $right-elems = $elems; | |
# If any side was empty and dwimmy (or both are empty), return the empty list | |
return () if $elems == 0; | |
# Return now if the dwim side is on the longer one | |
if ($left-ended && $right-ended) || | |
(!$left-ended && $dwim-left && !$dwim-right) || | |
(!$right-ended && $dwim-right && !$dwim-left) { | |
my $type = left.WHAT; | |
return nqp::iscont(left) ?? $type(|@result.eager).item !! $type(|@result.eager); | |
} | |
# Check whether a side is longer than the other and the shorter one is non dwimmy | |
if (!$left-ended && !$dwim-right) || (!$right-ended && !$dwim-left) { | |
X::HyperOp::NonDWIM.new(:&operator, :$left-elems, :$right-elems).throw | |
} | |
my $dwim-count = 0; | |
my $dwim-elems = $elems; | |
# Handle the dangling elem we got form the longer side when the shorter one ended | |
if $right-ended { | |
@result[$dwim-elems++] := HYPER(&operator, leftb[*-1], rightb[$dwim-count++], :$dwim-left, :$dwim-right); | |
} | |
else { ## $left-ended | |
@result[$dwim-elems++] := HYPER(&operator, leftb[$dwim-count++], rightb[*-1], :$dwim-left, :$dwim-right); | |
} | |
# Get the rest | |
my $dwim-ended = False; | |
my \dwim-iter := $right-ended ?? lefti !! righti; | |
loop { | |
my \dwimv := dwim-iter.pull-one; | |
$dwim-ended = dwimv =:= IterationEnd; | |
last if $dwim-ended; | |
if $right-ended { | |
@result[$dwim-elems++] := HYPER(&operator, dwimv, rightb[$dwim-count], :$dwim-left, :$dwim-right); | |
} | |
else { ## $left-ended | |
@result[$dwim-elems++] := HYPER(&operator, leftb[$dwim-count], dwimv, :$dwim-left, :$dwim-right); | |
} | |
$dwim-count = ($dwim-count + 1) % $elems; | |
} | |
# Coerce to the original type | |
my $type = left.WHAT; | |
return 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