| Filename | /home/ss5/local/projects/data-dpath/lib/Data/DPath/Path.pm |
| Statements | Executed 395 statements in 2.32ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 5.51ms | 12.0ms | Data::DPath::Path::BEGIN@11 |
| 1 | 1 | 1 | 4.24ms | 19.4ms | Data::DPath::Path::BEGIN@7 |
| 1 | 1 | 1 | 646µs | 3.77ms | Data::DPath::Path::BEGIN@8 |
| 4 | 1 | 1 | 448µs | 1.50ms | Data::DPath::Path::_build__steps |
| 16 | 1 | 1 | 92µs | 103µs | Data::DPath::Path::unescape |
| 4 | 1 | 1 | 87µs | 1.58ms | Data::DPath::Path::new |
| 46 | 3 | 1 | 80µs | 80µs | Data::DPath::Path::CORE:match (opcode) |
| 16 | 1 | 1 | 80µs | 99µs | Data::DPath::Path::quoted |
| 4 | 1 | 1 | 78µs | 4.46ms | Data::DPath::Path::match |
| 4 | 4 | 1 | 26µs | 4.49ms | Data::DPath::Path::op_match |
| 1 | 1 | 1 | 17µs | 71µs | Data::DPath::Path::BEGIN@4 |
| 1 | 1 | 1 | 15µs | 196µs | Data::DPath::Path::BEGIN@14 |
| 1 | 1 | 1 | 15µs | 149µs | Data::DPath::Path::BEGIN@21 |
| 1 | 1 | 1 | 13µs | 27µs | Data::DPath::Path::BEGIN@115 |
| 32 | 2 | 1 | 11µs | 11µs | Data::DPath::Path::CORE:subst (opcode) |
| 1 | 1 | 1 | 11µs | 16µs | Data::DPath::Path::BEGIN@5 |
| 1 | 1 | 1 | 11µs | 46.6ms | Data::DPath::Path::BEGIN@10 |
| 1 | 1 | 1 | 9µs | 551µs | Data::DPath::Path::BEGIN@9 |
| 1 | 1 | 1 | 7µs | 7µs | Data::DPath::Path::path (xsub) |
| 2 | 2 | 2 | 2µs | 2µs | Data::DPath::Path::_steps (xsub) |
| 1 | 1 | 1 | 700ns | 700ns | Data::DPath::Path::give_references (xsub) |
| 0 | 0 | 0 | 0s | 0s | Data::DPath::Path::unquote |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package Data::DPath::Path; | ||||
| 2 | # ABSTRACT: Abstraction for a DPath | ||||
| 3 | |||||
| 4 | 2 | 36µs | 2 | 124µs | # spent 71µs (17+54) within Data::DPath::Path::BEGIN@4 which was called:
# once (17µs+54µs) by Data::DPath::BEGIN@12 at line 4 # spent 71µs making 1 call to Data::DPath::Path::BEGIN@4
# spent 54µs making 1 call to strict::import |
| 5 | 2 | 25µs | 2 | 22µs | # spent 16µs (11+5) within Data::DPath::Path::BEGIN@5 which was called:
# once (11µs+5µs) by Data::DPath::BEGIN@12 at line 5 # spent 16µs making 1 call to Data::DPath::Path::BEGIN@5
# spent 5µs making 1 call to warnings::import |
| 6 | |||||
| 7 | 2 | 128µs | 2 | 19.5ms | # spent 19.4ms (4.24+15.2) within Data::DPath::Path::BEGIN@7 which was called:
# once (4.24ms+15.2ms) by Data::DPath::BEGIN@12 at line 7 # spent 19.4ms making 1 call to Data::DPath::Path::BEGIN@7
# spent 42µs making 1 call to Exporter::import |
| 8 | 2 | 135µs | 2 | 6.84ms | # spent 3.77ms (646µs+3.13) within Data::DPath::Path::BEGIN@8 which was called:
# once (646µs+3.13ms) by Data::DPath::BEGIN@12 at line 8 # spent 3.77ms making 1 call to Data::DPath::Path::BEGIN@8
# spent 3.07ms making 1 call to aliased::import |
| 9 | 2 | 31µs | 2 | 1.09ms | # spent 551µs (9+542) within Data::DPath::Path::BEGIN@9 which was called:
# once (9µs+542µs) by Data::DPath::BEGIN@12 at line 9 # spent 551µs making 1 call to Data::DPath::Path::BEGIN@9
# spent 542µs making 1 call to aliased::import |
| 10 | 2 | 40µs | 2 | 93.1ms | # spent 46.6ms (11µs+46.6) within Data::DPath::Path::BEGIN@10 which was called:
# once (11µs+46.6ms) by Data::DPath::BEGIN@12 at line 10 # spent 46.6ms making 1 call to Data::DPath::Path::BEGIN@10
# spent 46.6ms making 1 call to aliased::import |
| 11 | 3 | 160µs | 3 | 12.1ms | # spent 12.0ms (5.51+6.49) within Data::DPath::Path::BEGIN@11 which was called:
# once (5.51ms+6.49ms) by Data::DPath::BEGIN@12 at line 11 # spent 12.0ms making 1 call to Data::DPath::Path::BEGIN@11
# spent 74µs making 1 call to Exporter::import
# spent 12µs making 1 call to UNIVERSAL::VERSION |
| 12 | |||||
| 13 | use Class::XSAccessor | ||||
| 14 | 1 | 11µs | 1 | 181µs | # spent 196µs (15+181) within Data::DPath::Path::BEGIN@14 which was called:
# once (15µs+181µs) by Data::DPath::BEGIN@12 at line 19 # spent 181µs making 1 call to Class::XSAccessor::import |
| 15 | accessors => { | ||||
| 16 | path => 'path', | ||||
| 17 | _steps => '_steps', | ||||
| 18 | give_references => 'give_references', | ||||
| 19 | 1 | 45µs | 1 | 196µs | }; # spent 196µs making 1 call to Data::DPath::Path::BEGIN@14 |
| 20 | |||||
| 21 | 1 | 11µs | 1 | 134µs | # spent 149µs (15+134) within Data::DPath::Path::BEGIN@21 which was called:
# once (15µs+134µs) by Data::DPath::BEGIN@12 at line 29 # spent 134µs making 1 call to constant::import |
| 22 | ANYWHERE => 'ANYWHERE', | ||||
| 23 | KEY => 'KEY', | ||||
| 24 | ANYSTEP => 'ANYSTEP', | ||||
| 25 | NOSTEP => 'NOSTEP', | ||||
| 26 | PARENT => 'PARENT', | ||||
| 27 | ANCESTOR => 'ANCESTOR', | ||||
| 28 | ANCESTOR_OR_SELF => 'ANCESTOR_OR_SELF', | ||||
| 29 | 1 | 460µs | 1 | 149µs | }; # spent 149µs making 1 call to Data::DPath::Path::BEGIN@21 |
| 30 | |||||
| 31 | # spent 1.58ms (87µs+1.50) within Data::DPath::Path::new which was called 4 times, avg 396µs/call:
# 4 times (87µs+1.50ms) by Data::DPath::__ANON__[lib/Data/DPath.pm:19] at line 18 of lib/Data/DPath.pm, avg 396µs/call | ||||
| 32 | 4 | 2µs | my $class = shift; | ||
| 33 | 4 | 66µs | my $self = bless { @_ }, $class; | ||
| 34 | 4 | 6µs | 4 | 1.50ms | $self->_build__steps; # spent 1.50ms making 4 calls to Data::DPath::Path::_build__steps, avg 374µs/call |
| 35 | 4 | 11µs | return $self; | ||
| 36 | } | ||||
| 37 | |||||
| 38 | # spent 103µs (92+11) within Data::DPath::Path::unescape which was called 16 times, avg 6µs/call:
# 16 times (92µs+11µs) by Data::DPath::Path::_build__steps at line 112, avg 6µs/call | ||||
| 39 | 16 | 9µs | my ($str) = @_; | ||
| 40 | |||||
| 41 | 16 | 4µs | return unless defined $str; | ||
| 42 | 16 | 38µs | 16 | 7µs | $str =~ s/(?<!\\)\\(["'])/$1/g; # '"$ # spent 7µs making 16 calls to Data::DPath::Path::CORE:subst, avg 444ns/call |
| 43 | 16 | 28µs | 16 | 4µs | $str =~ s/\\{2}/\\/g; # spent 4µs making 16 calls to Data::DPath::Path::CORE:subst, avg 250ns/call |
| 44 | 16 | 35µs | return $str; | ||
| 45 | } | ||||
| 46 | |||||
| 47 | sub unquote { | ||||
| 48 | my ($str) = @_; | ||||
| 49 | $str =~ s/^"(.*)"$/$1/g; | ||||
| 50 | return $str; | ||||
| 51 | } | ||||
| 52 | |||||
| 53 | 16 | 119µs | 16 | 20µs | # spent 99µs (80+20) within Data::DPath::Path::quoted which was called 16 times, avg 6µs/call:
# 16 times (80µs+20µs) by Data::DPath::Path::_build__steps at line 77, avg 6µs/call # spent 20µs making 16 calls to Data::DPath::Path::CORE:match, avg 1µs/call |
| 54 | |||||
| 55 | 1 | 39µs | eval 'use overload "~~" => \&op_match' if $] >= 5.010; # spent 40µs executing statements in string eval # includes 14µs spent executing 1 call to 1 sub defined therein. | ||
| 56 | |||||
| 57 | # spent 4.49ms (26µs+4.46) within Data::DPath::Path::op_match which was called 4 times, avg 1.12ms/call:
# once (8µs+2.22ms) by main::RUNTIME at line 73 of t/optimization.t
# once (5µs+1.92ms) by main::RUNTIME at line 39 of t/optimization.t
# once (7µs+217µs) by main::RUNTIME at line 36 of t/optimization.t
# once (6µs+99µs) by main::RUNTIME at line 70 of t/optimization.t | ||||
| 58 | 4 | 4µs | my ($self, $data, $rhs) = @_; | ||
| 59 | |||||
| 60 | 4 | 24µs | 4 | 4.46ms | return [ $self->match( $data ) ]; # spent 4.46ms making 4 calls to Data::DPath::Path::match, avg 1.12ms/call |
| 61 | } | ||||
| 62 | |||||
| 63 | # essentially the Path parser | ||||
| 64 | # spent 1.50ms (448µs+1.05) within Data::DPath::Path::_build__steps which was called 4 times, avg 374µs/call:
# 4 times (448µs+1.05ms) by Data::DPath::Path::new at line 34, avg 374µs/call | ||||
| 65 | 4 | 3µs | my ($self) = @_; | ||
| 66 | |||||
| 67 | 4 | 21µs | 1 | 7µs | my $remaining_path = $self->path; # spent 7µs making 1 call to Data::DPath::Path::path |
| 68 | 4 | 800ns | my $extracted; | ||
| 69 | 4 | 1µs | my @steps; | ||
| 70 | |||||
| 71 | 4 | 56µs | 3 | 14µs | push @steps, Step->new->part('')->kind(ROOT); # spent 9µs making 1 call to Data::DPath::Step::new
# spent 4µs making 1 call to Data::DPath::Step::part
# spent 900ns making 1 call to Data::DPath::Step::kind |
| 72 | |||||
| 73 | 4 | 2µs | while ($remaining_path) { | ||
| 74 | 16 | 3µs | my $plain_part; | ||
| 75 | 16 | 2µs | my $filter; | ||
| 76 | 16 | 2µs | my $kind; | ||
| 77 | 16 | 26µs | 16 | 99µs | if ( quoted($remaining_path) ) { # spent 99µs making 16 calls to Data::DPath::Path::quoted, avg 6µs/call |
| 78 | ($plain_part, $remaining_path) = extract_delimited($remaining_path, q/'"/, "/"); # ' | ||||
| 79 | ($filter, $remaining_path) = extract_codeblock($remaining_path, "[]"); | ||||
| 80 | $plain_part = unescape unquote $plain_part; | ||||
| 81 | $kind = KEY; # quoted is always a key | ||||
| 82 | } | ||||
| 83 | else | ||||
| 84 | { | ||||
| 85 | 16 | 5µs | my $filter_already_extracted = 0; | ||
| 86 | 16 | 44µs | 16 | 760µs | ($extracted, $remaining_path) = extract_delimited($remaining_path,'/'); # spent 760µs making 16 calls to Text::Balanced::extract_delimited, avg 47µs/call |
| 87 | |||||
| 88 | 16 | 11µs | if (not $extracted) { | ||
| 89 | ($extracted, $remaining_path) = ($remaining_path, undef); # END OF PATH | ||||
| 90 | } else { | ||||
| 91 | |||||
| 92 | # work around to recognize slashes in filter expressions and handle them: | ||||
| 93 | # | ||||
| 94 | # - 1) see if key unexpectedly contains opening "[" but no closing "]" | ||||
| 95 | # - 2) use the part before "[" | ||||
| 96 | # - 3) unshift the rest to remaining | ||||
| 97 | # - 4) extract_codeblock() explicitely | ||||
| 98 | 12 | 50µs | 14 | 18µs | if ($extracted =~ /(.*)((?<!\\)\[.*)/ and $extracted !~ m|\]/\s*$|) { # spent 18µs making 14 calls to Data::DPath::Path::CORE:match, avg 1µs/call |
| 99 | $remaining_path = $2 . $remaining_path; | ||||
| 100 | ( $plain_part = $1 ) =~ s|^/||; | ||||
| 101 | ($filter, $remaining_path) = extract_codeblock($remaining_path, "[]"); | ||||
| 102 | $filter_already_extracted = 1; | ||||
| 103 | } else { | ||||
| 104 | 12 | 13µs | $remaining_path = (chop $extracted) . $remaining_path; | ||
| 105 | } | ||||
| 106 | } | ||||
| 107 | |||||
| 108 | 16 | 91µs | 16 | 42µs | ($plain_part, $filter) = $extracted =~ m,^/ # leading / # spent 42µs making 16 calls to Data::DPath::Path::CORE:match, avg 3µs/call |
| 109 | (.*?) # path part | ||||
| 110 | (\[.*\])?$ # optional filter | ||||
| 111 | ,xg unless $filter_already_extracted; | ||||
| 112 | 16 | 28µs | 16 | 103µs | $plain_part = unescape $plain_part; # spent 103µs making 16 calls to Data::DPath::Path::unescape, avg 6µs/call |
| 113 | } | ||||
| 114 | |||||
| 115 | 2 | 250µs | 2 | 41µs | # spent 27µs (13+14) within Data::DPath::Path::BEGIN@115 which was called:
# once (13µs+14µs) by Data::DPath::BEGIN@12 at line 115 # spent 27µs making 1 call to Data::DPath::Path::BEGIN@115
# spent 14µs making 1 call to warnings::unimport |
| 116 | 16 | 16µs | if ($plain_part eq '') { $kind ||= ANYWHERE } | ||
| 117 | elsif ($plain_part eq '*') { $kind ||= ANYSTEP } | ||||
| 118 | elsif ($plain_part eq '.') { $kind ||= NOSTEP } | ||||
| 119 | elsif ($plain_part eq '..') { $kind ||= PARENT } | ||||
| 120 | elsif ($plain_part eq '::ancestor') { $kind ||= ANCESTOR } | ||||
| 121 | elsif ($plain_part eq '::ancestor-or-self') { $kind ||= ANCESTOR_OR_SELF } | ||||
| 122 | 8 | 3µs | else { $kind ||= KEY } | ||
| 123 | |||||
| 124 | 16 | 96µs | 4 | 4µs | push @steps, Step->new->part($plain_part)->kind($kind)->filter($filter); # spent 2µs making 1 call to Data::DPath::Step::new
# spent 1µs making 1 call to Data::DPath::Step::part
# spent 700ns making 1 call to Data::DPath::Step::filter
# spent 700ns making 1 call to Data::DPath::Step::kind |
| 125 | } | ||||
| 126 | 4 | 8µs | 1 | 2µs | pop @steps if $steps[-1]->kind eq ANYWHERE; # ignore final '/' # spent 2µs making 1 call to Data::DPath::Step::kind |
| 127 | 4 | 20µs | 1 | 1µs | $self->_steps( \@steps ); # spent 1µs making 1 call to Data::DPath::Path::_steps |
| 128 | } | ||||
| 129 | |||||
| 130 | # spent 4.46ms (78µs+4.38) within Data::DPath::Path::match which was called 4 times, avg 1.12ms/call:
# 4 times (78µs+4.38ms) by Data::DPath::Path::op_match at line 60, avg 1.12ms/call | ||||
| 131 | 4 | 3µs | my ($self, $data) = @_; | ||
| 132 | |||||
| 133 | 4 | 74µs | 6 | 14µs | my $context = Context # spent 6µs making 1 call to Data::DPath::Point::new
# spent 5µs making 1 call to Data::DPath::Context::new
# spent 1µs making 1 call to Data::DPath::Point::ref
# spent 800ns making 1 call to Data::DPath::Context::current_points
# spent 700ns making 1 call to Data::DPath::Path::give_references
# spent 600ns making 1 call to Data::DPath::Context::give_references |
| 134 | ->new | ||||
| 135 | ->current_points([ Point->new->ref(\$data) ]) | ||||
| 136 | ->give_references($self->give_references); | ||||
| 137 | 4 | 17µs | 4 | 4.37ms | return $context->match($self); # spent 4.37ms making 4 calls to Data::DPath::Context::match, avg 1.09ms/call |
| 138 | } | ||||
| 139 | |||||
| 140 | 1 | 4µs | 1; | ||
| 141 | |||||
| 142 | __END__ | ||||
# spent 80µs within Data::DPath::Path::CORE:match which was called 46 times, avg 2µs/call:
# 16 times (42µs+0s) by Data::DPath::Path::_build__steps at line 108, avg 3µs/call
# 16 times (20µs+0s) by Data::DPath::Path::quoted at line 53, avg 1µs/call
# 14 times (18µs+0s) by Data::DPath::Path::_build__steps at line 98, avg 1µs/call | |||||
sub Data::DPath::Path::CORE:subst; # opcode | |||||
# spent 2µs within Data::DPath::Path::_steps which was called 2 times, avg 900ns/call:
# once (1µs+0s) by Data::DPath::Path::_build__steps at line 127
# once (700ns+0s) by Data::DPath::Context::_search at line 418 of lib/Data/DPath/Context.pm | |||||
# spent 700ns within Data::DPath::Path::give_references which was called:
# once (700ns+0s) by Data::DPath::Path::match at line 133 | |||||
# spent 7µs within Data::DPath::Path::path which was called:
# once (7µs+0s) by Data::DPath::Path::_build__steps at line 67 |