Data-Rmap

 view release on metacpan or  search on metacpan

lib/Data/Rmap.pm  view on Meta::CPAN

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;



( run in 2.072 seconds using v1.01-cache-2.11-cpan-13bb782fe5a )