Iterator-Flex
view release on metacpan or search on metacpan
lib/Iterator/Flex/Gather.pm view on Meta::CPAN
package Iterator::Flex::Gather;
# ABSTRACT: Gather Iterator Class
use v5.28;
use strict;
use warnings;
use experimental 'signatures';
our $VERSION = '0.34';
use Iterator::Flex::Factory 'to_iterator';
use Iterator::Flex::Utils qw[ THROW STATE EXHAUSTION :IterAttrs :IterStates throw_failure];
use Ref::Util;
use parent 'Iterator::Flex::Base';
use Iterator::Flex::Gather::Constants ':all';
use namespace::clean;
lib/Iterator/Flex/Gather.pm view on Meta::CPAN
sub new ( $class, $code, $iterable, $pars = {} ) {
throw_failure( parameter => q{'code' parameter is not a coderef} )
unless Ref::Util::is_coderef( $code );
my %pars = $pars->%*;
my %state = (
code => $code,
cycle_on_exhaustion => delete( $pars{cycle_on_exhaustion} ) // GATHER_CYCLE_STOP,
src => $iterable,
);
throw_failure( parameter => q{'cycle_on_exhaustion': illegal value} )
if defined $pars{cycle_on_exhaustion}
and $pars{cycle_on_exhaustion} != GATHER_CYCLE_CHOOSE
and !$pars{cycle_on_exhaustion} & ( GATHER_CYCLE_STOP | GATHER_CYCLE_ABORT );
$class->SUPER::new( \%state, \%pars );
}
sub construct ( $class, $state ) {
throw_failure( parameter => q{'state' parameter must be a HASH reference} )
unless Ref::Util::is_hashref( $state );
my ( $code, $src, $cycle_on_exhaustion ) = @{$state}{qw[ code src cycle_on_exhaustion ]};
$src
= to_iterator( $src, { ( +EXHAUSTION ) => THROW } );
my $self;
# cached value if current element should be in
# next cycle
my $has_cache = !!0;
my $cache;
my $iterator_state;
# This iterator may have to delay signalling exhaustion for one cycle if the
# input iterator is exhausted, and it needs to return the last group of elements.
# exhaustion.
my $next_is_exhausted = !!0;
return {
( +_NAME ) => 'igather',
( +_SELF ) => \$self,
( +STATE ) => \$iterator_state,
( +NEXT ) => sub {
return $self->signal_exhaustion
if $iterator_state == IterState_EXHAUSTED || $next_is_exhausted;
my $cycle;
my @gathered;
my $ret = eval {
while ( 1 ) {
my $rv = $has_cache ? $cache : $src->();
$has_cache = !!0;
local $_ = $rv;
my $result = $code->( \@gathered, GATHER_GATHERING );
$cycle = $result & GATHER_CYCLE_MASK;
throw_failure( parameter => 'cycle action (continue, stop, abort, restart) was not specified' )
unless $cycle;
if ( ( $result & GATHER_ELEMENT_MASK ) == GATHER_ELEMENT_INCLUDE ) {
push @gathered, $rv;
}
elsif ( ( $result & GATHER_ELEMENT_MASK ) == GATHER_ELEMENT_CACHE ) {
throw_failure( parameter =>
'inconsistent return: element action GATHER_ELEMENT_CACHE requires cycle action GATHER_CYCLE_STOP',
) unless $cycle & GATHER_CYCLE_RESTART;
$cache = $rv;
$has_cache = !!1;
}
last if $cycle & ( GATHER_CYCLE_RESTART | GATHER_CYCLE_STOP | GATHER_CYCLE_ABORT );
}
1;
};
if ( !$ret && length $@ ) {
die $@
unless Ref::Util::is_blessed_ref( $@ )
&& $@->isa( 'Iterator::Flex::Failure::Exhausted' );
local $_ = undef;
my $result
= $cycle_on_exhaustion == GATHER_CYCLE_CHOOSE
? $code->( \@gathered, GATHER_SRC_EXHAUSTED )
: $cycle_on_exhaustion;
return $self->signal_exhaustion
if ( $result & GATHER_CYCLE_ABORT )
|| ( $result & GATHER_CYCLE_STOP && !@gathered );
$next_is_exhausted = !!1;
}
return \@gathered;
},
(
map { ( ( +RESET ) => $_, ( +REWIND ) => $_, ) } sub {
$next_is_exhausted = $has_cache = !!0;
},
),
( +_DEPENDS ) => $src,
};
}
__PACKAGE__->_add_roles( qw[
State::Closure
Next::ClosedSelf
Rewind::Closure
Reset::Closure
Current::Closure
] );
1;
#
# This file is part of Iterator-Flex
#
# This software is Copyright (c) 2018 by Smithsonian Astrophysical Observatory.
#
# This is free software, licensed under:
#
# The GNU General Public License, Version 3, June 2007
#
__END__
=pod
=for :stopwords Diab Jerius Smithsonian Astrophysical Observatory
=head1 NAME
Iterator::Flex::Gather - Gather Iterator Class
=head1 VERSION
version 0.34
=head1 METHODS
( run in 2.732 seconds using v1.01-cache-2.11-cpan-98e64b0badf )