This file is indexed.

/usr/share/perl5/Data/Rmap.pm is in libdata-rmap-perl 0.65-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
package Data::Rmap;
our $VERSION = 0.65;

=head1 NAME

Data::Rmap - recursive map, apply a block to a data structure

=head1 SYNOPSIS

 $ perl -MData::Rmap -e 'print rmap { $_ } 1, [2,3], \\4, "\n"'
 1234

 $ perl -MData::Rmap=:all
 rmap_all { print (ref($_) || "?") ,"\n" } \@array, \%hash, \*glob;

 # OUTPUT (Note: a GLOB always has a SCALAR, hence the last two items)
 # ARRAY
 # HASH
 # GLOB
 # SCALAR
 # ?


 # Upper-case your leaves in-place
 $array = [ "a", "b", "c" ];
 $hash  = { key => "a value" };
 rmap { $_ = uc $_; } $array, $hash;

 use Data::Dumper; $Data::Dumper::Terse=1; $Data::Dumper::Indent=0;
 print Dumper($array), " ", Dumper($hash), "\n";

 # OUTPUT
 # ['A','B','C'] {'key' => 'A VALUE'}


 # Simple array dumper.
 # Uses $self->recurse method to alter traversal order
 ($dump) = rmap_to {

    return "'$_'" unless ref($_); # scalars are quoted and returned

    my $self = shift;
    # use $self->recurse to grab results and wrap them
    return '[ ' . join(', ', $self->recurse() ) . ' ]';

  } ARRAY|VALUE,  [ 1, [ 2, [ [ 3 ], 4 ] ], 5 ];

 print "$dump\n";
 # OUTPUT
 # [ '1', [ '2', [ [ '3' ], '4' ] ], '5' ]


=head1 DESCRIPTION

 rmap BLOCK LIST

Recursively evaluate a BLOCK over a list of data structures
(locally setting $_ to each element) and return the list composed
of the results of such evaluations.  $_ can be used to modify
the elements.

Data::Rmap currently traverses HASH, ARRAY, SCALAR and GLOB reference
types and ignores others.  Depending on which rmap_* wrapper is used,
the BLOCK is called for only scalar values, arrays, hashes, references,
all elements or a customizable combination.

The list of data structures is traversed pre-order in a depth-first fashion.
That is, the BLOCK is called for the container reference before is it called
for it's elements (although see "recurse" below for post-order).
The values of a hash are traversed in the usual "values" order which
may affect some applications.

If the "cut" subroutine is called in the BLOCK then the traversal
stops for that branch, say if you "cut" an array then the code is
never called for it's elements (or their sub-elements).
To simultaneously return values and cut, simply pass the return list
to cut:  C<cut('add','to','returned');>

The first parameter to the BLOCK is an object which maintains the
state of the traversal.  Methods available on this object are
described in L<State Object> below.

=head1 EXPORTS

By default:

 rmap, rmap_all, cut

Optionally:

 rmap_scalar rmap_hash rmap_array rmap_code rmap_ref rmap_to
 :types => [ qw(NONE VALUE HASH ARRAY SCALAR REF CODE ALL) ],
 :all => ... # everything

=head1 Functions

The various names are just wrappers which select when to call
the code BLOCK.  rmap_all always calls it, the others are more
selective while rmap_to takes an extra parameter permitting you
to provide selection criteria.  Furthermore, you can always
just rmap_all and skip nodes which are not of interest.

=over 4

=item rmap_to { ... } $want, @data_structures;

Most general first.

Recurse the @data_structures and apply the BLOCK to
elements selected by $want.  The $want parameter is the
bitwise "or" of whatever types you choose (imported with :types):

 VALUE  - non-reference scalar, eg. 1
 HASH   - hash reference
 ARRAY  - array reference
 SCALAR - scalar reference, eg. \1
 REF    - higher-level reference, eg. \\1, \\{}
          B<NOT> any reference type, see <Scalar::Util>'s reftype:
          perl -MScalar::Util=reftype -le 'print map reftype($_), \1, \\1'
 GLOB   - glob reference, eg. \*x
          (scalar, hash and array recursed, code too as of 0.63)
 ALL    - all of the above (not CODE)
 CODE   - code references (as of 0.63)
 NONE   - none of the above

