File Coverage

lib/Math/String/Charset/Nested.pm
Criterion Covered Total %
statement 211 288 73.2
branch 85 142 59.8
condition 17 37 45.9
subroutine 13 18 72.2
pod 6 9 66.6
total 332 494 67.2


line stmt bran cond sub pod time code
1             #############################################################################
2             # Math/String/Charset/Nested -- charsets for Math/String
3             #
4             # Copyright (C) 1999-2003 by Tels. All rights reserved.
5             #############################################################################
6              
7             # todo: tri-grams etc
8             # store counts for different end-chars at the max elemt of _count?
9             # if we later need to calculate further, we could pick up there and need
10             # not to re-calculate the lower numbers
11              
12             package Math::String::Charset::Nested;
13              
14             require 5.005; # requires this Perl version or later
15 7     7   49 use strict;
  7         15  
  7         286  
16              
17 7     7   42 use base 'Math::String::Charset';
  7         22  
  7         1070  
18              
19             our $VERSION;
20             $VERSION = '1.30'; # Current version of this package
21              
22 7     7   53 use Math::BigInt;
  7         12  
  7         41  
23              
24             our $die_on_error;
25             $die_on_error = 1; # set to 0 to not die
26              
27             # following hash values are used:
28             # _clen : length of one character (all chars must have same len unless sep)
29             # _start : contains array of all valid start characters
30             # _ones : list of one-character strings (cross of _end and _start)
31             # _end : contains hash (for easier lookup) of all valid end characters
32             # _order : 1,2,3.. etc, 1 => simple, 2 => bigram etc
33             # _type : 0 => simple or bi-gram, 1 => grouping
34             # _error : error message or ""
35             # _count : array of count of different strings with length x
36             # _sum : array of starting number for strings with length x
37             # _sum[x] = _sum[x-1]+_count[x-1]
38             # _cnt : number of elements in _count and _sum (as well as in _scnt & _ssum)
39             # _cnum : number of characters in _ones as BigInt (for speed)
40             # _minlen: minimum string length (anything shorter is invalid), default 0
41             # _maxlen: maximum string length (anything longer is invalid), default undef
42             # _scale : optional input/output scale
43              
44             # simple ones:
45             # _sep : separator string (undef for none)
46             # _map : mapping character to number
47              
48             # higher orders:
49             # _bi : hash with refs to array of bi-grams
50             # _bmap : hash with refs to hash of bi-grams
51             # _scnt : array of hashes, count of strings starting with this character
52             # _sm : hash w/ mapping of start characters for faster lookup
53              
54             #############################################################################
55             # private, initialize self
56              
57             sub _strict_check
58             {
59             # a per class check, to be overwritten by subclasses
60 9     9   12 my $self = shift;
61 9         23 my $value = shift;
62              
63 9         16 my $class = ref($self);
64             return $self->{_error} = "Wrong type '$self->{_type}' for $class"
65 9 50       20 if $self->{_type} != 0;
66             return $self->{_error} = "Wrong order'$self->{_order}' for $class"
67 9 50       17 if $self->{_order} != 2;
68 9         33 foreach my $key (keys %$value)
69             {
70 27 50       94 return $self->{_error} = "Illegal parameter '$key' for $class"
71             if $key !~ /^(start|minlen|maxlen|sep|bi|end|charlen|scale)$/;
72             }
73             }
74              
75             sub _initialize
76             {
77             # set yourself to the value represented by the given string
78 9     9   13 my $self = shift;
79 9         42 my $value = shift;
80              
81 9         15 my $end = {}; # we make array later on
82             # add the user-specified end set
83 9   50     23 my $bi = $value->{bi} || {};
84 9 50       33 return $self->{_error} = "Field 'bi' must be hash ref"
85             if ref($bi) ne 'HASH';
86 9         16 $self->{_order} = 2;
87             # if no end set is defined, add all followers as default
88 9 100       23 if (exists $value->{end})
89             {
90 6         8 $end = { map { $_ => 1 } @{$value->{end}} };
  18         42  
  6         16  
91             }
92             else
93             {
94 3         12 foreach my $c (keys %$bi)
95             {
96 12         12 foreach my $f (@{$bi->{$c}})
  12         20  
97             {
98 24         33 $end->{$f} = 1;
99             }
100             }
101             }
102 9 50       21 if (exists $value->{start})
103             {
104 9         13 $self->{_start} = [ @{$value->{start}} ];
  9         25  
105             }
106             else
107             {
108             # else all chars w/ followers can start a string (longer than 2)
109 0         0 my $s = { };
110 0         0 foreach my $c (keys %$bi)
111             {
112 0 0       0 $s->{$c} = 1 if @{$bi->{$c}} > 0;
  0         0  
113             }
114 0         0 $self->{_start} = [ sort keys %$s ];
115             }
116              
117             # make copy
118 9         27 foreach my $c (keys %$bi)
119             {
120 46         72 $self->{_bi}->{$c} = [ @{$bi->{$c}} ]; # make copy
  46         104  
121             }
122 9 50       24 if (!defined $self->{_sep})
123             {
124 9         43 foreach my $c (keys %$bi)
125             {
126 9         17 $self->{_clen} = CORE::length($c);
127 9         11 last;
128             }
129             }
130             # add empty array for chars with no followers
131 9         18 $bi = $self->{_bi};
132 9         27 my @keys = keys %$bi; # make copy since keys may be modified (necc?)
133 9         16 foreach my $c (@keys)
134             {
135 46 100       48 $end->{$c} = 1 if @{$bi->{$c}} == 0; # no follower
  46         76  
136              
137 46         53 foreach my $f (@{$bi->{$c}})
  46         64  
138             {
139 79 100       127 $self->{_bi}->{$f} = [] if !defined $self->{_bi}->{$f};
140 79 100       91 $end->{$f} = 1 if @{$bi->{$f}} == 0;
  79         129  
141 79 50       128 if (!defined $self->{_sep})
142             {
143             return $self->{_error} = "Illegal char '$f', length not $self->{_clen}"
144 79 50       144 if length($f) != $self->{_clen};
145             }
146             }
147             }
148              
149 9         15 $self->{_end} = $end;
150             # build _ones and _sm list (cross from start/end)
151 9         15 $self->{_ones} = [];
152 9         23 $self->{_sm} = {};
153 9         16 foreach (@{$self->{_start}})
  9         18  
154             {
155 30 100       50 push @{$self->{_ones}}, $_ if exists $end->{$_};
  22         34  
156 30         49 $self->{_sm}->{$_} = 1;
157             }
158             # print "ones => ",join(' ',@{$self->{_ones}}),"\n";
159             # remove anything from start with no followers, but keep original order
160 9         12 my @s;
161 9         14 foreach my $c (@{$self->{_start}})
  9         31  
162             {
163             push @s, $c
164 30 100 100     62 if ((!defined $self->{_bi}->{$c}) || (@{$self->{_bi}->{$c}} > 0));
  27         86  
165             }
166 9         21 $self->{_start} = \@s;
167              
168             # initialize array of counts for len of 0..1
169 9         16 $self->{_cnt} = 1; # cached amount of class-sizes
170 9         16 $self->{_count}->[0] = 1; # '' is one string
171 9         29 $self->{_count}->[1] = Math::BigInt->new (scalar @{$self->{_ones}}); # 1
  9         39  
172              
173             # initialize array of counts for len of 2
174 9         466 $end = $self->{_end};
175 9         39 my $count = Math::BigInt::bzero();
176 9         233 foreach my $c (keys %$bi)
177             {
178 50 100       4748 $count += scalar @{$bi->{$c}} if exists $end->{$c};
  38         106  
179             }
180 9         962 $self->{_count}->[2] = $count; # 2
181 9         24 $self->{_cnt}++; # adjust cache size
182              
183             # init _sum array
184 9         54 $self->{_sum}->[0] = 0;
185 9         14 $self->{_sum}->[1] = 1;
186 9         27 $self->{_sum}->[2] = $self->{_count}->[1] + 1;
187              
188             # from _ones, make mapping name => number
189 9         1334 my $i = 1;
190 9         49 foreach (@{$self->{_ones}})
  9         20  
191             {
192 22         72 $self->{_map}->{$_} = $i++;
193             }
194             # create mapping for is_valid (contains number of follower)
195 9         14 foreach my $c (keys %{$self->{_bi}}) # for all chars
  9         25  
196             {
197 50         55 my $i = 0;
198 50         59 foreach my $cf (@{$self->{_bi}->{$c}}) # for all followers
  50         77  
199             {
200 79         139 $self->{_bmap}->{$c}->{$cf} = $i++; # make hash for easier lookup
201             }
202             }
203              
204             # init _scnt array ([0] not used in both)
205 9         22 $self->{_scnt}->[1] = {};
206             #foreach my $c (keys %{$self->{_map}}) # it's nearly the same
207             # {
208             # $self->{_ssum}->[1]->{$c} = $self->{_map}->{$c} - 1;
209             # }
210              
211             # class 1
212 9         15 foreach my $c (@{$self->{_start}})
  9         15  
213             {
214             $self->{_scnt}->[1]->{$c} = 1 # exactly one for each char
215 29 100       66 if exists $self->{_end}->{$c}; # but not for invalid's
216             }
217             # class 2
218 9         22 my $last = Math::BigInt::bzero();
219 9         196 foreach my $c (keys %{$self->{_bi}}) # for each possible character
  9         43  
220             {
221 50         3184 my $cnt = 0;
222 50         54 foreach my $cf (@{$bi->{$c}}) # for each follower
  50         80  
223             {
224 79 100       143 $cnt ++ if exists $self->{_end}->{$cf}; # that can end the string
225             }
226 50         77 $self->{_scnt}->[2]->{$c} = $cnt; # store
227             $last += $cnt # next one is summed up
228 50 100       127 if exists $self->{_sm}->{$c}; # if starting with valid char
229             }
230             # print $self->{_count}->[2]||0," should already be $last\n";
231 9         640 $self->{_count}->[2] = $last; # all in class #2
232 9         13 $self->{_cnt} = 2; # cache size for bi is one more
233 9         11 $self->{_cnum} = Math::BigInt->new( scalar @{$self->{_ones}} );
  9         43  
234 9 100       387 if ($self->{_cnum}->is_zero())
235             {
236 1 50       15 $self->{_minlen} = 2 if $self->{_minlen} == 1; # no one's
237             # check whether charset can have 2-character long strings
238 1 50       103 if ($self->{_count}->[2] == 0)
239             {
240 1 50       174 $self->{_minlen} = 3 if $self->{_minlen} == 2; # no two's
241             # check whether some path from start to end set exists, if not: empty
242 1         107 $self->_min_path_len();
243             }
244             }
245 9         155 return $self;
246             }
247              
248             sub _min_path_len
249             {
250             # for n-grams calculate the minimum path len
251             # Starting with each character in the start set, traverse the n-gram tree
252             # until it arrives at one of the end characters. The count between is the
253             # length of the shortes valid string.
254             # This might be greater than the length the user specified, because it is
255             # possible to have no shorter strings due to restrictions.
256 1     1   3 my $self = shift;
257              
258             # these are already know, and if non-zero, we already have minlen
259 1 50 33     4 return if $self->class(1) != 0 || $self->class(2) != 0;
260              
261 1   50     168 my $minlen = $self->{_minlen} || 3; # either the defined min len, or 3
262             }
263              
264             sub dump
265             {
266 0     0 0 0 my $self = shift;
267              
268 0         0 print "type: BIGRAM:\n";
269 0         0 my $bi = $self->{_bi};
270 0         0 foreach my $c (keys %$bi)
271             {
272 0         0 print " $c => [";
273 0         0 foreach my $f (@{$bi->{$c}})
  0         0  
274             {
275 0         0 print "'$f', ";
276             }
277 0         0 print "]\n";
278             }
279 0         0 print "start: ", join(' ',@{$self->{_start}}),"\n";
  0         0  
280 0         0 print "end : ", join(' ',keys %{$self->{_end}}),"\n";
  0         0  
281 0         0 print "ones : ", join(' ',@{$self->{_ones}}),"\n";
  0         0  
282             }
283              
284             sub _calc
285             {
286             # given count of len 1..x, calculate count for y (y > x) and all between
287             # x and y
288             # currently re-calcs from 2 on, we could save the state and only calculate
289             # the missing counts.
290              
291 8     8   158 my $self = shift;
292 8 50 50     35 my $max = shift || 1; $max = 1 if $max < 1;
  8         16  
293 8 100       20 return if $max <= $self->{_cnt};
294              
295             # my ($counts,$org_counts);
296             # map to hash
297             # my $end = $self->{_end};
298             # %$counts = map { $_, $end->{$_} } keys %$end; # make copy
299              
300 7         9 my ($last,$count);
301 7         14 my $i = $self->{_cnt}+1; # start with next undefined level
302 7         14 while ($i <= $max)
303             {
304             # take current level, calculate all possible ending characters
305             # and count them (e.g. 2 times 'b', 2 times 'c' and 3 times 'a')
306             # each of the ending chars has a number of possible bi-grams. For the next
307             # length, we must add the count of the ending char to each of the possible
308             # bi-grams. After this, we get the new count for all new ending chars.
309             # %$org_counts = map { $_, $counts->{$_} } keys %$counts; # make copy
310             # $counts = {}; # init to 0
311             # $cnt = Math::BigInt::bzero();
312             # # for each of the ending chars
313             # foreach my $char (keys %$org_counts)
314             # {
315             # # and for each of it's bigrams
316             # $c = $org_counts->{$char}; # speed up
317             # foreach my $ec ( @{$self->{_bi}->{$char}})
318             # {
319             # # add to the new ending char the number of possibilities
320             # $counts->{$ec} += $c;
321             # }
322             # # now sum them up by multiplying bi-grams times org_char count
323             # $cnt += @{$self->{_bi}->{$char}} * $org_counts->{$char};
324             # }
325             # $self->{_count}->[$i] = $cnt; # store this level
326             #print "$i => $self->{_count}->[$i]\n";
327              
328             #########################################################################
329             # for each starting char, add together how many strings each follower
330             # starts in level-1
331             # print "level $i\n";
332 8         25 $last = Math::BigInt::bzero();
333 8         190 $count = Math::BigInt::bzero(); # all counts
334 8         150 my $bi = $self->{_bi};
335 8         25 foreach my $c (keys %$bi) # for each possible char
336             {
337 44         1971 my $cnt = 0;
338 44         48 foreach my $cf (@{$bi->{$c}}) # for each follower
  44         77  
339             {
340 64   100     161 my $ci = $self->{_scnt}->[$i-1]->{$cf} || 0;
341             # print "$c followed by $cf $ci times\n",
342 64         132 $cnt += $ci; # add count in level-1
343             }
344 44         74 $self->{_scnt}->[$i]->{$c} = $cnt; # store
345             # $self->{_ssum}->[$i]->{$c} = $last; # store sum up to here
346 44         96 $last += $cnt; # next one is summed up
347 44 100       6225 $count += $cnt if exists $self->{_sm}->{$c}; # only valid starts
348             # print "last $last count $count cnt $cnt\n";
349             }
350 8         558 $self->{_count}->[$i] = $count; # all in class w/ valid starts
351 8         26 $self->{_sum}->[$i] = $self->{_count}->[$i-1] + $self->{_sum}->[$i-1];
352              
353             # $last = Math::BigInt->bzero(); # set to 0
354             # foreach $c (@{$self->{_start}})
355             # {
356             # $cnt = Math::BigInt->bzero(); # number of followers
357             # foreach $cf (@{$self->{_bi}->{$c}}) # for each follower
358             # {
359             # my $ci = $self->{_scnt}->[$i-1]->{$cf} || 0;
360             # print "$c $cnt += ",$ci," ($cf)\n";
361             # $cnt += $ci; # add count in level-1
362             # }
363             # $self->{_scnt}->[$i]->{$c} = $cnt; # and store it
364             # $self->{_ssum}->[$i]->{$c} = $last; # store sum up to here
365             # $last += $cnt; # next one is summed up
366             # }
367             # $self->{_count}->[$i] = $last; # sum of all strings
368             # $self->{_sum}->[$i] = $self->{_count}->[$i-1] + $self->{_sum}->[$i-1];
369 8         565 $i++;
370             }
371 7         22 $self->{_cnt} = $i-1; # store new cache size
372             }
373              
374             sub is_valid
375             {
376             # check wether a string conforms to the given charset set
377 7     7 1 13 my $self = shift;
378 7         10 my $str = shift;
379              
380             # print "$str\n";
381 7 50       14 return 0 if !defined $str;
382 7 50 33     19 return 1 if $str eq '' && $self->{_minlen} <= 0;
383              
384             #my $int = Math::BigInt::bzero();
385 7         10 my @chars;
386 7 50       17 if (defined $self->{_sep})
387             {
388 0         0 @chars = split /$self->{_sep}/,$str;
389 0 0       0 shift @chars if $chars[0] eq '';
390 0 0       0 pop @chars if $chars[-1] eq $self->{_sep};
391             }
392             else
393             {
394 7         9 my $i = 0; my $len = CORE::length($str); my $clen = $self->{_clen};
  7         9  
  7         9  
395 7         14 while ($i < $len)
396             {
397 23         38 push @chars, substr($str,$i,$clen); $i += $clen;
  23         49  
398             }
399             }
400             # length okay?
401 7 50       26 return 0 if scalar @chars < $self->{_minlen};
402 7 50       498 return 0 if scalar @chars > $self->{_maxlen};
403              
404             # valid start char?
405 7         422 my $map = $self->{_map};
406 7 100       21 return 0 unless exists $map->{$chars[0]};
407             # check if conforms to bi-grams
408 6 50       11 return 1 if @chars == 1;
409             # further checks for strings longer than 1
410 6         7 my $i = 1; # start at second char
411 6         10 $map = $self->{_bmap};
412 6         19 while ($i < @chars)
413             {
414             #print "is valid $i $chars[$i-1] $chars[$i]\n";
415             # print "$chars[$i-1] $chars[$i]: ",
416             # $map->{$chars[$i-1]} || 'undef'," ",
417             # $map->{$chars[$i-1]}->{$chars[$i]} || 'undef',"\n";
418 13 100       27 return 0 unless exists $map->{$chars[$i-1]};
419 12 100       37 return 0 unless exists $map->{$chars[$i-1]}->{$chars[$i]};
420 8         16 $i++;
421             }
422 1         5 return 1;
423             }
424              
425             sub num2str
426             {
427             # convert Math::BigInt/Math::String to string
428 0     0 0 0 my $self = shift;
429 0         0 my $x = shift;
430              
431 0 0       0 $x = new Math::BigInt($x) unless ref $x;
432 0 0       0 return undef if ($x->sign() !~ /^[+-]$/);
433 0 0       0 if ($x->is_zero())
434             {
435 0 0       0 return wantarray ? ('',0) : '';
436             }
437 0         0 my $j = $self->{_cnum}; # nr of chars
438              
439 0 0       0 if ($x <= $j)
440             {
441 0         0 my $c = $self->{_ones}->[$x-1];
442 0 0       0 return wantarray ? ($c,1) : $c; # string len == 1
443             }
444              
445 0         0 my $digits = $self->chars($x); my $d = $digits;
  0         0  
446              
447             # now treat the string as it were a zero-padded string of length $digits
448              
449 0         0 my $es = "num2str() for bi-grams not ready yet";
450 0 0       0 return wantarray ? ($es,$d) : $es;
451             }
452              
453             sub str2num
454             {
455             # convert Math::String to Math::BigInt
456 4     4 0 237 my $self = shift;
457 4         5 my $str = shift; # simple string
458              
459 4         9 my $int = Math::BigInt::bzero();
460 4         90 my $i = CORE::length($str);
461              
462 4 100       10 return $int if $i == 0;
463 3         5 my $map = $self->{_map};
464 3         14 my $clen = $self->{_clen}; # len of one char
465 3 50       29 return new Math::BigInt($map->{$str}) if $i == $clen;
466 0 0       0 if (!defined $self->{_sep})
467             {
468 0         0 my $class = $i / $clen;
469 0 0       0 $self->_calc($class) if $class > $self->{_cnt}; # not yet cached?
470 0         0 $int = $self->{_sum}->[$class]; # base number
471             # print "base $int class $class\n";
472 0         0 $i = $clen; $class--;
  0         0  
473             # print "start with pos $i, class $class\n";
474 0         0 while ($class > 0)
475             {
476 0         0 $int += $self->{_ssum}->[$class]->{substr($str,$i,$clen)};
477             # print "$i $class $int ",substr($str,$i,$clen)," ",
478             # $self->{_ssum}->[$class]->{substr($str,$i,$clen)},"\n";
479 0         0 $class --;
480 0         0 $i += $clen;
481             #print "s2n $int j: $j i: $i m: $mul c: ",
482             #substr($str,$i+$clen,$clen),"\n";
483             }
484             # print "$int\n";
485             }
486             else
487             {
488             # sep char
489 0         0 my @chars = split /$self->{_sep}/, $str;
490 0 0       0 shift @chars if $chars[0] eq ''; # strip leading sep
491 0         0 my $class = scalar @chars;
492 0         0 foreach (@chars)
493             {
494 0         0 $int += $self->{_ssum}->[$class]->{$_};
495 0         0 $class --;
496             # print "$class $int\n";
497             }
498             }
499 0         0 return $int;
500             }
501              
502             sub chars
503             {
504             # return number of characters in output string
505 0     0 1 0 my $self = shift;
506 0         0 my $x = shift;
507              
508 0 0 0     0 return 0 if $x->is_zero() || $x->is_nan() || $x->is_inf();
      0        
509              
510 0         0 my $i = 1;
511             # not done yet
512 0         0 return $i;
513             }
514              
515             sub first
516             {
517 13     13 1 25 my $self = shift;
518 13   100     33 my $count = abs(shift || 0);
519              
520 13 100       40 return if $count < $self->{_minlen};
521 11 100 66     513 return if defined $self->{_maxlen} && $count > $self->{_maxlen};
522 10 100       451 return '' if $count == 0;
523              
524 9 100       21 return $self->{_ones}->[0] if $count == 1;
525 8         9 my $f;
526 8         10 foreach my $c (@{$self->{_start}})
  8         17  
527             {
528 8         35 $f = $self->_first('',$c,1,$count);
529 8 50       38 return $f if defined $f;
530             }
531 0         0 return;
532             }
533              
534             sub _first
535             {
536             # recursively check followers whether they are okay, or not
537             # $self, $f, $ending, $level, $count,
538              
539 29     29   51 my ($self,$f,$ending,$level,$count) = @_;
540              
541 29 100       55 if ($level >= $count) # overshot
542             {
543 8 50       29 return $f.$ending if exists $self->{_end}->{$ending};
544 0         0 return;
545             }
546              
547 21 50       35 return if !exists $self->{_bi}->{$ending};
548 21         25 foreach my $c (@{$self->{_bi}->{$ending}})
  21         45  
549             {
550 21         81 my $rc = $self->_first($f.$ending,$c,$level+1,$count);
551 21 100       54 return $rc if defined $rc;
552             }
553 1         3 return; # found nothing
554             }
555              
556             sub _last
557             {
558             # recursively check followers whether they are okay, or not
559             # $self, $f, $ending, $level, $count,
560              
561 28     28   59 my ($self,$f,$ending,$level,$count) = @_;
562              
563 28 100       48 if ($level >= $count) # overshot
564             {
565 6 50       21 return $f.$ending if exists $self->{_end}->{$ending};
566 0         0 return;
567             }
568              
569 22 100       51 return if !exists $self->{_bi}->{$ending};
570              
571 16         16 foreach my $c (reverse @{$self->{_bi}->{$ending}})
  16         25  
572             {
573 16         53 my $rc = $self->_last($f.$ending,$c,$level+1,$count);
574 16 100       39 return $rc if defined $rc;
575             }
576 3         4 return; # found nothing
577             }
578              
579             sub last
580             {
581 10     10 1 18 my $self = shift;
582 10   100     26 my $count = abs(shift || 0);
583              
584 10 100       35 return if $count < $self->{_minlen};
585 8 50 33     493 return if defined $self->{_maxlen} && $count > $self->{_maxlen};
586 8 100       417 return '' if $count == 0;
587              
588 7 100       18 return $self->{_ones}->[-1] if $count == 1;
589 6         7 my $f;
590 6         8 foreach my $c (reverse @{$self->{_start}})
  6         14  
591             {
592 12         19 $f = $self->_last('',$c,1,$count);
593 12 100       38 return $f if defined $f;
594             }
595 0           return;
596             }
597              
598             sub next
599             {
600 0     0 1   my $self = shift;
601 0           my $str = shift;
602              
603 0 0         if ($str->{_cache} eq '') # 0 => 1
604             {
605 0   0       $str->{_cache} = $self->first($self->minlen()||1);
606 0           return;
607             }
608              
609             # only the rightmost digit is adjusted. If this overflows, we simple
610             # invalidate the cache. The time saved by updating the cache would be to
611             # small to be of use, especially since updating the cache takes more time
612             # then. Also, if the cached isn't used later, we would have spent the
613             # update-time in vain.
614              
615             # for higher orders not ready yet
616 0           $str->{_cache} = undef;
617              
618 0           $self;
619             }
620              
621             sub prev
622             {
623 0     0 1   my $self = shift;
624 0           my $str = shift;
625              
626 0 0         if ($str->{_cache} eq '') # 0 => 1
627             {
628 0   0       $str->{_cache} = $self->first($self->minlen()||1);
629 0           return;
630             }
631              
632             # for higher orders not ready yet
633 0           $str->{_cache} = undef;
634              
635 0           $self;
636             }
637              
638              
639             __END__