NAME
CXC::Data::Visitor - Invoke a callback on every element at every level of a data structure.
VERSION
version 0.08
SYNOPSIS
use CXC::Data::Visitor 'visit', 'RESULT_CONTINUE';
my $hoh = { fruit => { berry => 'purple' }, };
visit(
$hoh,
sub {
my ( $key, $vref ) = @_;
$$vref = 'blue' if $key eq 'berry';
return RESULT_CONTINUE;
} );
say $hoh->{fruit}{berry} # 'blue'
DESCRIPTION
CXC::Data::Visitor provides a means of performing a depth first traversal of a data structure. There are similar modules on CPAN ("SEE ALSO"); this module provides a few extras.
Hashes are traversed in sorted key order. By default the order is that provided by Perl's standard string sort order. The caller may provide a coderef to provide an alternative sort order ("sort_keys").
The callback is invoked first on a container and then its elements. Given
{ a => { b => [ 0 ], c => 2 } }
the callback order is
{a}, {a}{b}, {a}{b}[0], {a}{c}
Blessed hashes or arrays are treated as terminal elements and are not further traversed.
Cycles are detected upon traversing a container a second time in a depth first search, and the resultant action is caller selectable.
Containers that can be reached multiple times without cycling, e.g.
%hash = ( a => { b => 1 }, ); $hash{c} = $hash{a};
are visited once per parent, e.g.
{a}, {a}{b}, {a}{b}[0] {c}, {c}{b}, {c}{b}[0]
A container (hash or array) may be optionally be immediately revisited.
An element whose value is a container may be optionally be revisited after the container is visited.
The traversal may be aborted.
The complete path from the structure route to an element (both the ancestor containers and the keys and indexes required to traverse the path) is available.
SUBROUTINES
visit
( $completed, $context, $metadata ) = visit( $struct, $callback, %opts );
Perform a depth-first traversal of $struct, invoking $callback on containers (hashes and arrays) and terminal elements in $struct.
$struct
is the data structure to traverse, $callback
is a coderef to be applied to specified members of the structure (see the "visit" option), and %opts
controls optional behavior.
$callback will be called as:
$handle_return = $callback->( $kydx, $vref, $context, \%metadata );
"$callback" is passed
- $kydx
-
the key or index into the visited element's parent container.
- $vref
-
a reference to the value of the element being visited. Use $$vref to extract or modify the value.
- $context
- $metadata
-
A hash of state information kept by CXC::Data::Visitor, but which may be of interest to the callback:
- container
-
a reference to the hash or array which contains the element being visited.
- path
-
An array which contains the path (keys and indices) used to arrive at the current element from $struct.
- ancestors
-
An array contains the ancestor containers of the current element.
- pass
-
A constant indicating the current visit pass through an element.
%opts may contain the following entries:
- context
-
Arbitrary data to be passed to "$callback" via the
$context
argument. Use it for whatever you'd like. If not specified, it defaults to a freshly created hash. - cycle => CYCLE_TRUNCATE | CYCLE_DIE | CYCLE_CONTINUE | <$coderef>
-
How to handle cycles in the data structure.
See "EXPORTS" to import the constant values.
- CYCLE_DIE
-
Throw an exception (the default).
- CYCLE_CONTINUE
-
Pretend we haven't seen it before. Will cause stack exhaustion if $callback does handle this.
- CYCLE_TRUNCATE
-
Truncate before entering the cycle a second time.
- $coderef
-
Examine the situation and request a particular resolution. $coderef is called as
$coderef->( $container, $context, $metadata );
where $container is the hash or array which has already been traversed. See below for "$context" and "$metadata".
$coderef should return one of CYCLE_DIE, CYCLE_CONTINUE, or CYCLE_TRUNCATE, indicating what should be done.
- visit => VISIT_HASH | VISIT_ARRAY | VISIT_CONTAINER | VISIT_LEAF | VISIT_ALL
-
The parts of the structure that will trigger a callback. See "EXPORTS" to import the constants.
- VISIT_CONTAINER
-
Invoke "$callback" on containers (either hashes or arrays). For example, the elements in the following structure
$struct = { a => { b => 1, c => [ 2, 3 ] } }
passed to "$callback" are:
a => {...} # $struct->{a} c => [...] # $struct->{c}
- VISIT_ARRAY
- VISIT_HASH
-
Only visit containers of the given type.
- VISIT_LEAF
-
Invoke "$callback" on terminal (leaf) elements. For example, the elements in the following structure
$struct = { a => { b => 1, c => [ 2, 3 ] } }
passed to "$callback" are:
b => 1 # $struct->{a}{b} 0 => 2 # $struct->{a}{c}[0] 1 => 3 # $struct->{a}{c}[1]
- VISIT_ALL
-
Invoke "$callback" on all elements. This is the default.
- sort_keys => coderef
-
An optional coderef which implements a caller specific sort order. It is passed two keys as arguments. It should return
-1
,0
, or1
indicating that the sort order of the first argument is less than, equal to, or greater than that of the second argument. - revisit_limit
-
If "$callback" returns RESULT_REVISIT_CONTAINER the element's parent container is re-scanned for its elements and revisited. To avoid an inadvertent infinite loop, an exception is thrown if the parent container is revisited more than this number of times. It defaults to 10; Set it to
0
to indicate no limit.
$callback
should return one of the following constants (see "EXPORTS"):
- RESULT_CONTINUE
-
The process of visiting elements should continue.
- RESULT_RETURN
-
"visit" should return immediately to the caller.
- RESULT_STOP_DESCENT
-
If the current element is a container, do not visit the container's contents (containers are visited before their contents).
For leaf elements, this is equivalent to "RESULT_CONTINUE".
- RESULT_REVISIT_CONTAINER
-
Further processing of the elements in the current container should stop and the container should be revisited. This allows "$callback" to modify the container and have it reprocessed.
To avoid inadvertent infinite loops, a finite number of revisits is allowed during a traversal of a container (see "revisit_limit"). Containers with multiple parents are traversed once per parent; The limit is reset for each traversal.
- RESULT_REVISIT_ELEMENT
-
If the value of this element is a container, it should be revisited (by calling "$callback") after its value is visited. This allows post-processing results when travelling back up the structure.
During the initial visit
$metadataa->{pass} & PASS_VISIT_ELEMENT
will be true. During the followup visit
$metadata->{pass} & PASS_REVISIT_ELEMENT
will be true and "$callback" may only return values of RESULT_RETURN and RESULT_CONTINUE; any other values will cause an exception.
The ordered contents of the $metadata{path} array uniquely identify an element, so may be used to track elements using external data structures. Do not depend upon reference addresses remaining constant.
"visit" returns the following:
- $completed => Boolean
-
true if all elements were visited, false if $callback requested a premature return.
- $context
-
The variable of the same name passed to $callback; see the "context" option.
- $metadata => hash
-
collected metadata. See "$metadata".
EXPORTS
This module uses Exporter::Tiny, which provides enhanced import utilities.
The following symbols may be exported:
visit
VISIT_CONTAINER VISIT_LEAF VISIT_ALL
CYCLE_DIE CYCLE_CONTINUE CYCLE_TRUNCATE
RESULT_RETURN RESULT_CONTINUE
RESULT_REVISIT_CONTAINER RESULT_REVISIT_ELEMENT
RESULT_STOP_DESCENT
PASS_VISIT_ELEMENT PASS_REVISIT_ELEMENT
The available tags and their respective imported symbols are:
- all
-
Import all symbols.
- results
-
RESULT_RETURN RESULT_CONTINUE RESULT_REVISIT_CONTAINER RESULT_REVISIT_ELEMENT RESULT_STOP_DESCENT
- cycles
-
CYCLE_DIE CYCLE_CONTINUE CYCLE_TRUNCATE
- visits
-
VISIT_CONTAINER VISIT_LEAF VISIT_ALL
- passes
-
PASS_VISIT_ELEMENT PASS_REVISIT_ELEMENT
- constants
-
Import tags
results
,cycles
,visits
.
SUPPORT
Bugs
Please report any bugs or feature requests to bug-cxc-data-visitor@rt.cpan.org or through the web interface at: https://rt.cpan.org/Public/Dist/Display.html?Name=CXC-Data-Visitor
Source
Source is available at
https://gitlab.com/djerius/cxc-data-visitor
and may be cloned from
https://gitlab.com/djerius/cxc-data-visitor.git
SEE ALSO
Please see those modules/websites for more information related to this module.
AUTHOR
Diab Jerius <djerius@cpan.org>
COPYRIGHT AND LICENSE
This software is Copyright (c) 2024 by Smithsonian Astrophysical Observatory.
This is free software, licensed under:
The GNU General Public License, Version 3, June 2007