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 | BEGIN@11 | Data::DPath::Path::
1 | 1 | 1 | 4.24ms | 19.4ms | BEGIN@7 | Data::DPath::Path::
1 | 1 | 1 | 646µs | 3.77ms | BEGIN@8 | Data::DPath::Path::
4 | 1 | 1 | 448µs | 1.50ms | _build__steps | Data::DPath::Path::
16 | 1 | 1 | 92µs | 103µs | unescape | Data::DPath::Path::
4 | 1 | 1 | 87µs | 1.58ms | new | Data::DPath::Path::
46 | 3 | 1 | 80µs | 80µs | CORE:match (opcode) | Data::DPath::Path::
16 | 1 | 1 | 80µs | 99µs | quoted | Data::DPath::Path::
4 | 1 | 1 | 78µs | 4.46ms | match | Data::DPath::Path::
4 | 4 | 1 | 26µs | 4.49ms | op_match | Data::DPath::Path::
1 | 1 | 1 | 17µs | 71µs | BEGIN@4 | Data::DPath::Path::
1 | 1 | 1 | 15µs | 196µs | BEGIN@14 | Data::DPath::Path::
1 | 1 | 1 | 15µs | 149µs | BEGIN@21 | Data::DPath::Path::
1 | 1 | 1 | 13µs | 27µs | BEGIN@115 | Data::DPath::Path::
32 | 2 | 1 | 11µs | 11µs | CORE:subst (opcode) | Data::DPath::Path::
1 | 1 | 1 | 11µs | 16µs | BEGIN@5 | Data::DPath::Path::
1 | 1 | 1 | 11µs | 46.6ms | BEGIN@10 | Data::DPath::Path::
1 | 1 | 1 | 9µs | 551µs | BEGIN@9 | Data::DPath::Path::
1 | 1 | 1 | 7µs | 7µs | path (xsub) | Data::DPath::Path::
2 | 2 | 2 | 2µs | 2µs | _steps (xsub) | Data::DPath::Path::
1 | 1 | 1 | 700ns | 700ns | give_references (xsub) | Data::DPath::Path::
0 | 0 | 0 | 0s | 0s | unquote | Data::DPath::Path::
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 |