| Filename | /home/ss5/local/projects/data-dpath/lib/Data/DPath/Context.pm |
| Statements | Executed 1716 statements in 6.26ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 3.41ms | 9.17ms | Data::DPath::Context::BEGIN@16.8 |
| 1 | 1 | 1 | 2.54ms | 15.3ms | Data::DPath::Context::BEGIN@17 |
| 1 | 1 | 1 | 1.56ms | 13.4ms | Data::DPath::Context::BEGIN@13 |
| 30 | 2 | 1 | 1.53ms | 1.66ms | Data::DPath::Context::_any (recurses: max depth 11, inclusive time 9.11ms) |
| 1 | 1 | 1 | 603µs | 871µs | Data::DPath::Context::BEGIN@12 |
| 8 | 1 | 1 | 508µs | 2.18ms | Data::DPath::Context::_select_key |
| 1 | 1 | 1 | 506µs | 2.71ms | Data::DPath::Context::BEGIN@10 |
| 4 | 1 | 1 | 223µs | 4.26ms | Data::DPath::Context::_search |
| 46 | 4 | 1 | 156µs | 1.68ms | Data::DPath::Context::_filter_points |
| 4 | 1 | 1 | 72µs | 1.75ms | Data::DPath::Context::_select_anywhere |
| 4 | 1 | 1 | 51µs | 76µs | Data::DPath::Context::_all |
| 4 | 1 | 1 | 51µs | 64µs | Data::DPath::Context::_select_parent |
| 2 | 1 | 1 | 48µs | 1.49ms | Data::DPath::Context::_filter_points_eval |
| 4 | 1 | 1 | 33µs | 4.37ms | Data::DPath::Context::match |
| 4 | 1 | 1 | 25µs | 42µs | Data::DPath::Context::_select_root |
| 1 | 1 | 1 | 17µs | 830µs | Data::DPath::Context::BEGIN@23 |
| 1 | 1 | 1 | 16µs | 44µs | Data::DPath::Context::BEGIN@11 |
| 1 | 1 | 1 | 16µs | 102µs | Data::DPath::Context::BEGIN@14 |
| 1 | 1 | 1 | 16µs | 30µs | Data::DPath::Context::BEGIN@4 |
| 1 | 1 | 1 | 16µs | 190µs | Data::DPath::Context::BEGIN@52 |
| 1 | 1 | 1 | 15µs | 26µs | Data::DPath::Filters::BEGIN@194 |
| 1 | 1 | 1 | 15µs | 170µs | Data::DPath::Context::BEGIN@45 |
| 1 | 1 | 1 | 14µs | 31µs | Data::DPath::Context::BEGIN@92 |
| 2 | 1 | 1 | 14µs | 14µs | Data::DPath::Context::CORE:subst (opcode) |
| 1 | 1 | 1 | 13µs | 26µs | Data::DPath::Context::BEGIN@414 |
| 1 | 1 | 1 | 12µs | 23µs | Data::DPath::Context::BEGIN@271 |
| 1 | 1 | 1 | 11µs | 21µs | Data::DPath::Context::BEGIN@295 |
| 1 | 1 | 1 | 11µs | 24µs | Data::DPath::Context::BEGIN@148 |
| 1 | 1 | 1 | 10µs | 21µs | Data::DPath::Context::BEGIN@415 |
| 1 | 1 | 1 | 10µs | 20µs | Data::DPath::Context::BEGIN@149 |
| 1 | 1 | 1 | 10µs | 20µs | Data::DPath::Context::BEGIN@213 |
| 1 | 1 | 1 | 9µs | 14µs | Data::DPath::Context::BEGIN@5 |
| 1 | 1 | 1 | 9µs | 22µs | Data::DPath::Context::BEGIN@212 |
| 1 | 1 | 1 | 9µs | 37µs | Data::DPath::Context::BEGIN@7 |
| 1 | 1 | 1 | 9µs | 403µs | Data::DPath::Context::BEGIN@9 |
| 4 | 1 | 1 | 9µs | 9µs | Data::DPath::Context::CORE:substcont (opcode) |
| 1 | 1 | 1 | 8µs | 106µs | Data::DPath::Context::BEGIN@8 |
| 4 | 1 | 1 | 8µs | 8µs | Data::DPath::Context::CORE:match (opcode) |
| 1 | 1 | 1 | 5µs | 5µs | Data::DPath::Context::new (xsub) |
| 4 | 4 | 2 | 3µs | 3µs | Data::DPath::Context::current_points (xsub) |
| 2 | 2 | 2 | 1µs | 1µs | Data::DPath::Context::give_references (xsub) |
| 0 | 0 | 0 | 0s | 0s | Data::DPath::Context::__ANON__[lib/Data/DPath/Context.pm:401] |
| 0 | 0 | 0 | 0s | 0s | Data::DPath::Context::_filter_points_index |
| 0 | 0 | 0 | 0s | 0s | Data::DPath::Context::_iter |
| 0 | 0 | 0 | 0s | 0s | Data::DPath::Context::_select_ancestor |
| 0 | 0 | 0 | 0s | 0s | Data::DPath::Context::_select_ancestor_or_self |
| 0 | 0 | 0 | 0s | 0s | Data::DPath::Context::_select_anystep |
| 0 | 0 | 0 | 0s | 0s | Data::DPath::Context::_select_nostep |
| 0 | 0 | 0 | 0s | 0s | Data::DPath::Context::_splice_threads |
| 0 | 0 | 0 | 0s | 0s | Data::DPath::Context::all_points |
| 0 | 0 | 0 | 0s | 0s | Data::DPath::Context::deref |
| 0 | 0 | 0 | 0s | 0s | Data::DPath::Context::first_point |
| 0 | 0 | 0 | 0s | 0s | Data::DPath::Context::isearch |
| 0 | 0 | 0 | 0s | 0s | Data::DPath::Context::ref |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package Data::DPath::Context; | ||||
| 2 | # ABSTRACT: Abstraction for a current context that enables incremental searches | ||||
| 3 | |||||
| 4 | 2 | 26µs | 2 | 44µs | # spent 30µs (16+14) within Data::DPath::Context::BEGIN@4 which was called:
# once (16µs+14µs) by Data::DPath::Path::BEGIN@1.6 at line 4 # spent 30µs making 1 call to Data::DPath::Context::BEGIN@4
# spent 14µs making 1 call to strict::import |
| 5 | 2 | 24µs | 2 | 19µs | # spent 14µs (9+5) within Data::DPath::Context::BEGIN@5 which was called:
# once (9µs+5µs) by Data::DPath::Path::BEGIN@1.6 at line 5 # spent 14µs making 1 call to Data::DPath::Context::BEGIN@5
# spent 5µs making 1 call to warnings::import |
| 6 | |||||
| 7 | 2 | 26µs | 2 | 65µs | # spent 37µs (9+28) within Data::DPath::Context::BEGIN@7 which was called:
# once (9µs+28µs) by Data::DPath::Path::BEGIN@1.6 at line 7 # spent 37µs making 1 call to Data::DPath::Context::BEGIN@7
# spent 28µs making 1 call to Exporter::import |
| 8 | 2 | 29µs | 2 | 106µs | # spent 106µs (8+97) within Data::DPath::Context::BEGIN@8 which was called:
# once (8µs+97µs) by Data::DPath::Path::BEGIN@1.6 at line 8 # spent 106µs making 1 call to Data::DPath::Context::BEGIN@8
# spent 97µs making 1 call to aliased::import, recursion: max depth 1, sum of overlapping time 97µs |
| 9 | 2 | 30µs | 2 | 403µs | # spent 403µs (9+394) within Data::DPath::Context::BEGIN@9 which was called:
# once (9µs+394µs) by Data::DPath::Path::BEGIN@1.6 at line 9 # spent 403µs making 1 call to Data::DPath::Context::BEGIN@9
# spent 394µs making 1 call to aliased::import, recursion: max depth 1, sum of overlapping time 394µs |
| 10 | 2 | 102µs | 2 | 2.81ms | # spent 2.71ms (506µs+2.20) within Data::DPath::Context::BEGIN@10 which was called:
# once (506µs+2.20ms) by Data::DPath::Path::BEGIN@1.6 at line 10 # spent 2.71ms making 1 call to Data::DPath::Context::BEGIN@10
# spent 99µs making 1 call to Exporter::import |
| 11 | 2 | 30µs | 2 | 71µs | # spent 44µs (16+27) within Data::DPath::Context::BEGIN@11 which was called:
# once (16µs+27µs) by Data::DPath::Path::BEGIN@1.6 at line 11 # spent 44µs making 1 call to Data::DPath::Context::BEGIN@11
# spent 27µs making 1 call to Exporter::import |
| 12 | 2 | 122µs | 1 | 871µs | # spent 871µs (603+268) within Data::DPath::Context::BEGIN@12 which was called:
# once (603µs+268µs) by Data::DPath::Path::BEGIN@1.6 at line 12 # spent 871µs making 1 call to Data::DPath::Context::BEGIN@12 |
| 13 | 2 | 102µs | 2 | 13.5ms | # spent 13.4ms (1.56+11.8) within Data::DPath::Context::BEGIN@13 which was called:
# once (1.56ms+11.8ms) by Data::DPath::Path::BEGIN@1.6 at line 13 # spent 13.4ms making 1 call to Data::DPath::Context::BEGIN@13
# spent 79µs making 1 call to Exporter::import |
| 14 | 2 | 36µs | 2 | 113µs | # spent 102µs (16+86) within Data::DPath::Context::BEGIN@14 which was called:
# once (16µs+86µs) by Data::DPath::Path::BEGIN@1.6 at line 14 # spent 102µs making 1 call to Data::DPath::Context::BEGIN@14
# spent 11µs making 1 call to List::Util::import |
| 15 | #use Sys::CPU; | ||||
| 16 | 2 | 110µs | 2 | 13.0ms | # spent 9.17ms (3.41+5.76) within Data::DPath::Context::BEGIN@16.8 which was called:
# once (3.41ms+5.76ms) by Data::DPath::Path::BEGIN@1.6 at line 16 # spent 9.17ms making 1 call to Data::DPath::Context::BEGIN@16.8
# spent 3.88ms making 1 call to POSIX::import |
| 17 | 2 | 191µs | 1 | 15.3ms | # spent 15.3ms (2.54+12.8) within Data::DPath::Context::BEGIN@17 which was called:
# once (2.54ms+12.8ms) by Data::DPath::Path::BEGIN@1.6 at line 17 # spent 15.3ms making 1 call to Data::DPath::Context::BEGIN@17 |
| 18 | |||||
| 19 | # run filter expressions in own Safe.pm compartment | ||||
| 20 | 1 | 200ns | our $COMPARTMENT; | ||
| 21 | 1 | 100ns | our $THREADCOUNT; | ||
| 22 | |||||
| 23 | # spent 830µs (17+814) within Data::DPath::Context::BEGIN@23 which was called:
# once (17µs+814µs) by Data::DPath::Path::BEGIN@1.6 at line 39 | ||||
| 24 | #$THREADCOUNT = $Data::DPath::PARALLELIZE ? Sys::CPU::cpu_count : 1; | ||||
| 25 | #print "THREADCOUNT: $THREADCOUNT\n"; | ||||
| 26 | package Data::DPath::Filters; | ||||
| 27 | 1 | 3µs | 1 | 697µs | $COMPARTMENT = Safe->new; # spent 697µs making 1 call to Safe::new |
| 28 | 1 | 2µs | 1 | 11µs | $COMPARTMENT->permit(qw":base_core"); # spent 11µs making 1 call to Safe::permit |
| 29 | # map DPath filter functions into new namespace | ||||
| 30 | 1 | 5µs | 1 | 106µs | $COMPARTMENT->share(qw(affe # spent 106µs making 1 call to Safe::share |
| 31 | idx | ||||
| 32 | size | ||||
| 33 | key | ||||
| 34 | value | ||||
| 35 | isa | ||||
| 36 | reftype | ||||
| 37 | is_reftype | ||||
| 38 | )); | ||||
| 39 | 1 | 39µs | 1 | 830µs | } # spent 830µs making 1 call to Data::DPath::Context::BEGIN@23 |
| 40 | |||||
| 41 | # print "use $]\n" if $] >= 5.010; # allow new-school Perl inside filter expressions | ||||
| 42 | # eval "use $]" if $] >= 5.010; # allow new-school Perl inside filter expressions | ||||
| 43 | |||||
| 44 | use Class::XSAccessor::Array | ||||
| 45 | 1 | 10µs | 1 | 156µs | # spent 170µs (15+156) within Data::DPath::Context::BEGIN@45 which was called:
# once (15µs+156µs) by Data::DPath::Path::BEGIN@1.6 at line 50 # spent 156µs making 1 call to Class::XSAccessor::Array::import |
| 46 | constructor => 'new', | ||||
| 47 | accessors => { | ||||
| 48 | current_points => 0, | ||||
| 49 | give_references => 1, | ||||
| 50 | 1 | 52µs | 1 | 170µs | }; # spent 170µs making 1 call to Data::DPath::Context::BEGIN@45 |
| 51 | |||||
| 52 | 1 | 12µs | 1 | 174µs | # spent 190µs (16+174) within Data::DPath::Context::BEGIN@52 which was called:
# once (16µs+174µs) by Data::DPath::Path::BEGIN@1.6 at line 63 # spent 174µs making 1 call to constant::import |
| 53 | ARRAY => 'ARRAY', | ||||
| 54 | SCALAR => 'SCALAR', | ||||
| 55 | ROOT => 'ROOT', | ||||
| 56 | ANYWHERE => 'ANYWHERE', | ||||
| 57 | KEY => 'KEY', | ||||
| 58 | ANYSTEP => 'ANYSTEP', | ||||
| 59 | NOSTEP => 'NOSTEP', | ||||
| 60 | PARENT => 'PARENT', | ||||
| 61 | ANCESTOR => 'ANCESTOR', | ||||
| 62 | ANCESTOR_OR_SELF => 'ANCESTOR_OR_SELF', | ||||
| 63 | 1 | 196µs | 1 | 190µs | }; # spent 190µs making 1 call to Data::DPath::Context::BEGIN@52 |
| 64 | |||||
| 65 | sub _splice_threads { | ||||
| 66 | my ($cargo) = @_; | ||||
| 67 | |||||
| 68 | my $nr_cargo = @$cargo; | ||||
| 69 | |||||
| 70 | return [[]] unless $nr_cargo; | ||||
| 71 | |||||
| 72 | my $threadcount = $THREADCOUNT || 1; | ||||
| 73 | my $blocksize = ceil ($nr_cargo / $threadcount); | ||||
| 74 | |||||
| 75 | my @result = map { | ||||
| 76 | my $first = $_ * $blocksize; | ||||
| 77 | my $last = min(($_+1) * $blocksize - 1, $nr_cargo-1); | ||||
| 78 | ($first <= $last) ? [ @$cargo[$first .. $last]] : (); | ||||
| 79 | } 0 .. $threadcount-1; | ||||
| 80 | |||||
| 81 | return \@result; | ||||
| 82 | } | ||||
| 83 | |||||
| 84 | # only finds "inner" values; if you need the outer start value | ||||
| 85 | # then just wrap it into one more level of array brackets. | ||||
| 86 | sub _any | ||||
| 87 | { | ||||
| 88 | # TODO: Idea: don't use @in/@out arrays but a hash to avoid memory reallocations | ||||
| 89 | |||||
| 90 | 30 | 18µs | my ($out, $in, $lookahead_key) = @_; | ||
| 91 | |||||
| 92 | 2 | 357µs | 2 | 48µs | # spent 31µs (14+17) within Data::DPath::Context::BEGIN@92 which was called:
# once (14µs+17µs) by Data::DPath::Path::BEGIN@1.6 at line 92 # spent 31µs making 1 call to Data::DPath::Context::BEGIN@92
# spent 17µs making 1 call to warnings::unimport |
| 93 | |||||
| 94 | 30 | 9µs | $in = defined $in ? $in : []; | ||
| 95 | 30 | 20µs | return $out unless @$in; | ||
| 96 | |||||
| 97 | 26 | 4µs | my @newin; | ||
| 98 | 26 | 2µs | my @newout; | ||
| 99 | 26 | 4µs | my $tmp_ref; | ||
| 100 | 26 | 3µs | my $tmp_deref; | ||
| 101 | 26 | 2µs | my $tmp_reftype; | ||
| 102 | |||||
| 103 | 26 | 20µs | foreach my $point (@$in) { | ||
| 104 | 58 | 7µs | my @values; | ||
| 105 | 58 | 10µs | next unless defined $point; | ||
| 106 | 58 | 31µs | 1 | 800ns | my $ref = $point->ref; # spent 800ns making 1 call to Data::DPath::Point::ref |
| 107 | |||||
| 108 | # speed optimization: first try faster ref, then reftype | ||||
| 109 | 58 | 969µs | 282 | 129µs | if (ref($$ref) eq HASH or reftype($$ref) eq HASH) { # spent 129µs making 282 calls to Scalar::Util::reftype, avg 456ns/call |
| 110 | @values = | ||||
| 111 | map { { val_ref => \($$ref->{$_}), key => $_ } } | ||||
| 112 | grep { | ||||
| 113 | # speed optimization: only consider a key if lookahead looks promising | ||||
| 114 | not defined $lookahead_key | ||||
| 115 | or $_ eq $lookahead_key | ||||
| 116 | or ($tmp_ref = ref($tmp_deref =$$ref->{$_})) eq HASH | ||||
| 117 | or $tmp_ref eq ARRAY | ||||
| 118 | or ($tmp_reftype = reftype($tmp_deref)) eq HASH | ||||
| 119 | or $tmp_reftype eq ARRAY | ||||
| 120 | # or HASH_or_ARRAY(\($$ref->{$_})) | ||||
| 121 | } | ||||
| 122 | keys %{$$ref}; | ||||
| 123 | } | ||||
| 124 | elsif (ref($$ref) eq ARRAY or reftype($$ref) eq ARRAY) { | ||||
| 125 | 38 | 40µs | @values = map { { val_ref => \$_ } } @{$$ref} | ||
| 126 | } | ||||
| 127 | else { | ||||
| 128 | next | ||||
| 129 | 14 | 8µs | } | ||
| 130 | |||||
| 131 | 44 | 68µs | foreach (@values) | ||
| 132 | { | ||||
| 133 | 54 | 22µs | my $key = $_->{key}; | ||
| 134 | 54 | 12µs | my $val_ref = $_->{val_ref}; | ||
| 135 | 54 | 145µs | 3 | 3µs | my $newpoint = Point->new->ref($val_ref)->parent($point); # spent 2µs making 1 call to Data::DPath::Point::new
# spent 900ns making 1 call to Data::DPath::Point::parent
# spent 900ns making 1 call to Data::DPath::Point::ref |
| 136 | 54 | 77µs | 2 | 3µs | $newpoint->attrs( Attrs->new(key => $key)) if $key; # spent 2µs making 1 call to Data::DPath::Attrs::new
# spent 800ns making 1 call to Data::DPath::Point::attrs |
| 137 | 54 | 17µs | push @newout, $newpoint; | ||
| 138 | 54 | 46µs | push @newin, $newpoint; | ||
| 139 | } | ||||
| 140 | } | ||||
| 141 | 26 | 16µs | push @$out, @newout; | ||
| 142 | 26 | 116µs | 26 | 0s | return _any ($out, \@newin, $lookahead_key); # spent 9.11ms making 26 calls to Data::DPath::Context::_any, avg 350µs/call, recursion: max depth 11, sum of overlapping time 9.11ms |
| 143 | } | ||||
| 144 | |||||
| 145 | # spent 76µs (51+25) within Data::DPath::Context::_all which was called 4 times, avg 19µs/call:
# 4 times (51µs+25µs) by Data::DPath::Context::match at line 465, avg 19µs/call | ||||
| 146 | 4 | 3µs | my ($self) = @_; | ||
| 147 | |||||
| 148 | 2 | 28µs | 2 | 38µs | # spent 24µs (11+14) within Data::DPath::Context::BEGIN@148 which was called:
# once (11µs+14µs) by Data::DPath::Path::BEGIN@1.6 at line 148 # spent 24µs making 1 call to Data::DPath::Context::BEGIN@148
# spent 14µs making 1 call to strict::unimport |
| 149 | 2 | 203µs | 2 | 31µs | # spent 20µs (10+10) within Data::DPath::Context::BEGIN@149 which was called:
# once (10µs+10µs) by Data::DPath::Path::BEGIN@1.6 at line 149 # spent 20µs making 1 call to Data::DPath::Context::BEGIN@149
# spent 10µs making 1 call to warnings::unimport |
| 150 | |||||
| 151 | return | ||||
| 152 | 4 | 7µs | 1 | 700ns | map { $self->give_references ? $_ : $$_ } # spent 700ns making 1 call to Data::DPath::Point::ref |
| 153 | uniq | ||||
| 154 | map { defined $_ ? $_->ref : () } | ||||
| 155 | 4 | 70µs | 6 | 24µs | @{$self->current_points}; # spent 23µs making 4 calls to List::MoreUtils::uniq, avg 6µs/call
# spent 700ns making 1 call to Data::DPath::Context::give_references
# spent 600ns making 1 call to Data::DPath::Context::current_points |
| 156 | } | ||||
| 157 | |||||
| 158 | # filter current results by array index | ||||
| 159 | sub _filter_points_index { | ||||
| 160 | my ($self, $index, $points) = @_; | ||||
| 161 | |||||
| 162 | return $points ? [$points->[$index]] : []; | ||||
| 163 | } | ||||
| 164 | |||||
| 165 | # filter current results by condition | ||||
| 166 | sub _filter_points_eval | ||||
| 167 | # spent 1.49ms (48µs+1.44) within Data::DPath::Context::_filter_points_eval which was called 2 times, avg 744µs/call:
# 2 times (48µs+1.44ms) by Data::DPath::Context::_filter_points at line 222, avg 744µs/call | ||||
| 168 | 2 | 3µs | my ($self, $filter, $points) = @_; | ||
| 169 | |||||
| 170 | 2 | 800ns | return [] unless @$points; | ||
| 171 | 2 | 400ns | return $points unless defined $filter; | ||
| 172 | |||||
| 173 | 2 | 400ns | my $new_points; | ||
| 174 | 2 | 300ns | my $res; | ||
| 175 | { | ||||
| 176 | 2 | 1µs | package Data::DPath::Filters; | ||
| 177 | |||||
| 178 | 2 | 2µs | local our $idx = 0; | ||
| 179 | 2 | 1µs | $new_points = [ | ||
| 180 | grep { | ||||
| 181 | 2 | 6µs | local our $p = $_; | ||
| 182 | 2 | 500ns | local $_; | ||
| 183 | 2 | 7µs | 1 | 900ns | my $pref = $p->ref; # spent 900ns making 1 call to Data::DPath::Point::ref |
| 184 | 2 | 1µs | if ( defined $pref ) { | ||
| 185 | 2 | 1µs | $_ = $$pref; | ||
| 186 | 2 | 2µs | if ($Data::DPath::USE_SAFE) { | ||
| 187 | # 'uninitialized' values are the norm | ||||
| 188 | # but "no warnings 'uninitialized'" does | ||||
| 189 | # not work in this restrictive Safe.pm config, so | ||||
| 190 | # we deactivate warnings completely by localizing $^W | ||||
| 191 | 2 | 9µs | 2 | 1.44ms | $res = $COMPARTMENT->reval('local $^W;'.$filter); # spent 1.44ms making 2 calls to Safe::reval, avg 720µs/call |
| 192 | } else { | ||||
| 193 | # 'uninitialized' values are the norm | ||||
| 194 | 2 | 119µs | 2 | 36µs | # spent 26µs (15+11) within Data::DPath::Filters::BEGIN@194 which was called:
# once (15µs+11µs) by Data::DPath::Path::BEGIN@1.6 at line 194 # spent 26µs making 1 call to Data::DPath::Filters::BEGIN@194
# spent 11µs making 1 call to warnings::unimport |
| 195 | $res = eval($filter); | ||||
| 196 | } | ||||
| 197 | 2 | 800ns | print STDERR ($@, "\n") if $@; | ||
| 198 | } else { | ||||
| 199 | $res = 0; | ||||
| 200 | } | ||||
| 201 | 2 | 900ns | $idx++; | ||
| 202 | 2 | 3µs | $res; | ||
| 203 | } @$points | ||||
| 204 | ]; | ||||
| 205 | } | ||||
| 206 | 2 | 8µs | return $new_points; | ||
| 207 | } | ||||
| 208 | |||||
| 209 | # spent 1.68ms (156µs+1.52) within Data::DPath::Context::_filter_points which was called 46 times, avg 36µs/call:
# 34 times (116µs+1.52ms) by Data::DPath::Context::_select_key at line 286, avg 48µs/call
# 4 times (16µs+1µs) by Data::DPath::Context::_select_root at line 241, avg 4µs/call
# 4 times (13µs+0s) by Data::DPath::Context::_select_parent at line 343, avg 3µs/call
# 4 times (12µs+0s) by Data::DPath::Context::_select_anywhere at line 261, avg 3µs/call | ||||
| 210 | 46 | 22µs | my ($self, $step, $points) = @_; | ||
| 211 | |||||
| 212 | 2 | 27µs | 2 | 35µs | # spent 22µs (9+13) within Data::DPath::Context::BEGIN@212 which was called:
# once (9µs+13µs) by Data::DPath::Path::BEGIN@1.6 at line 212 # spent 22µs making 1 call to Data::DPath::Context::BEGIN@212
# spent 13µs making 1 call to strict::unimport |
| 213 | 2 | 307µs | 2 | 30µs | # spent 20µs (10+10) within Data::DPath::Context::BEGIN@213 which was called:
# once (10µs+10µs) by Data::DPath::Path::BEGIN@1.6 at line 213 # spent 20µs making 1 call to Data::DPath::Context::BEGIN@213
# spent 10µs making 1 call to warnings::unimport |
| 214 | |||||
| 215 | 46 | 73µs | return [] unless @$points; | ||
| 216 | |||||
| 217 | 20 | 17µs | 1 | 1µs | my $filter = $step->filter; # spent 1µs making 1 call to Data::DPath::Step::filter |
| 218 | 20 | 63µs | return $points unless defined $filter; | ||
| 219 | |||||
| 220 | 2 | 47µs | 6 | 22µs | $filter =~ s/^\[\s*(.*?)\s*\]$/$1/; # strip brackets and whitespace # spent 14µs making 2 calls to Data::DPath::Context::CORE:subst, avg 7µs/call
# spent 9µs making 4 calls to Data::DPath::Context::CORE:substcont, avg 2µs/call |
| 221 | |||||
| 222 | 2 | 33µs | 6 | 1.50ms | if ($filter =~ /^-?\d+$/) # spent 1.49ms making 2 calls to Data::DPath::Context::_filter_points_eval, avg 744µs/call
# spent 8µs making 4 calls to Data::DPath::Context::CORE:match, avg 2µs/call |
| 223 | { | ||||
| 224 | return $self->_filter_points_index($filter, $points); # simple array index | ||||
| 225 | } | ||||
| 226 | elsif ($filter =~ /\S/) | ||||
| 227 | { | ||||
| 228 | return $self->_filter_points_eval($filter, $points); # full condition | ||||
| 229 | } | ||||
| 230 | else | ||||
| 231 | { | ||||
| 232 | return $points; | ||||
| 233 | } | ||||
| 234 | } | ||||
| 235 | |||||
| 236 | # the root node | ||||
| 237 | # (only makes sense at first step, but currently not asserted) | ||||
| 238 | # spent 42µs (25+17) within Data::DPath::Context::_select_root which was called 4 times, avg 10µs/call:
# 4 times (25µs+17µs) by Data::DPath::Context::_search at line 424, avg 10µs/call | ||||
| 239 | 4 | 3µs | my ($self, $step, $current_points, $new_points) = @_; | ||
| 240 | |||||
| 241 | 4 | 6µs | 4 | 17µs | my $step_points = $self->_filter_points($step, $current_points); # spent 17µs making 4 calls to Data::DPath::Context::_filter_points, avg 4µs/call |
| 242 | 4 | 12µs | push @$new_points, @$step_points; | ||
| 243 | } | ||||
| 244 | |||||
| 245 | |||||
| 246 | # // | ||||
| 247 | # anywhere in the tree | ||||
| 248 | # spent 1.75ms (72µs+1.67) within Data::DPath::Context::_select_anywhere which was called 4 times, avg 436µs/call:
# 4 times (72µs+1.67ms) by Data::DPath::Context::_search at line 424, avg 436µs/call | ||||
| 249 | 4 | 3µs | my ($self, $step, $current_points, $lookahead, $new_points) = @_; | ||
| 250 | |||||
| 251 | # speed optimization: only useful points added | ||||
| 252 | 4 | 900ns | my $lookahead_key; | ||
| 253 | 4 | 12µs | 2 | 1µs | if (defined $lookahead and $lookahead->kind eq KEY) { # spent 600ns making 1 call to Data::DPath::Step::kind
# spent 500ns making 1 call to Data::DPath::Step::part |
| 254 | $lookahead_key = $lookahead->part; | ||||
| 255 | } | ||||
| 256 | |||||
| 257 | # '//' | ||||
| 258 | # all hash/array nodes of a data structure | ||||
| 259 | 4 | 16µs | foreach my $point (@$current_points) { | ||
| 260 | 4 | 17µs | 4 | 1.66ms | my @step_points = (@{_any([], [ $point ], $lookahead_key)}, $point); # spent 1.66ms making 4 calls to Data::DPath::Context::_any, avg 415µs/call |
| 261 | 4 | 22µs | 4 | 12µs | push @$new_points, @{$self->_filter_points($step, \@step_points)}; # spent 12µs making 4 calls to Data::DPath::Context::_filter_points, avg 3µs/call |
| 262 | } | ||||
| 263 | } | ||||
| 264 | |||||
| 265 | # /key | ||||
| 266 | # the value of a key | ||||
| 267 | # spent 2.18ms (508µs+1.67) within Data::DPath::Context::_select_key which was called 8 times, avg 273µs/call:
# 8 times (508µs+1.67ms) by Data::DPath::Context::_search at line 424, avg 273µs/call | ||||
| 268 | 8 | 6µs | my ($self, $step, $current_points, $new_points) = @_; | ||
| 269 | |||||
| 270 | 8 | 32µs | foreach my $point (@$current_points) { | ||
| 271 | 2 | 164µs | 2 | 34µs | # spent 23µs (12+11) within Data::DPath::Context::BEGIN@271 which was called:
# once (12µs+11µs) by Data::DPath::Path::BEGIN@1.6 at line 271 # spent 23µs making 1 call to Data::DPath::Context::BEGIN@271
# spent 11µs making 1 call to warnings::unimport |
| 272 | 62 | 10µs | next unless defined $point; | ||
| 273 | 62 | 35µs | 1 | 700ns | my $pref = $point->ref; # spent 700ns making 1 call to Data::DPath::Point::ref |
| 274 | next unless ( | ||||
| 275 | # speed optimization: | ||||
| 276 | # first try faster ref, then reftype | ||||
| 277 | 62 | 129µs | 30 | 24µs | ref($$pref) eq HASH or # spent 24µs making 30 calls to Scalar::Util::reftype, avg 807ns/call |
| 278 | reftype($$pref) eq HASH | ||||
| 279 | ); | ||||
| 280 | # take point as hash, skip undefs | ||||
| 281 | 34 | 118µs | 2 | 8µs | my $attrs = Attrs->new(key => $step->part); # spent 8µs making 1 call to Data::DPath::Attrs::new
# spent 500ns making 1 call to Data::DPath::Step::part |
| 282 | 34 | 10µs | my $step_points = []; | ||
| 283 | 34 | 81µs | 6 | 5µs | if (exists $$pref->{$step->part}) { # spent 1µs making 1 call to Data::DPath::Point::new
# spent 1µs making 2 calls to Data::DPath::Step::part, avg 600ns/call
# spent 1µs making 1 call to Data::DPath::Point::attrs
# spent 900ns making 1 call to Data::DPath::Point::ref
# spent 800ns making 1 call to Data::DPath::Point::parent |
| 284 | $step_points = [ Point->new->ref(\($$pref->{$step->part}))->parent($point)->attrs($attrs) ]; | ||||
| 285 | } | ||||
| 286 | 34 | 87µs | 34 | 1.63ms | push @$new_points, @{$self->_filter_points($step, $step_points)}; # spent 1.63ms making 34 calls to Data::DPath::Context::_filter_points, avg 48µs/call |
| 287 | } | ||||
| 288 | } | ||||
| 289 | |||||
| 290 | # '*' | ||||
| 291 | # all leaves of a data tree | ||||
| 292 | sub _select_anystep { | ||||
| 293 | my ($self, $step, $current_points, $new_points) = @_; | ||||
| 294 | |||||
| 295 | 2 | 655µs | 2 | 32µs | # spent 21µs (11+10) within Data::DPath::Context::BEGIN@295 which was called:
# once (11µs+10µs) by Data::DPath::Path::BEGIN@1.6 at line 295 # spent 21µs making 1 call to Data::DPath::Context::BEGIN@295
# spent 10µs making 1 call to warnings::unimport |
| 296 | foreach my $point (@$current_points) { | ||||
| 297 | # take point as array | ||||
| 298 | my $pref = $point->ref; | ||||
| 299 | my $ref = $$pref; | ||||
| 300 | my $step_points = []; | ||||
| 301 | # speed optimization: first try faster ref, then reftype | ||||
| 302 | if (ref($ref) eq HASH or reftype($ref) eq HASH) { | ||||
| 303 | $step_points = [ map { | ||||
| 304 | my $v_ref = \($ref->{$_}); | ||||
| 305 | my $attrs = Attrs->new(key => $_); | ||||
| 306 | Point->new->ref($v_ref)->parent($point)->attrs($attrs) | ||||
| 307 | } keys %$ref ]; | ||||
| 308 | } elsif (ref($ref) eq ARRAY or reftype($ref) eq ARRAY) { | ||||
| 309 | $step_points = [ map { | ||||
| 310 | Point->new->ref(\$_)->parent($point) | ||||
| 311 | } @$ref ]; | ||||
| 312 | } else { | ||||
| 313 | if (ref($pref) eq SCALAR or reftype($pref) eq SCALAR) { | ||||
| 314 | # TODO: without map, it's just one value | ||||
| 315 | $step_points = [ #map { | ||||
| 316 | Point->new->ref($pref)->parent($point) # XXX? why $_? What happens to $pref? | ||||
| 317 | ]; # } $ref ]; | ||||
| 318 | } | ||||
| 319 | } | ||||
| 320 | push @$new_points, @{ $self->_filter_points($step, $step_points) }; | ||||
| 321 | } | ||||
| 322 | } | ||||
| 323 | |||||
| 324 | # '.' | ||||
| 325 | # no step (neither up nor down), just allow filtering | ||||
| 326 | sub _select_nostep { | ||||
| 327 | my ($self, $step, $current_points, $new_points) = @_; | ||||
| 328 | |||||
| 329 | foreach my $point (@{$current_points}) { | ||||
| 330 | my $step_points = [$point]; | ||||
| 331 | push @$new_points, @{ $self->_filter_points($step, $step_points) }; | ||||
| 332 | } | ||||
| 333 | } | ||||
| 334 | |||||
| 335 | # '..' | ||||
| 336 | # the parent | ||||
| 337 | # spent 64µs (51+14) within Data::DPath::Context::_select_parent which was called 4 times, avg 16µs/call:
# 4 times (51µs+14µs) by Data::DPath::Context::_search at line 424, avg 16µs/call | ||||
| 338 | 4 | 5µs | my ($self, $step, $current_points, $new_points) = @_; | ||
| 339 | |||||
| 340 | 4 | 16µs | foreach my $point (@{$current_points}) { | ||
| 341 | 4 | 1µs | next unless defined $point; | ||
| 342 | 4 | 9µs | 1 | 900ns | my $step_points = [$point->parent]; # spent 900ns making 1 call to Data::DPath::Point::parent |
| 343 | 4 | 15µs | 4 | 13µs | push @$new_points, @{ $self->_filter_points($step, $step_points) }; # spent 13µs making 4 calls to Data::DPath::Context::_filter_points, avg 3µs/call |
| 344 | } | ||||
| 345 | } | ||||
| 346 | |||||
| 347 | # '::ancestor' | ||||
| 348 | # all ancestors (parent, grandparent, etc.) of the current node | ||||
| 349 | sub _select_ancestor { | ||||
| 350 | my ($self, $step, $current_points, $new_points) = @_; | ||||
| 351 | |||||
| 352 | foreach my $point (@{$current_points}) { | ||||
| 353 | my $step_points = []; | ||||
| 354 | my $parent = $point; | ||||
| 355 | while ($parent = $parent->parent) { | ||||
| 356 | push @$step_points, $parent; # order matters | ||||
| 357 | } | ||||
| 358 | push @$new_points, @{ $self->_filter_points($step, $step_points) }; | ||||
| 359 | } | ||||
| 360 | } | ||||
| 361 | |||||
| 362 | # '::ancestor-or-self' | ||||
| 363 | # all ancestors (parent, grandparent, etc.) of the current node and the current node itself | ||||
| 364 | sub _select_ancestor_or_self { | ||||
| 365 | my ($self, $step, $current_points, $new_points) = @_; | ||||
| 366 | |||||
| 367 | foreach my $point (@{$current_points}) { | ||||
| 368 | my $step_points = [$point]; | ||||
| 369 | my $parent = $point; | ||||
| 370 | while ($parent = $parent->parent) { | ||||
| 371 | push @$step_points, $parent; # order matters | ||||
| 372 | } | ||||
| 373 | push @$new_points, @{ $self->_filter_points($step, $step_points) }; | ||||
| 374 | } | ||||
| 375 | } | ||||
| 376 | |||||
| 377 | sub ref { | ||||
| 378 | my ($self) = @_; | ||||
| 379 | $self->first_point->{ref}; | ||||
| 380 | } | ||||
| 381 | |||||
| 382 | sub deref { | ||||
| 383 | my ($self) = @_; | ||||
| 384 | ${$self->ref}; | ||||
| 385 | } | ||||
| 386 | |||||
| 387 | sub first_point { | ||||
| 388 | my ($self) = @_; | ||||
| 389 | $self->current_points->[0]; | ||||
| 390 | } | ||||
| 391 | |||||
| 392 | sub all_points { | ||||
| 393 | my ($self) = @_; | ||||
| 394 | iarray $self->current_points; | ||||
| 395 | } | ||||
| 396 | |||||
| 397 | sub _iter { | ||||
| 398 | my ($self) = @_; | ||||
| 399 | |||||
| 400 | my $iter = iarray $self->current_points; | ||||
| 401 | return imap { __PACKAGE__->new->current_points([ $_ ]) } $iter; | ||||
| 402 | } | ||||
| 403 | |||||
| 404 | sub isearch | ||||
| 405 | { | ||||
| 406 | my ($self, $path_str) = @_; | ||||
| 407 | $self->_search(Data::DPath::Path->new(path => $path_str))->_iter; | ||||
| 408 | } | ||||
| 409 | |||||
| 410 | sub _search | ||||
| 411 | # spent 4.26ms (223µs+4.04) within Data::DPath::Context::_search which was called 4 times, avg 1.07ms/call:
# 4 times (223µs+4.04ms) by Data::DPath::Context::match at line 465, avg 1.07ms/call | ||||
| 412 | 4 | 2µs | my ($self, $dpath) = @_; | ||
| 413 | |||||
| 414 | 2 | 29µs | 2 | 40µs | # spent 26µs (13+14) within Data::DPath::Context::BEGIN@414 which was called:
# once (13µs+14µs) by Data::DPath::Path::BEGIN@1.6 at line 414 # spent 26µs making 1 call to Data::DPath::Context::BEGIN@414
# spent 14µs making 1 call to strict::unimport |
| 415 | 2 | 285µs | 2 | 31µs | # spent 21µs (10+10) within Data::DPath::Context::BEGIN@415 which was called:
# once (10µs+10µs) by Data::DPath::Path::BEGIN@1.6 at line 415 # spent 21µs making 1 call to Data::DPath::Context::BEGIN@415
# spent 10µs making 1 call to warnings::unimport |
| 416 | |||||
| 417 | 4 | 5µs | 1 | 500ns | my $current_points = $self->current_points; # spent 500ns making 1 call to Data::DPath::Context::current_points |
| 418 | 4 | 5µs | 1 | 700ns | my $steps = $dpath->_steps; # spent 700ns making 1 call to Data::DPath::Path::_steps |
| 419 | 4 | 56µs | for (my $i = 0; $i < @$steps; $i++) { | ||
| 420 | 20 | 9µs | my $step = $steps->[$i]; | ||
| 421 | 20 | 9µs | my $lookahead = $steps->[$i+1]; | ||
| 422 | 20 | 9µs | my $new_points = []; | ||
| 423 | |||||
| 424 | 20 | 81µs | 26 | 4.04ms | if ($step->kind eq ROOT) # spent 2.18ms making 8 calls to Data::DPath::Context::_select_key, avg 273µs/call
# spent 1.75ms making 4 calls to Data::DPath::Context::_select_anywhere, avg 436µs/call
# spent 64µs making 4 calls to Data::DPath::Context::_select_parent, avg 16µs/call
# spent 42µs making 4 calls to Data::DPath::Context::_select_root, avg 10µs/call
# spent 4µs making 6 calls to Data::DPath::Step::kind, avg 617ns/call |
| 425 | { | ||||
| 426 | $self->_select_root($step, $current_points, $new_points); | ||||
| 427 | } | ||||
| 428 | elsif ($step->kind eq ANYWHERE) | ||||
| 429 | { | ||||
| 430 | $self->_select_anywhere($step, $current_points, $lookahead, $new_points); | ||||
| 431 | } | ||||
| 432 | elsif ($step->kind eq KEY) | ||||
| 433 | { | ||||
| 434 | $self->_select_key($step, $current_points, $new_points); | ||||
| 435 | } | ||||
| 436 | elsif ($step->kind eq ANYSTEP) | ||||
| 437 | { | ||||
| 438 | $self->_select_anystep($step, $current_points, $new_points); | ||||
| 439 | } | ||||
| 440 | elsif ($step->kind eq NOSTEP) | ||||
| 441 | { | ||||
| 442 | $self->_select_nostep($step, $current_points, $new_points); | ||||
| 443 | } | ||||
| 444 | elsif ($step->kind eq PARENT) | ||||
| 445 | { | ||||
| 446 | $self->_select_parent($step, $current_points, $new_points); | ||||
| 447 | } | ||||
| 448 | elsif ($step->kind eq ANCESTOR) | ||||
| 449 | { | ||||
| 450 | $self->_select_ancestor($step, $current_points, $new_points); | ||||
| 451 | } | ||||
| 452 | elsif ($step->kind eq ANCESTOR_OR_SELF) | ||||
| 453 | { | ||||
| 454 | $self->_select_ancestor_or_self($step, $current_points, $new_points); | ||||
| 455 | } | ||||
| 456 | 20 | 14µs | $current_points = $new_points; | ||
| 457 | } | ||||
| 458 | 4 | 8µs | 1 | 1µs | $self->current_points( $current_points ); # spent 1µs making 1 call to Data::DPath::Context::current_points |
| 459 | 4 | 13µs | return $self; | ||
| 460 | } | ||||
| 461 | |||||
| 462 | # spent 4.37ms (33µs+4.34) within Data::DPath::Context::match which was called 4 times, avg 1.09ms/call:
# 4 times (33µs+4.34ms) by Data::DPath::Path::match at line 137 of lib/Data/DPath/Path.pm, avg 1.09ms/call | ||||
| 463 | 4 | 2µs | my ($self, $dpath) = @_; | ||
| 464 | |||||
| 465 | 4 | 24µs | 8 | 4.34ms | $self->_search($dpath)->_all; # spent 4.26ms making 4 calls to Data::DPath::Context::_search, avg 1.07ms/call
# spent 76µs making 4 calls to Data::DPath::Context::_all, avg 19µs/call |
| 466 | } | ||||
| 467 | |||||
| 468 | 1 | 4µs | 1; | ||
| 469 | |||||
| 470 | __END__ | ||||
# spent 8µs within Data::DPath::Context::CORE:match which was called 4 times, avg 2µs/call:
# 4 times (8µs+0s) by Data::DPath::Context::_filter_points at line 222, avg 2µs/call | |||||
# spent 14µs within Data::DPath::Context::CORE:subst which was called 2 times, avg 7µs/call:
# 2 times (14µs+0s) by Data::DPath::Context::_filter_points at line 220, avg 7µs/call | |||||
# spent 9µs within Data::DPath::Context::CORE:substcont which was called 4 times, avg 2µs/call:
# 4 times (9µs+0s) by Data::DPath::Context::_filter_points at line 220, avg 2µs/call | |||||
# spent 3µs within Data::DPath::Context::current_points which was called 4 times, avg 750ns/call:
# once (1µs+0s) by Data::DPath::Context::_search at line 458
# once (800ns+0s) by Data::DPath::Path::match at line 133 of lib/Data/DPath/Path.pm
# once (600ns+0s) by Data::DPath::Context::_all at line 155
# once (500ns+0s) by Data::DPath::Context::_search at line 417 | |||||
# spent 1µs within Data::DPath::Context::give_references which was called 2 times, avg 650ns/call:
# once (700ns+0s) by Data::DPath::Context::_all at line 155
# once (600ns+0s) by Data::DPath::Path::match at line 133 of lib/Data/DPath/Path.pm | |||||
# spent 5µs within Data::DPath::Context::new which was called:
# once (5µs+0s) by Data::DPath::Path::match at line 133 of lib/Data/DPath/Path.pm |