Iterator-Flex
view release on metacpan or search on metacpan
lib/Iterator/Flex/Take.pm view on Meta::CPAN
package Iterator::Flex::Take;
# ABSTRACT: Take Iterator Class
use v5.28;
use strict;
use warnings;
our $VERSION = '0.34';
use Iterator::Flex::Utils ':IterAttrs', ':IterStates', ':SignalParameters', ':ExhaustionActions',
'throw_failure';
use Iterator::Flex::Factory 'to_iterator';
use Ref::Util;
use namespace::clean;
use experimental 'signatures';
use parent 'Iterator::Flex::Base';
sub new ( $class, $iterable, $n, $pars = {} ) {
my %pars = $pars->%*;
$n //= 1;
Scalar::Util::looks_like_number( $n ) && int( $n ) == $n && $n > 0
|| throw_failure( parameter => 'parameter "n" is not a positive integer' );
my $lazy = delete $pars{lazy} // !!1;
$class->SUPER::new( {
n => $n,
lazy => $lazy,
src => $iterable,
},
\%pars,
);
}
sub construct ( $class, $state ) {
throw_failure( parameter => q{'state' parameter must be a HASH reference} )
unless Ref::Util::is_hashref( $state );
my ( $src, $prev, $current, $next, $array, $n, $lazy )
= @{$state}{qw[ src prev current next array n lazy ]};
$src
= to_iterator( $src, { ( +EXHAUSTION ) => RETURN } );
my $len;
$len = $array->@* if defined $array;
$current //= undef;
$prev //= undef;
$next //= 0;
my $took = 0;
my $self;
my $is_exhausted = $src->can( 'is_exhausted' );
my $iterator_state;
my %params = (
( +_NAME ) => 'itake',
( +_SELF ) => \$self,
( +STATE ) => \$iterator_state,
# this iterator only depends on $src if it hasn't drained it.
# currently _DEPENDS must be a list of iterators, not a
# coderef, so a dynamic dependency is not possible
( +_DEPENDS ) => $src,
( +FREEZE ) => sub {
return [
$class,
{
src => $src,
prev => $prev,
current => $current,
next => $next,
array => $array,
n => $n,
lazy => $lazy,
},
];
},
);
if ( $lazy ) {
$params{ +RESET } = sub {
$prev = $current = undef;
$next = 0;
$took = 0;
};
$params{ +REWIND } = sub {
$next = 0;
$took = 0;
};
lib/Iterator/Flex/Take.pm view on Meta::CPAN
return $self->signal_exhaustion
if $iterator_state == IterState_EXHAUSTED
|| $took == $n;
my $value = $src->();
return $self->signal_exhaustion
if !$value && $src->$is_exhausted;
$took++;
$prev = $current;
$current = $value;
return $current;
};
}
else {
$params{ +RESET } = sub {
$array = $prev = $current = undef;
$len = undef;
$next = 0;
};
$params{ +REWIND } = sub {
$prev = $array->[$current] if defined $current;
$array = $current = undef;
$len = undef;
$next = 0;
};
$params{ +PREV } = sub {
return $prev;
};
$params{ +CURRENT } = sub {
return defined $current ? $array->[$current] : undef;
};
$params{ +NEXT } = sub {
return $self->signal_exhaustion
if $iterator_state == IterState_EXHAUSTED;
if ( !defined $array ) {
eval {
$array = [];
# preload $array
push( $array->@*, $src->next );
# postfix until/while check conditional first,
# which would be a problem if $array->@* and
# n == 0, in which case it would never
# call $src->next
push( $array->@*, $src->next ) until $array->@* == $n;
1;
} or do {
die $@
unless Ref::Util::is_blessed_ref( $@ )
&& $@->isa( 'Iterator::Flex::Failure::Exhausted' );
if ( !$array->@* ) {
$current = undef;
return $self->signal_exhaustion;
}
};
$current = 0;
$next = 1;
$len = $array->@*;
return $array->[$current];
}
if ( $next == $len ) {
$prev = $array->[$current];
return $self->signal_exhaustion;
}
$prev = $array->[$current];
$current = $next++;
return $array->[$current];
};
}
return \%params;
}
__PACKAGE__->_add_roles( qw[
State::Closure
Next::ClosedSelf
Rewind::Closure
Reset::Closure
Prev::Closure
Current::Closure
Freeze
] );
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
( run in 1.153 second using v1.01-cache-2.11-cpan-6aa56a78535 )