Iterator-Flex

 view release on metacpan or  search on metacpan

lib/Iterator/Flex/Permute.pm  view on Meta::CPAN

package Iterator::Flex::Permute;

# ABSTRACT: Permute Iterator Class

use v5.28;
use strict;
use warnings;
use experimental qw( signatures postderef declared_refs );

our $VERSION = '0.34';

use parent 'Iterator::Flex::Base';
use Iterator::Flex::Utils qw( :IterAttrs :IterStates throw_failure );
use Iterator::Flex::Factory 'to_iterator';
use Scalar::Util;
use Ref::Util 'is_hashref', 'is_arrayref';

use namespace::clean;




































sub new ( $class, $array, $pars = {} ) {

    throw_failure( parameter => q{'array' argument must be an array} )
      unless is_arrayref( $array );

    throw_failure( parameter => q{'pars' argument must be a hash} )
      unless is_hashref( $pars );

    my %pars = $pars->%*;
    my $k    = delete $pars{k} // $array->@*;
    my $n    = $array->@*;

    defined $k && Scalar::Util::looks_like_number( $k ) && int( $k ) == $k && $k > 0
      || throw_failure( parameter => 'k parameter is not a positive integer' );

    throw_failure( parameter => "size of subset (k = $k) > size of set ( $n )" )
      if $k > $n;

    $class->SUPER::new( { k => $k, array => $array, }, \%pars );
}


my sub permutations;

sub construct ( $class, $state ) {

    throw_failure( parameter => q{state must be a HASH reference} )
      unless Ref::Util::is_hashref( $state );

    my ( $array, $k, $idx, $value, $c, $i, $restart ) = @{$state}{
        qw[ array k idx value
          c i restart
        ] };

    $value //= [];

    $c       //= [ ( 0 ) x $k ];
    $i       //= 1;
    $restart //= !!0;

    my $self;
    my $iterator_state;
    my $n = $array->@*;

    my %params = (

        ( +_SELF ) => \$self,

        ( +STATE ) => \$iterator_state,


        ( +CURRENT ) => sub {
            return $idx ? [ $value->@* ] : undef;
        },

        ( +RESET ) => sub {
            $i       = 1;
            $c       = [ ( 0 ) x $k ];
            $restart = !!0;

            $idx = undef;
            $value->@* = ();
        },

        +( REWIND ) => sub {
            $i       = 1;
            $c       = [ ( 0 ) x $k ];
            $restart = !!0;
            $idx     = undef;
        },

    );

    if ( $n == $k ) {

        $params{ +NEXT } = sub {
            return $self->signal_exhaustion
              if $iterator_state == IterState_EXHAUSTED;

            my \@value = $value;
            my \@array = $array;

            if ( !defined $idx ) {
                $idx = [ 0 .. $k - 1 ];
            }
            else {
                $i = permutations( $c, $i, $n, $idx, $restart );
                return $self->signal_exhaustion if !defined $i;



( run in 0.661 second using v1.01-cache-2.11-cpan-6aa56a78535 )