File Coverage

blib/lib/Math/Prime/Util/PrimeArray.pm
Criterion Covered Total %
statement 79 85 92.9
branch 20 30 66.6
condition 15 15 100.0
subroutine 15 20 75.0
pod n/a
total 129 150 86.0


line stmt bran cond sub pod time code
1             package Math::Prime::Util::PrimeArray;
2 2     2   48704 use strict;
  2         15  
  2         69  
3 2     2   15 use warnings;
  2         5  
  2         81  
4              
5             BEGIN {
6 2     2   6 $Math::Prime::Util::PrimeArray::AUTHORITY = 'cpan:DANAJ';
7 2         31 $Math::Prime::Util::PrimeArray::VERSION = '0.68';
8             }
9              
10             # parent is cleaner, and in the Perl 5.10.1 / 5.12.0 core, but not earlier.
11             # use parent qw( Exporter );
12 2     2   10 use base qw( Exporter );
  2         4  
  2         516  
13             our @EXPORT_OK = qw(@primes @prime @pr @p $probj);
14             our %EXPORT_TAGS = (all => [ @EXPORT_OK ]);
15              
16             # It would be nice to do this dynamically.
17             our(@primes, @prime, @pr, @p, $probj);
18             sub import {
19 2 50   2   13 tie @primes, __PACKAGE__ if grep { $_ eq '@primes' } @_;
  2         9  
20 2 50       4 tie @prime , __PACKAGE__ if grep { $_ eq '@prime' } @_;
  2         5  
21 2 50       3 tie @pr , __PACKAGE__ if grep { $_ eq '@pr' } @_;
  2         6  
22 2 50       4 tie @p , __PACKAGE__ if grep { $_ eq '@p' } @_;
  2         4  
23 2 50       4 $probj = __PACKAGE__->TIEARRAY if grep { $_ eq '$probj' } @_;
  2         4  
24 2         1619 goto &Exporter::import;
25             }
26              
27 2     2   783 use Math::Prime::Util qw/nth_prime nth_prime_upper nth_prime_lower primes prime_precalc next_prime prev_prime/;
  2         4  
  2         20  
28 2     2   526 use Tie::Array;
  2         1804  
  2         52  
29 2     2   12 use Carp qw/carp croak confess/;
  2         3  
  2         87  
30              
31 2     2   10 use constant SEGMENT_SIZE => 50_000;
  2         3  
  2         92  
32 2     2   9 use constant ALLOW_SKIP => 3_000; # Sieve if skipping up to this
  2         4  
  2         1181  
33              
34             sub TIEARRAY {
35 4     4   886 my $class = shift;
36 4 50       13 if (@_) {
37 0         0 croak "usage: tie ARRAY, '" . __PACKAGE__ . "";
38             }
39 4         19 return bless {
40             # used to keep track of shift
41             SHIFTINDEX => 0,
42             # Remove all extra prime memory when we go out of scope
43             MEMFREE => Math::Prime::Util::MemFree->new,
44             # A chunk of primes
45             PRIMES => [2, 3, 5, 7, 11, 13, 17],
46             # What's the index of the first one?
47             BEG_INDEX => 0,
48             # What's the index of the last one?
49             END_INDEX => 6,
50             # positive = forward, negative = backward, 0 = random
51             ACCESS_TYPE => 0,
52             }, $class;
53             }
54 0     0   0 sub STORE { carp "You cannot write to the prime array"; }
55 0     0   0 sub DELETE { carp "You cannot write to the prime array"; }
56 0     0   0 sub STORESIZE { carp "You cannot write to the prime array"; }
57 0     0   0 sub EXISTS { 1 }
58             #sub EXTEND { my $self = shift; my $count = shift; prime_precalc($count); }
59 0     0   0 sub EXTEND { 1 }
60 2     2   6 sub FETCHSIZE { 0x7FFF_FFFF } # Even on 64-bit
61             # Simple FETCH:
62             # sub FETCH { return nth_prime($_[1]+1); }
63              
64             sub FETCH {
65 2067     2067   19916 my ($self, $index) = @_;
66 2067 50       3031 $index = 0xFFFFFFFF + $index + 1 if $index < 0;
67 2067         2523 $index += $self->{SHIFTINDEX}; # take into account any shifts
68 2067         2437 my $begidx = $self->{BEG_INDEX};
69 2067         2344 my $endidx = $self->{END_INDEX};
70              
71 2067 100 100     4787 if ( $index < $begidx || $index > $endidx ) {
72              
73 51 100 100     176 if ($index > $endidx && $index < $endidx + ALLOW_SKIP) { # Forward iteration
    100 100        
74              
75 22         30 $self->{ACCESS_TYPE}++;
76 22 100 100     58 if ($self->{ACCESS_TYPE} > 2 || $index > $endidx+1) {
77 16         371 my $end_prime = nth_prime_upper($index + SEGMENT_SIZE);
78 16         56 $self->{PRIMES} = primes( $self->{PRIMES}->[-1]+1, $end_prime );
79 16         33 $begidx = $endidx+1;
80             } else {
81 6         9 push @{$self->{PRIMES}}, next_prime($self->{PRIMES}->[-1]);
  6         20  
82             }
83              
84             } elsif ($index < $begidx && $index > $begidx - ALLOW_SKIP) { # Bk iteration
85              
86 22         29 $self->{ACCESS_TYPE}--;
87 22 100 100     52 if ($self->{ACCESS_TYPE} < -2 || $index < $begidx-1) {
88 14 50       26 my $beg_prime = $index <= SEGMENT_SIZE
89             ? 2 : nth_prime_lower($index - SEGMENT_SIZE);
90 14         37 $self->{PRIMES} = primes($beg_prime, $self->{PRIMES}->[0]-1);
91 14         40 $begidx -= scalar @{ $self->{PRIMES} };
  14         37  
92             } else {
93 8         11 $begidx--;
94 8         10 unshift @{$self->{PRIMES}}, prev_prime($self->{PRIMES}->[0]);
  8         1423  
95             }
96              
97             } else { # Random access
98              
99 7         19 $self->{ACCESS_TYPE} = int($self->{ACCESS_TYPE} / 2);
100             # Alternately we could get a small window, but that will be quite
101             # a bit slower if true random access.
102 7         10 $begidx = $index;
103 7         760 $self->{PRIMES} = [nth_prime($begidx+1)];
104              
105             }
106 51         87 $self->{BEG_INDEX} = $begidx;
107 51         59 $self->{END_INDEX} = $begidx + scalar @{$self->{PRIMES}} - 1;
  51         99  
108             }
109 2067         4749 return $self->{PRIMES}->[ $index - $begidx ];
110             }
111              
112             # Fake out shift and unshift
113             sub SHIFT {
114 5     5   13 my $self = shift;
115 5         9 my $head = $self->FETCH(0);
116 5         9 $self->{SHIFTINDEX}++;
117 5         20 $head;
118             }
119             sub UNSHIFT {
120 2     2   494 my ($self, $shiftamount) = @_;
121 2 50       9 $shiftamount = 1 unless defined $shiftamount;
122             $self->{SHIFTINDEX} = ($shiftamount >= $self->{SHIFTINDEX})
123             ? 0
124 2 50       8 : $self->{SHIFTINDEX} - $shiftamount;
125 2         8 $self->FETCHSIZE;
126             }
127             # CLEAR this
128             # PUSH this, LIST
129             # POP this
130             # SPLICE this, offset, len, LIST
131             # DESTROY this
132             # UNTIE this
133              
134             1;
135              
136             __END__