So to call the block for arrays and scalar values do:

 use Data::Rmap ':all';         # or qw(:types rmap_to)
 rmap { ... } ARRAY|VALUE, @data_structures;

(ALL | CODE) and (ALL & !GLOB) might also be handy.

The remainder of the wrappers are given in terms of the $want for rmap_to.

=item rmap { ... } @list;

Recurse and call the BLOCK on non-reference scalar values.  $want = VALUE

=item rmap_all BLOCK LIST

Recurse and call the BLOCK on everything.  $want = ALL

=item rmap_scalar { ... }  @list

Recurse and call the BLOCK on non-collection scalars.
$want = VALUE|SCALAR|REF

=item rmap_hash

Recurse and call the BLOCK on hash refs.  $want = HASH

=item rmap_array

Recurse and call the BLOCK on array refs.  $want = ARRAY

=item rmap_code

Recurse and call the BLOCK on code refs.  $want = CODE

=item rmap_ref

Recurse and call the BLOCK on all "normal" references:
$want = HASH|ARRAY|SCALAR|REF

Note: rmap_ref isn't the same as rmap_to {} REF

=item cut(@list)

Don't traverse sub-elements and return the @list immediately.
For example, if $_ is an ARRAY reference, then the array's elements
are not traversed.

If there's two paths to an element, both will need to be cut.

=back

=head1 State Object

The first parameter to the BLOCK is an object which maintains
most of the traversal state (except current node, which is $_).
I<You will ignore it most of the time>.
The "recurse" method may be useful.
Other methods should only be used in throw away tools, see L<TODO>

Methods:

=over 4

=item recurse

Process child nodes of $_ now and return the result.

This makes it easier to perform post-order and in-order
processing of a structure.  Note that since the same "seen list"
is used, the child nodes aren't reprocessed.

=item code

The code reference of the BLOCK itself.  Possible useful in
some situations.

=item seen

