File Coverage

blib/lib/Tie/REHash.pm
Criterion Covered Total %
statement 191 243 78.6
branch 138 284 48.5
condition 47 102 46.0
subroutine 22 23 95.6
pod 3 13 23.0
total 401 665 60.3


line stmt bran cond sub pod time code
1             package Tie::REHash;
2            
3 1     1   46524 use 5.006;
  1         3  
4            
5 1     1   5 use strict qw[vars subs];
  1         1  
  1         32  
6             $Tie::REHash::VERSION = '1.06';
7            
8 1     1   4 no warnings;
  1         6  
  1         897  
9            
10             sub CDUP () { 0 }
11             sub CMIS () { 1 }
12             sub CHIT () { 1 }
13             sub OFFSET () { 0 }
14             our (%Global_options, %AD);
15             our $qr_fragment = qr{(subcall[\w\d]+)(?:\(\))?};
16            
17             $AD{croak} = 'use Carp;';
18            
19             $AD{import} = <<'SUBCODE';
20             sub import {
21             my $self = shift;
22             %Global_options = ref $_[0] eq 'HASH' ? %{$_[0]} : @_;
23            
24             $Global_options{precompile}
25             and $self->precompile;
26            
27             exists $Global_options{stringref_bug_is_fixed}
28             and $self->stringref_bug_is_fixed;
29             }
30             SUBCODE
31            
32             *tiehash = \&new;
33             *TIEHASH = \&new;
34             *STORE = \&store;
35             *FETCH = \&fetch;
36             *EXISTS = \&exists;
37             *DELETE = \&delete;
38             *FIRSTKEY = \&firstkey;
39             *NEXTKEY = \&nextkey;
40             *SCALAR = \&scalar;
41             *CLEAR = \&clear;
42            
43             $AD{new} = <<'SUBCODE';
44             sub new {
45             return $_[0]
46             if ref $_[0];
47            
48             my $self = bless {}, $_[0];
49            
50             if (ref $_[1]) {
51             $_[1] =~ /HASH/
52             or croak("Wrong $_[1] argument to tie()");
53            
54             $self->{REGX} = [ $_[1] ];
55             $self->{DELIM} = $_[2] if @_ == 3;
56             }
57             else {
58             shift @_;
59            
60             $self->{DELIM} = pop @_
61             if @_ - 2*int(@_/2);
62            
63             $self->{REGX} = [ {@_} ];
64             }
65            
66             $self->{ESC} = {};
67            
68             $self->{DELIM} = $Global_options{autodelete_limit}
69             if exists $Global_options{autodelete_limit};
70            
71             $self->{OFFSET2} = $Global_options{_offset2}
72             if exists $Global_options{_offset2};
73            
74             $self->{REMOD}
75             = exists $Global_options{remove_dups}
76             ? $Global_options{remove_dups}
77             : 1;
78            
79             $self->{CACH}
80             = ref $Global_options{do_cache} eq 'HASH'
81             ? $Global_options{do_cache} : {}
82             if exists $Global_options{do_cache};
83            
84             $self->{CMIS2}
85             = exists $Global_options{do_cache_miss}
86             ? $Global_options{do_cache_miss}
87             : 1;
88            
89             $self->{CHIT2}
90             = exists $Global_options{do_cache_hit}
91             ? $Global_options{do_cache_hit}
92             : 1;
93            
94             return $self
95             }
96             SUBCODE
97            
98             $AD{store} = <<'SUBCODE';
99             sub store {
100             my $self = $_[0];
101            
102             $self->{IS_NORMALIZED} = undef;
103            
104             my $cach = $self->{CACH} if !CDUP;
105            
106             my ($k, $esc, $dyn);
107            
108             !ref $_[1] ? $k = $_[1]
109             : do{
110             ($k, $esc, $dyn)
111             = (ref $_[1] eq 'REF'
112             or ref $_[1] eq 'SCALAR')
113             ? ref $_[2] eq 'CODE'
114             ? ( ${$_[1]}, undef, 1 )
115             : ( ${$_[1]}, 1 )
116             : ( $_[1] );
117            
118             if (ref $k eq 'Regexp') {
119             $dyn
120             ? $self->{DYN2}{$k} = 1
121             : delete $self->{DYN2}{$k};
122             $esc
123             ? $self->{ESC2}{$k} = 1
124             : delete $self->{ESC2}{$k};
125            
126             if (exists $self->{REGX2}{$k}) {
127             my $regx = $self->{REGX};
128            
129             $k eq $regx->[$_]
130             and splice(@$regx, $_, 1)
131             foreach reverse 0..$#$regx;
132             }
133            
134             my (@upfront, $element);
135             while (@{$self->{REGX}}) {
136             $element = $self->{REGX}[0];
137            
138             last
139             if ref $element eq 'Regexp'
140             or $self->{DELIM}
141             and $self->{DELIM} <= keys %$element;
142            
143             shift @{$self->{REGX}};
144            
145             $_ =~ $k
146             and delete $element->{$_}
147             foreach keys %$element;
148            
149             push @upfront, $element;
150             }
151             unshift @{$self->{REGX}}, @upfront, $k;
152            
153             if (!CDUP and $cach) {
154             $_ =~ $k
155             and delete $cach->{$_}
156             foreach keys %$cach;
157             }
158            
159             return $self->{REGX2}{$k} = $esc ? undef : $_[2]
160             }
161            
162             _examine($self)
163             if @{$self->{REGX}} > 1;
164             };
165            
166             !CDUP
167             and $cach
168             and delete $cach->{$k};
169            
170             $esc
171             and @{$self->{REGX}} == 1
172             and ref $self->{REGX}[0] eq 'HASH'
173             and delete $self->{REGX}[0]{$k}
174             , delete $self->{ESC}{$k}
175             , delete $self->{DYN}{$k}
176             , return undef;
177            
178             $dyn
179             ? $self->{DYN}{$k} = 1
180             : delete $self->{DYN}{$k};
181             $esc
182             ? $self->{ESC}{$k} = 1
183             : delete $self->{ESC}{$k};
184            
185             my $offset;
186             foreach (@{$self->{REGX}}) {
187             last
188             if ref $_ eq 'Regexp'
189             and $k =~ $_;
190            
191             return $_->{$k} = $esc ? undef : $_[2]
192             if ref $_ eq 'HASH';
193            
194             last if OFFSET
195             and $self->{OFFSET2}
196             and $self->{OFFSET2} <= ++$offset;
197             }
198            
199             unshift @{$self->{REGX}}, {$k => $esc ? undef : $_[2] };
200            
201             return $esc ? undef : $_[2]
202             }
203             SUBCODE
204            
205             $AD{subcall_match} = <<'SUBCODE';
206             SUBCODE
207             $AD{subcall_match2} = <<'SUBCODE';
208             !$cach2
209             ? $self->{REGX2}{ $_}
210             : ( CDUP
211             ? $self->{REGX}[0]{$k}
212             : ${ $cach2->{$k}
213             = \$self->{REGX2}{ $_} } )
214             SUBCODE
215             $AD{subcall_match0} = <<'SUBCODE';
216             !$cach2
217             ? undef
218             : ( CDUP
219             ? $self->{REGX}[0]{$k}
220             : $cach2->{$k} = undef
221             , $self->{ESC}{$k} = 1 )[0]
222             SUBCODE
223            
224             $AD{subcall_fetch} = <<'SUBCODE';
225             ($_ eq $cach ? ${$_->{$k}}
226             : $_->{$k})
227             SUBCODE
228             $AD{subcall_fetch2} = <<'SUBCODE';
229             !$cach2
230             ? $_ eq $cach ? ${$_->{$k}}
231             : $_->{$k}
232             : ( CDUP
233             ? $self->{REGX}[0]{$k}
234             : ${ $cach2->{$k}
235             = \$_->{$k} } )
236             SUBCODE
237             $AD{subcall_fetch0} = <<'SUBCODE';
238             !$cach2
239             ? undef
240             : ( CDUP
241             ? $self->{REGX}[0]{$k}
242             : $cach2->{$k}
243             = undef )
244             SUBCODE
245            
246             $AD{fetch} = <<'SUBCODE';
247             sub fetch {
248             my $self = $_[0];
249             my $type = $_[2];
250            
251             my ($k, $esc);
252            
253             !ref $_[1] ? $k = $_[1]
254             : do{
255             ($k, $esc)
256             = (ref $_[1] eq 'REF'
257             or ref $_[1] eq 'SCALAR')
258             ? ( ${$_[1]}, 1 )
259             : ( $_[1] );
260            
261             if (ref $k eq 'Regexp') {
262             return
263             exists $self->{ESC2}{$k}
264             ? undef
265             : $type eq 'ex'
266             ? 1
267             : exists $self->{DYN2}{$k} && !$esc
268             ? $type eq 'sr'
269             ? \$self->{REGX2}{$k}($self, $k, @_[2..$#_])
270             : $self->{REGX2}{$k}($self, $k, @_[2..$#_])
271             : $type eq 'sr'
272             ? \$self->{REGX2}{$k}
273             : $self->{REGX2}{$k}
274             if exists $self->{REGX2}{$k};
275            
276             return undef;
277             }
278             };
279            
280             my $cach = $self->{CACH};
281            
282             my $first_element2;
283             ref ($first_element2 = $self->{REGX}[0]) eq 'HASH'
284             or $first_element2 = undef ;
285             foreach (CDUP || !$cach ? () : $cach, @{$self->{REGX}}) {
286             my $cach2 = $cach
287             if $_ ne $cach
288             and $_ ne $first_element2;
289            
290             if (ref $_ eq 'Regexp') {
291             next if $k !~ $_;
292            
293             if ( CHIT
294             and $self->{CHIT2}
295             ) {
296             CDUP
297             and ref $self->{REGX}[0] eq 'HASH'
298             || unshift @{$self->{REGX}}, {};
299            
300             return
301             exists $self->{ESC2}{$_}
302             ? subcall_match0()
303             : $type eq 'ex'
304             ? 1
305             : exists $self->{DYN2}{$_} && !$esc
306             ? $type eq 'sr'
307             ? \(subcall_match2()->($self, $k, @_[2..$#_]))
308             : subcall_match2()->($self, $k, @_[2..$#_])
309             : $type eq 'sr'
310             ? \(subcall_match2())
311             : subcall_match2();
312             }
313             else {
314             return
315             exists $self->{ESC2}{$_}
316             ? undef
317             : $type eq 'ex'
318             ? 1
319             : exists $self->{DYN2}{$_} && !$esc
320             ? $type eq 'sr'
321             ? \$self->{REGX2}{ $_}($self, $k, @_[2..$#_])
322             : $self->{REGX2}{ $_}($self, $k, @_[2..$#_])
323             : $type eq 'sr'
324             ? \$self->{REGX2}{ $_}
325             : $self->{REGX2}{ $_};
326             }
327             }
328             else {
329             next if !exists $_->{$k};
330            
331             if ( CHIT
332             and $self->{CHIT2}
333             ) {
334             CDUP
335             and ref $self->{REGX}[0] eq 'HASH'
336             || unshift @{$self->{REGX}}, {};
337            
338             return
339             exists $self->{ESC}{$k}
340             ? subcall_fetch0()
341             : $type eq 'ex'
342             ? 1
343             : exists $self->{DYN}{$k} && !$esc
344             ? $type eq 'sr'
345             ? \(subcall_fetch2()->($self, $k, @_[2..$#_]))
346             : subcall_fetch2()->($self, $k, @_[2..$#_])
347             : $type eq 'sr'
348             ? \(subcall_fetch2())
349             : subcall_fetch2();
350             }
351             else {
352             return
353             exists $self->{ESC}{$k}
354             ? undef
355             : $type eq 'ex'
356             ? 1
357             : exists $self->{DYN}{$k} && !$esc
358             ? $type eq 'sr'
359             ? \(subcall_fetch()->($self, $k, @_[2..$#_]))
360             : subcall_fetch()->($self, $k, @_[2..$#_])
361             : $type eq 'sr'
362             ? \subcall_fetch()
363             : subcall_fetch();
364            
365             }
366             }
367             }
368            
369             !CDUP
370             ? ( $cach
371             and $self->{ESC}{$k} = 1
372             and $cach->{$k} = undef )
373             : ( ref $self->{REGX}[0] eq 'HASH'
374             ? $self->{REGX}[0]{$k} = undef
375             : unshift(@{$self->{REGX}}, {$k => undef})
376             , $self->{ESC}{$k} = 1 )
377             if CMIS
378             and $self->{CMIS2}
379             and $self->{CMIS2} < @{$self->{REGX}};
380            
381             return undef
382             }
383             SUBCODE
384            
385             $AD{_examine} = <<'SUBCODE';
386             sub _examine {
387             my $self = $_[0];
388            
389             my $element;
390             while (1) {
391             last
392             unless
393             exists $self->{ESC2}{$element =
394             $self->{REGX}[-1]};
395            
396             pop @{$self->{REGX}};
397             delete $self->{REGX2}{ $element};
398             delete $self->{ESC2}{$element};
399             delete $self->{DYN2}{$element};
400             }
401             }
402             SUBCODE
403            
404             $AD{exists} = <<'SUBCODE';
405             sub exists {
406             $_[2] = 'ex';
407             goto &FETCH
408             }
409             SUBCODE
410            
411             $AD{delete} = <<'SUBCODE';
412             sub delete {
413             my ($k, $esc, $dyn);
414            
415             !ref $_[1] ? $k = $_[1]
416             : do{
417             ($k, $esc, $dyn)
418             = (ref $_[1] eq 'REF'
419             or ref $_[1] eq 'SCALAR')
420             ? ref $_[2] eq 'CODE'
421             ? ( ${$_[1]}, undef, 1 )
422             : ( ${$_[1]}, 1 )
423             : ( $_[1] );
424            
425             if (ref $k eq 'Regexp') {
426             return( ( $_[0]->FETCH( $k)
427             , $_[0]->STORE(\$k) )[0] )
428             }
429             };
430            
431             return undef
432             unless my $value = $_[0]->FETCH( $k, 'sr');
433             $value = $$value;
434             $_[0]->STORE(\$k);
435             return $value
436             }
437             SUBCODE
438            
439             $AD{normalize} = <<'SUBCODE';
440             sub normalize {
441             my $self = $_[0];
442            
443             my ($element, $element2);
444            
445             my $regx = \@{$self->{REGX}};
446             my $esc = \%{$self->{ESC}};
447             my $esc2 = \%{$self->{ESC2}};
448             my $regx2 = \%{$self->{REGX2}};
449            
450             my $rem_esc_2;
451             my $rem_all_2;
452             my $rem_2 = $self->{REMOD};
453             $rem_2 == 3
454             ? $rem_all_2 = 1
455             : $rem_2 == 2
456             ? $rem_esc_2 = 1
457             : $rem_2 && !($self)->SCALAR()
458             ? $rem_esc_2 = 1
459             : ();
460            
461             foreach $element2 (@$regx) {
462             next unless ref $element2 eq 'HASH';
463            
464             foreach my $k (keys %$element2) {
465             my $in_over;
466             if ($rem_all_2
467             or $rem_esc_2 and my $esc_key = $esc->{$k}
468             ) {
469             my $over_element2;
470             my $element2_k_is_2;
471             foreach $element (@$regx) {
472             $in_over
473             and ref $element eq 'HASH'
474             ? delete $element->{$k}
475             :( !defined $element2_k_is_2
476             and $over_element2
477             and exists $element2->{$k}
478             and $k =~ $element
479             and $element2_k_is_2
480             = $esc_key
481             ? exists $esc2->{$element} ? 1 : 0
482             : $element2->{$k} eq $regx2->{$element} )
483             , next;
484            
485             $over_element2 = 1 if $element eq $element2;
486            
487             $in_over = 1
488             if ref $element eq 'Regexp'
489             ? $k =~ $element
490             : $over_element2;
491             }
492            
493             !defined $element2_k_is_2
494             and $esc_key
495             and exists $element2->{$k}
496             and $element2_k_is_2 = 1;
497            
498             delete $element2->{$k}
499             if $element2_k_is_2;
500             }
501             else {
502             foreach $element (@$regx) {
503             $in_over
504             and ( ref $element eq 'HASH'
505             and delete $element->{$k} )
506             , next;
507            
508             $in_over = 1
509             if ref $element eq 'Regexp'
510             ? $k =~ $element
511             : $element eq $element2;
512             }
513             }
514            
515             }
516             }
517            
518             @$regx = (
519             { map ref $_ eq 'HASH' ? %$_ : (), @$regx },
520             ( map ref $_ ne 'HASH' ? $_ : (), @$regx ),
521             );
522            
523             _examine($self)
524             if @$regx > 1;
525            
526             $self->{IS_NORMALIZED} = 1;
527             }
528             SUBCODE
529            
530             $AD{firstkey} = <<'SUBCODE';
531             sub firstkey {
532             my $self = $_[0];
533            
534             ($self)->normalize unless $self->{IS_NORMALIZED};
535            
536             $self->{EACH} = [ 0, [reverse @{$self->{REGX}}] ];
537            
538             return( ($self)->NEXTKEY)
539             }
540             SUBCODE
541            
542             $AD{nextkey} = <<'SUBCODE';
543             sub nextkey {
544             my $self = $_[0];
545            
546             return( ($self)->firstkey)
547             if !$self->{EACH};
548            
549             NEXT: {
550            
551             delete $self->{EACH}
552             , return wantarray ? () : undef
553             if $#{$self->{EACH}[1]}
554             < $self->{EACH}[0];
555            
556             my $element = $self->{EACH}[1]->[$self->{EACH}[0]];
557            
558             if (ref $element eq 'Regexp') {
559             ++$self->{EACH}[0];
560            
561             return( ( exists $self->{DYN2}{$element}
562             || exists $self->{ESC2}{$element} ? \$element : $element
563             , wantarray ? $self->{REGX2}{ $element} : ()
564             )[0, wantarray ? 1 : ()] )
565             }
566             else {
567             my ($k, $value);
568             wantarray ? ($k, $value) = each %$element
569             : ($k = each %$element);
570            
571             ++$self->{EACH}[0]
572             , redo NEXT
573             if !defined $k;
574            
575             return( ( exists $self->{DYN}{$k}
576             || exists $self->{ESC}{$k} ? \$k : $k
577             , wantarray ? $value : ()
578             )[0, wantarray ? 1 : ()] )
579             }
580            
581             }
582            
583             }
584             SUBCODE
585            
586             $AD{keys} = <<'SUBCODE';
587             sub keys {
588             (my $self, my $as_arrayref) = @_;
589            
590             ($self)->normalize unless $self->{IS_NORMALIZED};
591            
592             my (@list, $count);
593            
594             if (wantarray or $as_arrayref) {
595             my $element;
596             foreach $element (reverse @{$self->{REGX}}) {
597             if (ref $element eq 'Regexp') {
598             push @list
599             , exists $self->{DYN2}{$element}
600             || exists $self->{ESC2}{$element} ? \$element : $element;
601             }
602             else {
603             push @list
604             , map exists $self->{DYN}{$_}
605             || exists $self->{ESC}{$_} ? \$_ : $_
606             , keys %$element;
607             }
608             }
609             }
610             else {
611             ref $_ eq 'Regexp' ? $count++ : ($count += keys %$_)
612             foreach @{$self->{REGX}};
613             }
614            
615             wantarray ? @list : $as_arrayref ? \@list : $count
616             }
617             SUBCODE
618            
619             $AD{values} = <<'SUBCODE';
620             sub values {
621             (my $self, my $as_arrayref) = @_;
622            
623             ($self)->normalize unless $self->{IS_NORMALIZED};
624            
625             my (@list, $count);
626            
627             if (wantarray or $as_arrayref) {
628             my $element;
629             foreach $element (reverse @{$self->{REGX}}) {
630             if (ref $element eq 'Regexp') {
631             push @list, $self->{REGX2}{$element};
632             }
633             else {
634             push @list, values %$element;
635             }
636             }
637             }
638             else {
639             ref $_ eq 'Regexp' ? $count++ : ($count += keys %$_)
640             foreach @{$self->{REGX}};
641             }
642            
643             wantarray ? @list : $as_arrayref ? \@list : $count
644             }
645             SUBCODE
646            
647             $AD{list} = <<'SUBCODE';
648             sub list {
649             my $as_arrayref = $_[1];
650            
651             my $ks = $_[0]->keys( 'as_arrayref');
652             my $values = $_[0]->values('as_arrayref');
653             my @list = map +($ks->[$_], $values->[$_]), 0..$#$ks;
654            
655             wantarray ? @list : $as_arrayref ? \@list : @list
656             }
657             SUBCODE
658            
659             $AD{scalar} = <<'SUBCODE';
660             sub scalar {
661             my $self = $_[0];
662            
663             return scalar %{$self->{REGX}[0]}
664             if @{$self->{REGX}} == 1
665             and ref $self->{REGX}[0] eq 'HASH'
666             and !%{$self->{ESC}};
667            
668             ref $_ eq 'Regexp'
669             and !exists $self->{ESC2}{$_}
670             and return 1
671             foreach @{$self->{REGX}};
672            
673             my $cach = $self->{CACH} if !CDUP;
674            
675             my ($element, $element2, $k);
676             foreach $element2 ($cach||(), @{$self->{REGX}}) {
677             next if ref $element2 eq 'Regexp';
678            
679             KEY: foreach $k (keys %$element2) {
680             next if exists $self->{ESC}{$k};
681            
682             foreach $element ($cach||(), @{$self->{REGX}}) {
683             $element eq $element2
684             and return 1;
685            
686             ref $element eq 'Regexp'
687             ? $k =~ $element
688             ? !exists $self->{ESC2}{$element}
689             ? return 1
690             : next KEY
691             : next
692             : exists $element->{$k}
693             ? !exists $self->{ESC}{$k}
694             ? return 1
695             : next KEY
696             : next;
697             }
698            
699             return 1
700             }
701             }
702            
703             return 0
704             }
705             SUBCODE
706            
707             $AD{clear} = <<'SUBCODE';
708             sub clear {
709             my $self = $_[0];
710            
711             @{$self->{REGX}} = ();
712             %{$self->{ESC}} = ();
713             %{$self->{DYN}} = ();
714             %{$self->{ESC2}} = ();
715             %{$self->{DYN2}} = ();
716             %{$self->{REGX2}} = ();
717             %{$self->{CACH}} = () if $self->{CACH};
718             }
719             SUBCODE
720            
721             sub DESTROY {
722 2     2   678 %{$_[0]} = ();
  2         63  
723             }
724            
725             *storable = \&freeze;
726             $AD{freeze} = <<'SUBCODE';
727             sub freeze {
728             my $what = $_[1];
729             my $selffreeze = ( $what =~ /self/i );
730             my $self = $selffreeze ? $_[0] : {%{$_[0]}};
731             if (!$selffreeze) {
732             $self->{REGX} = [@{$self->{REGX}}];
733             $self->{REGX2} = {%{$self->{REGX2}}};
734             $self->{ESC2} = {%{$self->{ESC2}}};
735             $self->{DYN2} = {%{$self->{DYN2}}};
736            
737             bless $self, ref($_[0])||$_[0]
738             if $what =~ /clone/i;
739             }
740            
741             my ($wraps_removed, $old);
742             ref $_ eq 'Regexp'
743             and $old = $_ , $_ = "$_"
744             #,( $wraps_removed = ($_ =~ s/(\(\?[a-z\-]+:)(?=\1)//g)
745             ,( $wraps_removed = ($_ =~ s/(\(\?(?:\^|[a-z\-]+):)(?=\1)//g) # perl 5.14 switches to (?^:) wrap
746             and $_ =~ s/\){$wraps_removed}$// )
747             ,( exists $self->{REGX2}{$old}
748             and $self->{REGX2}{$_}
749             = delete $self->{REGX2}{$old} )
750             ,( exists $self->{ESC2}{$old}
751             and $self->{ESC2}{$_}
752             = delete $self->{ESC2}{$old} )
753             ,( exists $self->{DYN2}{$old}
754             and $self->{DYN2}{$_}
755             = delete $self->{DYN2}{$old} )
756             foreach @{$self->{REGX}};
757            
758             return $self
759             }
760             SUBCODE
761            
762             *thaw = \&unfreeze;
763             *restore = \&unfreeze;
764             $AD{unfreeze} = <<'SUBCODE';
765             sub unfreeze {
766             my $do_not_bless = $_[2];
767             my $self = ref $_[1] ? $_[1] : ref $_[0] ? $_[0] : return undef;
768            
769             bless $self, ref($_[0])||$_[0]
770             unless $self =~ /=/
771             or $do_not_bless;
772            
773             my $old;
774             !ref $_
775             and $old = $_ , $_ = qr{$_}
776             ,( exists $self->{REGX2}{$old}
777             and $self->{REGX2}{$_}
778             = delete $self->{REGX2}{$old} )
779             ,( exists $self->{ESC2}{$old}
780             and $self->{ESC2}{$_}
781             = delete $self->{ESC2}{$old} )
782             ,( exists $self->{DYN2}{$old}
783             and $self->{DYN2}{$_}
784             = delete $self->{DYN2}{$old} )
785             foreach @{$self->{REGX}};
786            
787             return $self
788             }
789             SUBCODE
790            
791             $AD{STORABLE_freeze} = <<'SUBCODE';
792             sub STORABLE_freeze {
793             return (undef, $_[0]->freeze)
794             }
795             SUBCODE
796            
797             $AD{STORABLE_thaw} = <<'SUBCODE';
798             sub STORABLE_thaw {
799             my $self = $_[3];
800             $_[0]->unfreeze($self);
801             %{$_[0]} = %$self;
802             }
803             SUBCODE
804            
805             $AD{autodelete_limit} = <<'SUBCODE';
806             sub autodelete_limit {
807             my $self = $_[0];
808            
809             return $self->{DELIM} = $_[1] if @_ > 1;
810             return $self->{DELIM}
811             }
812             SUBCODE
813            
814             $AD{_offset2} = <<'SUBCODE';
815             sub _offset2 {
816             my $self = $_[0];
817            
818             return $self->{OFFSET2} = $_[1] if @_ > 1;
819             return $self->{OFFSET2}
820             }
821             SUBCODE
822            
823             $AD{do_cache} = <<'SUBCODE';
824             sub do_cache {
825             my $self = $_[0];
826            
827             return $self->{CACH} ||= ref $_[1] eq 'HASH' ? $_[1] : {} if $_[1];
828             return delete $self->{CACH}
829             }
830             SUBCODE
831            
832             $AD{do_cache_miss} = <<'SUBCODE';
833             sub do_cache_miss {
834             my $self = $_[0];
835            
836             return $self->{CMIS2} = $_[1] if @_ > 1;
837             return $self->{CMIS2}
838             }
839             SUBCODE
840            
841             $AD{do_cache_hit} = <<'SUBCODE';
842             sub do_cache_hit {
843             my $self = $_[0];
844            
845             return $self->{CHIT2} = $_[1] if @_ > 1;
846             return $self->{CHIT2}
847             }
848             SUBCODE
849            
850             $AD{flush_cache} = <<'SUBCODE';
851             sub flush_cache {
852             my $self = $_[0];
853            
854             %{ $self->{CACH}} = ()
855             if $self->{CACH};
856             }
857             SUBCODE
858            
859             $AD{remove_dups} = <<'SUBCODE';
860             sub remove_dups {
861             my $self = $_[0];
862            
863             return $self->{REMOD} = $_[1] if @_ > 1;
864             return $self->{REMOD}
865             }
866             SUBCODE
867            
868             $AD{die_on_stringref_bug} = $AD{stringref_bug_is_fixed} = <<'SUBCODE';
869             sub die_on_stringref_bug {
870             my $bugtxt = 'Due to bug (rt.perl.org ticket 79178) in your instance of perl, storing/fetching to/from the rehash should avoid escaped literal keys (as well as stringified scalarref keys), like $hash{\"foo"} (or in one statement: $regx2{$k = \"foo"}), or fatal error will result. The workaround: $k = \"foo"; $hash{$k}.';
871             #warn("BUG WARNING: $bugtxt");
872            
873             *FETCH2 = \&FETCH;
874             *STORE2 = \&STORE;
875            
876             my $qr_scalaref = qr{^SCALAR\(0x[\dabcdef]+\)$};
877             my $errmess = "Tie::REHash: Aborting due to Perl bug - escaped literal (or stringified scalarref) key has been used. $bugtxt";
878            
879             *FETCH = sub{
880             !ref $_[1]
881             and $_[1] =~ $qr_scalaref
882             and croak($errmess);
883            
884             goto &FETCH2;
885             };
886             *STORE = sub{
887             !ref $_[1]
888             and $_[1] =~ $qr_scalaref
889             and croak($errmess);
890            
891             goto &STORE2;
892             };
893             }
894            
895             sub stringref_bug_is_fixed {
896             *FETCH = \&FETCH2;
897             *STORE = \&STORE2;
898             }
899             SUBCODE
900            
901             $AD{precompile} = <<'SUBCODE';
902             sub precompile {
903             foreach (keys %AD) {
904             next
905             if $_ =~ $qr_fragment;
906             $AD{$_} =~ s/$qr_fragment/($AD{$1})/g;
907             eval $AD{$_};
908             !$@ or croak( "Compilation error: $@ in code: $AD{$_}")
909             }
910            
911             return 1
912             }
913             SUBCODE
914            
915             eval join '', map "sub $_;", keys %AD;
916            
917 0     0 0 0 sub is_precompiled { 0 }
918             $AD{is_precompiled} = <<'SUBCODE';
919             sub is_precompiled { 1 }
920             SUBCODE
921            
922             sub AUTOLOAD {
923             my $code = \( $AD{$Tie::REHash::AUTOLOAD}
924 14   50 14   557 || scalar( $Tie::REHash::AUTOLOAD =~ /::(\w+)$/, $AD{$1} ) );
925 14         23 eval{ $$code =~ s/$qr_fragment/($AD{$1})/g; };
  14         94  
926 14 100 33 5 1 2764 eval $$code;
  5 50 100 1 0 10  
  5 50 100 1 0 6  
  5 0 66 8 0 5  
  10 50 100 42 0 91  
  5 50 0 123 0 8  
  5 100 100 3 1 17  
  5 50 0 1 0 9  
  5 100 50 4 0 10  
  5 50 50 3 1 6  
  1 50 66 3 0 2  
  1 100 0 3 0 3  
  1 100 0 11   4  
  1 100 33 34   2  
  1 100 0     2  
  1 100 0     4  
  1 100 0     2  
  1 50 0     2  
  1 50 0     2  
  1 100 0     1  
  1 100 66     2  
  1 50 66     2  
  1 0 100     1  
  1 50 100     2  
  1 50 33     1  
  1 50 0     2  
  1 50 100     5  
  0 100 100     0  
  8 100 33     424  
  8 100 66     17  
  5 100 100     23  
  0 0 0     0  
  0 0 100     0  
  5 0 66     12  
  5 0 33     74  
  3 0       60  
  3 50       8  
  3 100       43  
  3 50       13  
  42 0       807  
  42 0       601  
  123 50       8323  
  123 50       166  
  123 50       151  
  123 50       234  
  47 50       171  
  17 50       51  
  47 50       93  
  36 100       273  
  1 100       17  
  87 100       122  
  87 100       97  
  87 0       215  
  87 0       140  
  87 0       179  
  141 0       470  
  141 0       253  
  54 0       249  
  48 0       117  
  48 0       55  
  48 0       317  
  0 50       0  
  0 100       0  
  0 100       0  
  0 50       0  
  0 50       0  
  87 50       199  
  30 50       45  
  30 100       32  
  30 0       212  
  0 0       0  
  0 50       0  
  0 50       0  
  0 50       0  
  0 50       0  
  0 50       0  
  0 0       0  
  0 50       0  
  0 50       0  
  0 50       0  
  0 50       0  
  0 50       0  
  0 100       0  
  9 0       23  
  9 0       24  
  9 0       32  
  3 50       36  
  3 50       35  
  3 0       4  
  3 0       9  
  3 0       32  
  1 50       3  
  1 50       4  
  0 50       0  
  1 50       2  
  1 100       10  
  4 0       443  
  2 0       4  
  2 0       6  
  0 0       0  
  0 0       0  
  0 0       0  
  2 0       4  
  2 0       9  
  2 0       9  
  2 0       4  
  2 0       5  
  2 100       5  
  2 100       4  
  2 100       4  
  2 50       6  
  2 50       5  
  2 100       6  
  3 0       7  
  3 0       7  
  3 0       3  
  6 0       7  
  6 0       27  
  3 0       5  
  3 0       6  
  0 100       0  
  0 100       0  
  3 100       5  
  3 100       6  
  3 100       10  
  0 100       0  
  3 50       5  
  3 100       5  
  3 100       4  
  3 100       5  
  3 100       4  
  3 50       4  
  3 100       3  
  3 100       5  
  3 100       3  
  3 50       5  
  3 100       5  
  3 50       5  
  3 0       48  
  3 0       9  
  7         14  
  2         3  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  3         24  
  3         35  
  3         42  
  3         6  
  3         8  
  3         7  
  11         39  
  11         14  
  3         13  
  11         36  
  3         8  
  8         11  
  8         57  
  6         10  
  6         8  
  6         16  
  6         11  
  14         28  
  4         9  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  6         58  
  34         1847  
  34         52  
  34         42  
  34         46  
  34         67  
  23         93  
  6         12  
  11         21  
  23         41  
  16         32  
  16         32  
  16         31  
  5         6  
  5         33  
  16         21  
  16         19  
  26         34  
  26         80  
  16         20  
  16         25  
  16         91  
  16         25  
  32         58  
  16         18  
  16         34  
  16         28  
  0         0  
  16         92  
  7         11  
  7         43  
  18         35  
  18         33  
  5         48  
  16         28  
  16         30  
  16         16  
  16         18  
  16         31  
  16         29  
  16         110  
  0         0  
  0         0  
  0         0  
  0         0  
927 14 50       51 !$@ or die("$@ evaluating $$code");
928            
929 14 50       359 goto &$Tie::REHash::AUTOLOAD
930             if defined &$Tie::REHash::AUTOLOAD;
931             }
932            
933             {
934             package Tie::REHash::StringrefBug;
935 2     2   106 sub TIEHASH { bless {}, $_[0] }
936 2     2   15 sub STORE { ref $_[1] }
937 4     4   18 sub FETCH { ref $_[1] }
938             }
939             tie my %detector, 'Tie::REHash::StringrefBug';
940             ( $detector{\'foo'} = 1 ) eq 'SCALAR'
941             and $detector{\'foo'} eq 'SCALAR'
942             #$] >= 5.012
943             or die_on_stringref_bug();
944            
945             1
946            
947             __END__