FAST

 view release on metacpan or  search on metacpan

lib/FAST/List/Gen.pm  view on Meta::CPAN


    sub empty () {tiegen 'Empty'}
    generator Empty => sub {
        curse {
            FETCH => sub () { },
            fsize => sub () {0},
        } => shift
    };


=head2 source generators

=over 4

=item range C< SIZE >

returns a generator from C< 0 > to C< SIZE - 1 >

    my $range = range 10;

    say $range->str;  # 0 1 2 3 4 5 6 7 8 9
    say $range->size; # 10

=item range C< START STOP [STEP] >

returns a generator for values from C< START > to C< STOP > by C< STEP >,
inclusive.

C< STEP > defaults to 1 but can be fractional and negative. depending on your
choice of C< STEP >, the last value returned may not always be C< STOP >.

    range(0, 3, 0.4) will return (0, 0.4, 0.8, 1.2, 1.6, 2, 2.4, 2.8)

    print "$_ " for @{range 0, 1, 0.1};
    # 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1

    print "$_ " for @{range 5, 0, -1};
    # 5 4 3 2 1 0

    my $nums = range 0, 1_000_000, 2;
    print "@$nums[10, 100, 1000]";
    # gets the tenth, hundredth, and thousandth numbers in the range
    # without calculating any other values

C<range> also accepts character strings instead of numbers.  it will behave
the same way as perl's internal C< .. > operator, except it will be lazy.

    say range('a', 'z')->str;   # 'a b c d e f g ... x y z'

    range('a', 'zzz', 2)->say;  # 'a c e g i k m ... zzu zzw zzy'

    say <A .. ZZ>->str;         # 'A B C D E ... ZX ZY ZZ'

    <1..>->zip(<a..>)->say(10); # '1 a 2 b 3 c 4 d 5 e'

to specify an infinite range, you can pass C< range > an infinite value
(C< 9**9**9 > works well), or the glob C< ** >, or the string C< '*' >

    range(1, 9**9**9) ~~ range(1, **) ~~ range(1, '*') ~~ <1..*> ~~ <1..>

ranges only store their endpoints, and ranges of all sizes take up the same
amount of memory.

=cut

    sub range ($;$$) {
        splice @_, 1, 1, 9**9**9
            if @_ > 1 and $_[1] eq '*'
                      || \$_[1] == \**;
        for (@_) {
            defined
            and /^[a-z]+$/i
            and not looks_like_number $_
            and goto &arange
        }
        tiegen Range => @_ == 1 ? (0, $_[0] - 1) : @_
    }
    generator Range => sub {
        my ($class, $low, $high, $step, $size) = (@_, 1);
        $size = $high < 9**9**9
            ? do {
                $size = $step > 0 ? $high - $low : $low - $high;
                $size = 1 + $size / abs $step;
                $size > 0 ? int $size : 0
            } : $high;

        $size = 0 unless $low < 9**9**9;
        curse {
            FETCH => sub {
                $_[1] < $size
                      ? $low + $step * $_[1]
                      : croak "range index $_[1] out of bounds [0 .. @{[$size - 1]}]"
            },
            fsize => sub {$size},
            range => sub {$low, $step, $size},
        } => $class
    };

    {my %map; @map{0..25} = 'a'..'z';
     my @cache = 'a'..'zz';
    sub num2alpha {
        my $num = @_ ? $_[0] : $_;
        return '-'.num2alpha(-$num) if $num < 0;
        return $cache[$num]         if $num < 702;
        my @str;
        while ($num > -1) {
            unshift @str, $map{$num % 26};
            $num = int($num / 26) - 1;
        }
        join '' => @str
    }}

    {my %map; @map{'a'..'z'} = 0..25;
    sub alpha2num {
        my $str = shift;
        return -alpha2num($1) if $str =~ /^-(.+)/;
        my ($num, $scale);
        for (split //, reverse $str) {
            $num += ($map{$_} + !!$scale) * 26**$scale++
        }
        $num



( run in 1.020 second using v1.01-cache-2.11-cpan-39bf76dae61 )