Reference to the HASH used to track where we have visited.
You may want to modify it in some situations (though I haven't yet).
Beware circular references.  The (current) convention used for the key
is in the source.

=item want

The $want state described in L<rmap_to>.

=back

=head1 EXAMPLES

 # command-line play
 $ perl -MData::Rmap -le 'print join ":", rmap { $_ } 1,2,[3..5],\\6'
 1:2:3:4:5:6


 # Linearly number questions on a set of pages
 my $qnum = 1;
 rmap_hash {
     $_->{qnum} = $qnum++ if($_->{qn});
 } @pages;


 # Grep recursively, finding ALL objects
 use Scalar::Util qw(blessed);
 my @objects = rmap_ref {
     blessed($_) ? $_ : ();
 } $data_structure;


 # Grep recursively, finding public objects (note the cut)
 use Scalar::Util qw(blessed);
 my @objects = rmap_ref {
     blessed($_) ?  cut($_) : ();
 } $data_structure;


 # Return a modified structure
 # (result flattening means we must cheat by cloning then modifying)
 use Storable qw(dclone);
 use Lingua::EN::Numbers::Easy;

 $words = [ 1, \2, { key => 3 } ];
 $nums = dclone $words;
 rmap { $_ = $N{$_} || $_ } $nums;


 # Make an assertion about a structure
 use Data::Dump;
 rmap_ref {
    blessed($_) && $_->isa('Question') && defined($_->name)
        or die "Question doesn't have a name:", dump($_);
 } @pages;


 # Traverse a tree using localize state
 $tree = [
     one =>
     two =>
     [
         three_one =>
         three_two =>
         [
             three_three_one =>
         ],
         three_four =>
     ],
     four =>
     [
         [
             five_one_one =>
         ],
     ],
 ];

 @path = ('q');
 rmap_to {
     if(ref $_) {
         local(@path) = (@path, 1); # ARRAY adds a new level to the path
         $_[0]->recurse(); # does stuff within local(@path)'s scope
     } else {
         print join('.', @path), " = $_ \n"; # show the scalar's path
     }
     $path[-1]++; # bump last element (even when it was an aref)
 } ARRAY|VALUE, $tree;

 # OUTPUT
 # q.1 = one
 # q.2 = two
 # q.3.1 = three_one
 # q.3.2 = three_two
 # q.3.3.1 = three_three_one
 # q.3.4 = three_four
 # q.4 = four
 # q.5.1.1 = five_one_one

 # replace CODE with "<CODE>"
 $ perl -MData::Rmap=:all -E 'say join ":", rmap_code { "<CODE>" } sub{},sub{}'
 <CODE>:<CODE>

 # look inside code refs with PadWalker
 $ perl -MData::Rmap=:all -MSub::Identify=:all -MPadWalker=:all -MSub::Name
   use 5.10.0;
   my $s = sub {}; sub A::a { $s };
   say join ", ",
    rmap_code {
        sub_fullname($_),                       # name string
        map { $_[0]->recurse } closed_over($_)  # then recurse the sub innards
    } \*A::a, subname b => sub { $s };
   # A::a, main::__ANON__, main::b

=head1 Troubleshooting

Beware comma after block:

 rmap { print }, 1..3;
               ^-------- bad news, you get an empty list:
 rmap(sub { print $_; }), 1..3;

If you don't import a function, perl's confusion may produce:

 $ perl -MData::Rmap -le 'rmap_scalar { print } 1'
 Can't call method "rmap_scalar" without a package or object reference...

 $ perl -MData::Rmap -le 'rmap_scalar { $_++ } 1'
 Can't call method "rmap_scalar" without a package or object reference...

If there's two paths to an element, both will need to be cut.

If there's two paths to an element, one will be taken randomly when
there is an intervening hash.

Autovivification can lead to "Deep recursion" warnings if you test
C<< exists $_->{this}{that} >> instead of
C<< exists $_->{this} && exists $_->{this}{that} >>
as you may follow a long chain of "this"s
Alternatively use the "no autovivification" pragma to avoid this problem.

=head1 TODO

put for @_ in wrapper to allow parameters in a different wrapper,
solve localizing problem.

Store custom localized data about the traversal.
Seems too difficult and ugly when compare to doing it at the call site.
Should support multiple reentrancy so avoid the symbol table.

C<rmap_args { } $data_structure, @args> form to pass parameters.
Could potentially help localizing needs.  (Maybe only recurse last item)

Benchmark.  Use array based object and/or direct access internally.

Think about permitting different callback for different types.
The prototype syntax is a bit too flaky....

Ensure that no memory leaks are possible, leaking the closure.

=head1 SEE ALSO

map, grep, L<Storable>'s dclone, L<Scalar::Util>'s reftype and blessed

Faint traces of treemap:

 http://www.perlmonks.org/index.pl?node_id=60829

Update: various alternatives have appear over the years,
L<Data::Visitor> has a list.

=head1 AUTHOR

Brad Bowman E<lt>rmap@bereft.netE<gt>

=head1 LICENCE AND COPYRIGHT

Copyright (c) 2004- Brad Bowman (E<lt>rmap@bereft.netE<gt>).
All rights reserved.

This module is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See L<perlartistic> and L<perlgpl>.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

=cut

# Early design discussion:
# http://www.perlmonks.org/index.pl?node_id=295642
# wantarray
# http://www.class-dbi.com/cgi-bin/wiki/index.cgi?AtomicUpdates

use warnings;
use strict;
use Carp qw(croak);
use Scalar::Util qw(blessed refaddr reftype);

require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(rmap rmap_all cut);
our %EXPORT_TAGS = (
    types => [ qw(NONE VALUE HASH ARRAY SCALAR REF GLOB CODE ALL) ],
);
our @EXPORT_OK = ( qw(rmap_scalar rmap_hash rmap_array rmap_code rmap_ref rmap_to),
                @{ $EXPORT_TAGS{types} } );

$EXPORT_TAGS{all} = [ @EXPORT, @EXPORT_OK ];


# Uses stringifying instead of S::U::ref* b/c it's under control
my $cut = \do { my $thing }; # my = out of symbol table
sub cut {
    die $cut = [@_]; # cut can return
}

sub NONE()   { 0 }
sub VALUE()  { 1 }
sub HASH()   { 2 }
sub ARRAY()  { 4 }
sub SCALAR() { 8 }
sub REF()    { 16 }
sub GLOB()   { 32 }
sub CODE()   { 64 }
sub ALL()    { VALUE|HASH|ARRAY|SCALAR|REF|GLOB }
# Others like CODE, Regex, etc are ignored

my %type_bits = (
    HASH => HASH,
    ARRAY => ARRAY,
    SCALAR => SCALAR,
    REF => REF,
    GLOB => GLOB,
    CODE => CODE,
    # reftype actually returns undef for:
    VALUE => VALUE,
);

sub new {
    bless { code => $_[1], want => $_[2], seen => $_[3] }, $_[0];
}
sub code { $_[0]->{code} }
sub want { $_[0]->{want} }
sub seen { $_[0]->{seen} }
sub call { $_[0]->{code}->($_[0]) }

sub recurse {
    # needs to deref $_ and *then* run the code, enter _recurse directly
    $_[0]->_recurse(); # cut not needed as seen remembers
}

sub rmap (&@) {
    __PACKAGE__->new(shift, VALUE, {})->_rmap(@_);
}

sub rmap_all (&@) {
    __PACKAGE__->new(shift, ALL, {})->_rmap(@_);
}

sub rmap_scalar (&@) {
    __PACKAGE__->new(shift, VALUE|SCALAR|REF, {})->_rmap(@_);
}

sub rmap_hash (&@) {
    __PACKAGE__->new(shift, HASH, {})->_rmap(@_);
}

sub rmap_array (&@) {
    __PACKAGE__->new(shift, ARRAY, {})->_rmap(@_);
}

sub rmap_code (&@) {
    __PACKAGE__->new(shift, CODE, {})->_rmap(@_);
}

sub rmap_ref (&@) {
    __PACKAGE__->new(shift, HASH|ARRAY|SCALAR|REF, {})->_rmap(@_);
}

sub rmap_to (&@) {
    __PACKAGE__->new(shift, shift, {})->_rmap(@_);
}

sub _rmap {
    my $self = shift;
    my @return;

    for (@_) { # just one after the wrapper call
        my ($key, $type);

        if($type = reftype($_)) {
            $key = refaddr $_;
            $type = $type_bits{$type} or next;
        } else {
            $key = "V:".refaddr(\$_); # prefix to distinguish from \$_
            $type = VALUE;
        }

        next if ( exists $self->seen->{$key} );
        $self->seen->{$key} = undef;

        # Call the $code
        if($self->want & $type) {
            my $e; # local($@) and rethrow caused problems
            my @got;
            {
                local ($@); # don't trample, cut impl. should be transparent
                # call in array context.  pass block for reentrancy
                @got = eval { $self->call() };
                $e = $@;
            }

            if($e) {
                if(ref($e) && $e == $cut) {
                    push @return, @$cut; # cut can add to return list
                    next; # they're cutting, don't recurse
                } else {
                    die $e;
                }
            }
            push @return, @got;
        }

        push @return, $self->_recurse(); # process $_ node
    }
    return @return;
}

sub _recurse {
    my $self = shift;
    my $type = $type_bits{reftype($_) || 'VALUE'} or return;
    my @return;

    # Recurse appropriately, keeping $_ alias
    if ($type & HASH) {
        push @return, $self->_rmap($_) for values %$_;
    } elsif ($type & ARRAY) {
        # Does this change cut behaviour? No, cut is one scalar ref
        #push @return, _rmap($code, $want, $seen, $_) for @$_;
        push @return, $self->_rmap(@$_);
    } elsif ($type & (SCALAR|REF) ) {
        push @return, $self->_rmap($$_);
    } elsif ($type & GLOB) {
        # SCALAR is always there, undef may be unused or set to undef
        push @return, $self->_rmap(*$_{SCALAR});
        defined *$_{ARRAY} and
            push @return, $self->_rmap(*$_{ARRAY});
        defined *$_{HASH} and
            push @return, $self->_rmap(*$_{HASH});
        defined *$_{CODE} and
            push @return, $self->_rmap(*$_{CODE});
        # Is it always: *f{GLOB} == \*f ?
        # Also PACKAGE NAME GLOB
    }
    return @return;
}

1;