Filename | /home/lbr/project/petal-tiny/lib/Petal/Tiny.pm |
Statements | Executed 485626 statements in 519ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
14960 | 1 | 1 | 79.1ms | 187ms | tag2node | Petal::Tiny::
50 | 1 | 1 | 66.7ms | 269ms | xml2nodes | Petal::Tiny::
4430 | 1 | 1 | 66.1ms | 90.2ms | extract_attributes | Petal::Tiny::
4950 | 3 | 1 | 62.7ms | 73.2ms | resolve (recurses: max depth 1, inclusive time 16.5ms) | Petal::Tiny::
3080 | 2 | 1 | 51.3ms | 255ms | makeitso_node (recurses: max depth 11, inclusive time 1.66s) | Petal::Tiny::
2190 | 6 | 1 | 49.2ms | 131ms | resolve_expression | Petal::Tiny::
34910 | 7 | 1 | 47.5ms | 47.5ms | CORE:match (opcode) | Petal::Tiny::
2010 | 3 | 1 | 26.9ms | 255ms | makeitso (recurses: max depth 11, inclusive time 1.70s) | Petal::Tiny::
2860 | 1 | 1 | 25.7ms | 25.7ms | node2txt | Petal::Tiny::
26660 | 14 | 1 | 20.0ms | 20.0ms | CORE:subst (opcode) | Petal::Tiny::
3870 | 1 | 1 | 18.1ms | 19.2ms | _interpolate_dollar | Petal::Tiny::
8250 | 3 | 1 | 5.05ms | 5.05ms | reftype | Petal::Tiny::
2150 | 1 | 1 | 2.94ms | 3.44ms | xmlencode | Petal::Tiny::
1 | 1 | 1 | 2.75ms | 2.94ms | BEGIN@5 | Petal::Tiny::
210 | 2 | 1 | 539µs | 3.21ms | modifier_true | Petal::Tiny::
50 | 1 | 1 | 434µs | 524ms | process | Petal::Tiny::
50 | 1 | 1 | 409µs | 525µs | new | Petal::Tiny::
10 | 1 | 1 | 220µs | 1.11ms | _do_repeat | Petal::Tiny::
3 | 3 | 1 | 211µs | 211µs | CORE:regcomp (opcode) | Petal::Tiny::
80 | 1 | 1 | 174µs | 1.26ms | modifier_false | Petal::Tiny::
10 | 1 | 1 | 86µs | 86µs | _deep_copy | Petal::Tiny::
10 | 1 | 1 | 45µs | 449µs | __ANON__[lib/Petal/Tiny.pm:127] | Petal::Tiny::
20 | 1 | 1 | 14µs | 14µs | CORE:substcont (opcode) | Petal::Tiny::
1 | 1 | 1 | 11µs | 16µs | BEGIN@3 | Petal::Tiny::
1 | 1 | 1 | 8µs | 17µs | BEGIN@4 | Petal::Tiny::
1 | 1 | 1 | 2µs | 2µs | CORE:qr (opcode) | Petal::Tiny::
0 | 0 | 0 | 0s | 0s | modifier_string | Petal::Tiny::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package Petal::Tiny; | ||||
2 | |||||
3 | 2 | 15µs | 2 | 20µs | # spent 16µs (11+5) within Petal::Tiny::BEGIN@3 which was called:
# once (11µs+5µs) by main::BEGIN@2 at line 3 # spent 16µs making 1 call to Petal::Tiny::BEGIN@3
# spent 5µs making 1 call to warnings::import |
4 | 2 | 14µs | 2 | 26µs | # spent 17µs (8+9) within Petal::Tiny::BEGIN@4 which was called:
# once (8µs+9µs) by main::BEGIN@2 at line 4 # spent 17µs making 1 call to Petal::Tiny::BEGIN@4
# spent 9µs making 1 call to strict::import |
5 | 2 | 2.13ms | 2 | 2.97ms | # spent 2.94ms (2.75+183µs) within Petal::Tiny::BEGIN@5 which was called:
# once (2.75ms+183µs) by main::BEGIN@2 at line 5 # spent 2.94ms making 1 call to Petal::Tiny::BEGIN@5
# spent 35µs making 1 call to Exporter::import |
6 | |||||
7 | # REX/Perl 1.0 | ||||
8 | # Robert D. Cameron "REX: XML Shallow Parsing with Regular Expressions", | ||||
9 | # Technical Report TR 1998-17, School of Computing Science, Simon Fraser | ||||
10 | # University, November, 1998. | ||||
11 | # Copyright (c) 1998, Robert D. Cameron. | ||||
12 | # The following code may be freely used and distributed provided that | ||||
13 | # this copyright and citation notice remains intact and that modifications | ||||
14 | # or additions are clearly identified. | ||||
15 | 1 | 400ns | my $TextSE = "[^<]+"; | ||
16 | 1 | 100ns | my $UntilHyphen = "[^-]*-"; | ||
17 | 1 | 800ns | my $Until2Hyphens = "$UntilHyphen(?:[^-]$UntilHyphen)*-"; | ||
18 | 1 | 400ns | my $CommentCE = "$Until2Hyphens>?"; | ||
19 | 1 | 200ns | my $UntilRSBs = "[^\\]]*](?:[^\\]]+])*]+"; | ||
20 | 1 | 500ns | my $CDATA_CE = "$UntilRSBs(?:[^\\]>]$UntilRSBs)*>"; | ||
21 | 1 | 200ns | my $S = "[ \\n\\t\\r]+"; | ||
22 | 1 | 100ns | my $NameStrt = "[A-Za-z_:]|[^\\x00-\\x7F]"; | ||
23 | 1 | 100ns | my $NameChar = "[A-Za-z0-9_:.-]|[^\\x00-\\x7F]"; | ||
24 | 1 | 600ns | my $Name = "(?:$NameStrt)(?:$NameChar)*"; | ||
25 | 1 | 100ns | my $QuoteSE = "\"[^\"]*\"|'[^']*'"; | ||
26 | 1 | 2µs | my $DT_IdentSE = "$S$Name(?:$S(?:$Name|$QuoteSE))*"; | ||
27 | 1 | 600ns | my $MarkupDeclCE = "(?:[^\\]\"'><]+|$QuoteSE)*>"; | ||
28 | 1 | 100ns | my $S1 = "[\\n\\r\\t ]"; | ||
29 | 1 | 100ns | my $UntilQMs = "[^?]*\\?+"; | ||
30 | 1 | 700ns | my $PI_Tail = "\\?>|$S1$UntilQMs(?:[^>?]$UntilQMs)*>"; | ||
31 | 1 | 2µs | my $DT_ItemSE = "<(?:!(?:--$Until2Hyphens>|[^-]$MarkupDeclCE)|\\?$Name(?:$PI_Tail))|%$Name;|$S"; | ||
32 | 1 | 1µs | my $DocTypeCE = "$DT_IdentSE(?:$S)?(?:\\[(?:$DT_ItemSE)*](?:$S)?)?>?"; | ||
33 | 1 | 2µs | my $DeclCE = "--(?:$CommentCE)?|\\[CDATA\\[(?:$CDATA_CE)?|DOCTYPE(?:$DocTypeCE)?"; | ||
34 | 1 | 600ns | my $PI_CE = "$Name(?:$PI_Tail)?"; | ||
35 | 1 | 400ns | my $EndTagCE = "$Name(?:$S)?>?"; | ||
36 | 1 | 200ns | my $AttValSE = "\"[^<\"]*\"|'[^<']*'"; | ||
37 | 1 | 1µs | my $ElemTagCE = "$Name(?:$S$Name(?:$S)?=(?:$S)?(?:$AttValSE))*(?:$S)?/?>?"; | ||
38 | 1 | 1µs | my $ElemTagCE_Mod = "$S($Name)(?:$S)?=(?:$S)?($AttValSE)"; | ||
39 | 1 | 1µs | my $MarkupSPE = "<(?:!(?:$DeclCE)?|\\?(?:$PI_CE)?|/(?:$EndTagCE)?|(?:$ElemTagCE)?)"; | ||
40 | 1 | 3µs | my $XML_SPE = "$TextSE|$MarkupSPE"; | ||
41 | # REX END - thank you Robert for this 26 line XML parser - awesome ... | ||||
42 | |||||
43 | 1 | 43µs | 2 | 34µs | my $ATTR_RE = qr /$ElemTagCE_Mod/; # spent 32µs making 1 call to Petal::Tiny::CORE:regcomp
# spent 2µs making 1 call to Petal::Tiny::CORE:qr |
44 | |||||
45 | 1 | 200ns | my $DEFAULT_NS = 'petal'; | ||
46 | |||||
47 | # spent 525µs (409+117) within Petal::Tiny::new which was called 50 times, avg 11µs/call:
# 50 times (409µs+117µs) by main::RUNTIME at line 59 of opt.pl, avg 11µs/call | ||||
48 | 50 | 17µs | my $class = shift; | ||
49 | 50 | 19µs | $class = ref $class || $class; | ||
50 | 50 | 142µs | my $thing = shift; | ||
51 | 50 | 42µs | my $self = bless {}, $class; | ||
52 | 50 | 244µs | 50 | 116µs | if (defined $thing and $thing =~ /(\<|\n|\>)/) { # spent 116µs making 50 calls to Petal::Tiny::CORE:match, avg 2µs/call |
53 | $self->{xmldata} = $thing; | ||||
54 | } | ||||
55 | elsif (defined $thing) { | ||||
56 | open my $xmldatafile, "<", $thing or die "cannot read open $thing"; | ||||
57 | $self->{xmldata} = join '', <$xmldatafile>; | ||||
58 | close $xmldatafile; | ||||
59 | } | ||||
60 | 50 | 77µs | return $self; | ||
61 | } | ||||
62 | |||||
63 | |||||
64 | # spent 524ms (434µs+524) within Petal::Tiny::process which was called 50 times, avg 10.5ms/call:
# 50 times (434µs+524ms) by main::RUNTIME at line 60 of opt.pl, avg 10.5ms/call | ||||
65 | 50 | 10µs | my $self = shift; | ||
66 | 50 | 121µs | my $context = { @_ }; | ||
67 | 50 | 20µs | my $data = $self->{xmldata}; | ||
68 | 50 | 11µs | defined $data or return; # empty data, empty result. | ||
69 | 50 | 236µs | 100 | 524ms | return $self->makeitso($self->xml2nodes($data), $context); # earl grey. hot. # spent 269ms making 50 calls to Petal::Tiny::xml2nodes, avg 5.38ms/call
# spent 255ms making 50 calls to Petal::Tiny::makeitso, avg 5.10ms/call |
70 | } | ||||
71 | |||||
72 | # spent 269ms (66.7+202) within Petal::Tiny::xml2nodes which was called 50 times, avg 5.38ms/call:
# 50 times (66.7ms+202ms) by Petal::Tiny::process at line 69, avg 5.38ms/call | ||||
73 | 50 | 19µs | my ($self, $xml) = @_; | ||
74 | |||||
75 | 50 | 15.7ms | 51 | 14.8ms | my @flat = ( $xml =~ /$XML_SPE/og ); # spent 14.6ms making 50 calls to Petal::Tiny::CORE:match, avg 292µs/call
# spent 178µs making 1 call to Petal::Tiny::CORE:regcomp |
76 | |||||
77 | 50 | 78µs | my $top = { _kids => [], _ns => $DEFAULT_NS }; | ||
78 | 50 | 18µs | my @nest = ( $top ); | ||
79 | 50 | 32µs | for my $tag (@flat) { | ||
80 | 14960 | 9.35ms | 14960 | 187ms | my $node = tag2node($tag, $nest[-1]{_ns}); # if ns is not explicitly set, inherit parent ns # spent 187ms making 14960 calls to Petal::Tiny::tag2node, avg 13µs/call |
81 | |||||
82 | 14960 | 7.28ms | if ($node->{_close}) { | ||
83 | 3590 | 609µs | my $open = pop @nest; | ||
84 | 3590 | 883µs | confess "unbalanced close-tag '</$node->{_tag}>'" if $open == $top; | ||
85 | 3590 | 1.82ms | confess "wrong close-tag '</$node->{_tag}>' for '<$open->{_tag}>'" if lc($node->{_tag}) ne lc($open->{_tag}); | ||
86 | } | ||||
87 | else { | ||||
88 | 11370 | 3.80ms | push @{ $nest[-1]{_kids} }, $node; | ||
89 | 11370 | 3.00ms | push @nest, $node unless ($node->{_simple} or $node->{_selfclose}); | ||
90 | } | ||||
91 | } | ||||
92 | 50 | 20µs | confess "Unbalanced tree, more open than close nodes" if @nest > 1; | ||
93 | |||||
94 | 50 | 44µs | my @nodes = @{ $top->{_kids} }; | ||
95 | |||||
96 | 50 | 636µs | return \@nodes; | ||
97 | } | ||||
98 | |||||
99 | # spent 255ms (26.9+228) within Petal::Tiny::makeitso which was called 2010 times, avg 127µs/call:
# 1930 times (26.3ms+-26.3ms) by Petal::Tiny::makeitso_node at line 232, avg 0s/call
# 50 times (260µs+255ms) by Petal::Tiny::process at line 69, avg 5.10ms/call
# 30 times (378µs+-378µs) by Petal::Tiny::makeitso_node at line 227, avg 0s/call | ||||
100 | 2010 | 417µs | my ($self, $nodes, $context) = @_; | ||
101 | |||||
102 | 2010 | 1.15ms | return "" unless @$nodes; | ||
103 | |||||
104 | 1240 | 132µs | my @res; | ||
105 | 1240 | 472µs | for my $node (@$nodes) { | ||
106 | 6940 | 6.55ms | 3870 | 19.2ms | if ($node->{_simple}) { # spent 19.2ms making 3870 calls to Petal::Tiny::_interpolate_dollar, avg 5µs/call |
107 | push @res, $self->_interpolate_dollar($context, $node->{_elem}, 'resolve_expression'); | ||||
108 | } | ||||
109 | else { | ||||
110 | 3070 | 2.47ms | 3070 | 255ms | push @res, $self->makeitso_node($node, $context); # spent 1.91s making 3070 calls to Petal::Tiny::makeitso_node, avg 623µs/call, recursion: max depth 11, sum of overlapping time 1.66s |
111 | } | ||||
112 | } | ||||
113 | |||||
114 | 1240 | 7.93ms | return join "", @res; | ||
115 | } | ||||
116 | |||||
117 | # spent 19.2ms (18.1+1.09) within Petal::Tiny::_interpolate_dollar which was called 3870 times, avg 5µs/call:
# 3870 times (18.1ms+1.09ms) by Petal::Tiny::makeitso at line 106, avg 5µs/call | ||||
118 | 3870 | 1.07ms | my ($self, $context, $string, $method) = @_; | ||
119 | |||||
120 | 3870 | 9.99ms | 3870 | 596µs | if ($string =~ /\$/) { # spent 596µs making 3870 calls to Petal::Tiny::CORE:match, avg 154ns/call |
121 | # spent 449µs (45+404) within Petal::Tiny::__ANON__[lib/Petal/Tiny.pm:127] which was called 10 times, avg 45µs/call:
# 10 times (45µs+404µs) by Petal::Tiny::_interpolate_dollar at line 129, avg 45µs/call | ||||
122 | 10 | 6µs | my $what = shift; | ||
123 | 10 | 16µs | 10 | 404µs | my $res = $self->$method($what, $context); # spent 404µs making 10 calls to Petal::Tiny::resolve_expression, avg 40µs/call |
124 | 10 | 20µs | return $res if defined $res; | ||
125 | carp "'$what' in \$-interpolation resolved to undef"; | ||||
126 | return ""; | ||||
127 | 10 | 31µs | }; | ||
128 | |||||
129 | 20 | 5.43ms | 40 | 490µs | $string =~ s/(?<!\$) \$\{ ( [^{}]+ ) \} / $subst->($1) /xegi; # spent 449µs making 10 calls to Petal::Tiny::__ANON__[lib/Petal/Tiny.pm:127], avg 45µs/call
# spent 26µs making 10 calls to Petal::Tiny::CORE:subst, avg 3µs/call
# spent 14µs making 20 calls to Petal::Tiny::CORE:substcont, avg 700ns/call |
130 | 10 | 13µs | 10 | 2µs | $string =~ s/(?<!\$) \$\{? ( [a-z0-9-\/:_]+ ) \}? / $subst->($1) /xegi; # spent 2µs making 10 calls to Petal::Tiny::CORE:subst, avg 210ns/call |
131 | 10 | 39µs | 10 | 1µs | $string =~ s/\$\$/\$/g; # spent 1µs making 10 calls to Petal::Tiny::CORE:subst, avg 130ns/call |
132 | } | ||||
133 | 3870 | 9.12ms | return $string; | ||
134 | } | ||||
135 | |||||
136 | # spent 86µs within Petal::Tiny::_deep_copy which was called 10 times, avg 9µs/call:
# 10 times (86µs+0s) by Petal::Tiny::_do_repeat at line 263, avg 9µs/call | ||||
137 | 10 | 3µs | my $node = shift; | ||
138 | 10 | 48µs | my %copy = %$node; | ||
139 | 10 | 3µs | my @kids; | ||
140 | 10 | 12µs | for my $kid (@{ $node->{_kids} }) { | ||
141 | push @kids, _deep_copy($kid); | ||||
142 | } | ||||
143 | 10 | 6µs | $copy{_kids} = \@kids; | ||
144 | 10 | 19µs | return \%copy; | ||
145 | } | ||||
146 | |||||
147 | sub makeitso_node { | ||||
148 | 3080 | 608µs | my ($self, $node, $context) = @_; | ||
149 | |||||
150 | 3080 | 953µs | my $TAL = $node->{_ns}; | ||
151 | |||||
152 | 3080 | 452µs | my $STOP_RECURSE = 0; | ||
153 | |||||
154 | 3080 | 904µs | if ($node->{_has_tal}) { | ||
155 | 1690 | 530µs | $node->{_change} = 1; | ||
156 | |||||
157 | 1690 | 983µs | if (defined( my $stuff = delete $node->{"$TAL:on-error"} )) { | ||
158 | my $nodeCopy = { %$node }; | ||||
159 | my $res = eval { $self->makeitso_node($node, $context); }; | ||||
160 | if ($@) { | ||||
161 | for my $k (keys %$nodeCopy) { delete $nodeCopy->{$k} if $k =~ /^$TAL:/ } | ||||
162 | delete $nodeCopy->{_selfclose}; | ||||
163 | $nodeCopy->{_contents} = $self->resolve_expression($stuff, $context); | ||||
164 | return node2txt($nodeCopy); | ||||
165 | } | ||||
166 | return $res; | ||||
167 | } | ||||
168 | |||||
169 | 1690 | 4.47ms | $context = { %$context }; | ||
170 | |||||
171 | 1690 | 866µs | if (defined( my $stuff = delete $node->{"$TAL:define"} )) { | ||
172 | for my $def (split /;(?!;)/, $stuff) { | ||||
173 | my ($symbol, $expression) = split ' ', $def, 2; | ||||
174 | $context->{$symbol} = $self->resolve_expression($expression, $context); | ||||
175 | } | ||||
176 | } | ||||
177 | |||||
178 | 1690 | 963µs | if (defined( my $stuff = delete $node->{"$TAL:condition"} )) { | ||
179 | 210 | 155µs | for my $cond (split /;(?!;)/, $stuff) { | ||
180 | 210 | 500µs | 210 | 21.8ms | return '' unless $self->resolve_expression($cond, $context); # spent 21.8ms making 210 calls to Petal::Tiny::resolve_expression, avg 104µs/call |
181 | } | ||||
182 | } | ||||
183 | |||||
184 | 1560 | 836µs | if (defined( my $stuff = delete $node->{"$TAL:repeat"} )) { | ||
185 | 10 | 15µs | my @loops = split /;(?!;)/, $stuff; | ||
186 | 10 | 3µs | my $count = 0; | ||
187 | 10 | 50µs | 10 | 1.11ms | return join "", $self->_do_repeat(\$count, 1, \@loops, $node, $context); # spent 1.11ms making 10 calls to Petal::Tiny::_do_repeat, avg 111µs/call |
188 | } | ||||
189 | |||||
190 | 1550 | 1.08ms | if (defined( my $stuff = delete $node->{"$TAL:content"} )) { | ||
191 | 930 | 707µs | 930 | 42.2ms | my $res = $self->resolve_expression($stuff, $context); # spent 42.2ms making 930 calls to Petal::Tiny::resolve_expression, avg 45µs/call |
192 | 930 | 358µs | $node->{_contents} = defined $res ? $res : ""; | ||
193 | 930 | 421µs | delete $node->{_selfclose}; | ||
194 | |||||
195 | # set the stop recurse flag so that if content contains $foo and $bar, | ||||
196 | # those aren't interpolated as variables. | ||||
197 | 930 | 281µs | $STOP_RECURSE = 1; | ||
198 | } | ||||
199 | |||||
200 | 1550 | 749µs | if (defined( my $stuff = delete $node->{"$TAL:replace"} )) { | ||
201 | 50 | 39µs | 50 | 1.98ms | my $res = $self->resolve_expression($stuff, $context); # spent 1.98ms making 50 calls to Petal::Tiny::resolve_expression, avg 40µs/call |
202 | 50 | 113µs | return defined $res ? $res : ''; | ||
203 | } | ||||
204 | |||||
205 | 1500 | 1.15ms | if (defined( my $stuff = delete $node->{"$TAL:attributes"} )) { | ||
206 | 780 | 928µs | for my $att (split /;(?!;)/, $stuff) { | ||
207 | 980 | 780µs | my ($symbol, $expression) = split ' ', $att, 2; | ||
208 | 980 | 1.69ms | 980 | 516µs | my $add = ($symbol =~ s/^\+//); # spent 516µs making 980 calls to Petal::Tiny::CORE:subst, avg 526ns/call |
209 | 980 | 722µs | 980 | 64.8ms | my $new = $self->resolve_expression($expression, $context); # spent 64.8ms making 980 calls to Petal::Tiny::resolve_expression, avg 66µs/call |
210 | 980 | 749µs | if (defined $new) { | ||
211 | 380 | 58µs | if ($add) { | ||
212 | 70 | 36µs | my $old = $node->{$symbol}; | ||
213 | 70 | 26µs | $old = "" unless defined $old; | ||
214 | 70 | 38µs | $new = $old . $new; | ||
215 | } | ||||
216 | 380 | 222µs | $node->{$symbol} = $new; | ||
217 | } | ||||
218 | else { | ||||
219 | 600 | 137µs | delete $node->{$symbol} unless $add; | ||
220 | } | ||||
221 | } | ||||
222 | } | ||||
223 | |||||
224 | 1500 | 1.15ms | if (defined(my $stuff = delete $node->{"$TAL:omit-tag"})) { | ||
225 | 30 | 10µs | if ($stuff eq '' or $self->resolve_expression($stuff, $context)) { | ||
226 | 30 | 6µs | return $node->{_contents} if $STOP_RECURSE; | ||
227 | 30 | 105µs | 30 | 0s | return $self->makeitso($node->{_kids}, $context); # spent 177ms making 30 calls to Petal::Tiny::makeitso, avg 5.90ms/call, recursion: max depth 4, sum of overlapping time 177ms |
228 | } | ||||
229 | } | ||||
230 | } | ||||
231 | |||||
232 | 2860 | 1.98ms | 1930 | 0s | unless ($STOP_RECURSE) { # spent 1.53s making 1930 calls to Petal::Tiny::makeitso, avg 791µs/call, recursion: max depth 11, sum of overlapping time 1.53s |
233 | $node->{_contents} = $self->makeitso($node->{_kids}, $context); | ||||
234 | } | ||||
235 | 2860 | 10.2ms | 2860 | 25.7ms | return node2txt($node); # spent 25.7ms making 2860 calls to Petal::Tiny::node2txt, avg 9µs/call |
236 | } | ||||
237 | |||||
238 | # spent 1.11ms (220µs+886µs) within Petal::Tiny::_do_repeat which was called 10 times, avg 111µs/call:
# 10 times (220µs+886µs) by Petal::Tiny::makeitso_node at line 187, avg 111µs/call | ||||
239 | 10 | 6µs | my ($self, $count, $last, $loops_ref, $node, $context) = @_; | ||
240 | 10 | 7µs | my @loops = @$loops_ref; | ||
241 | 10 | 4µs | my $stuff = shift @loops; | ||
242 | 10 | 12µs | my ($symbol, $expression) = split ' ', $stuff, 2; | ||
243 | 10 | 11µs | 10 | 258µs | my $array = $self->resolve_expression($expression, $context); # spent 258µs making 10 calls to Petal::Tiny::resolve_expression, avg 26µs/call |
244 | 10 | 7µs | $array = [ $array ] unless ref $array; # we don't judge | ||
245 | 10 | 2µs | my @result; | ||
246 | 10 | 15µs | foreach my $idx (0 .. $#$array) { | ||
247 | 10 | 3µs | my $item = $array->[$idx]; | ||
248 | 10 | 8µs | $context->{$symbol} = $item; | ||
249 | 10 | 17µs | if (@loops) { | ||
250 | push @result, $self->_do_repeat($count, $last && $idx == $#$array, \@loops, $node, $context); | ||||
251 | } | ||||
252 | else { | ||||
253 | 10 | 5µs | $$count++; | ||
254 | 10 | 9µs | $context->{repeat} = {}; | ||
255 | 10 | 8µs | $context->{repeat}->{index} = $$count; | ||
256 | 10 | 5µs | $context->{repeat}->{number} = $$count; | ||
257 | 10 | 11µs | $context->{repeat}->{even} = $$count%2 ? 0 : 1; | ||
258 | 10 | 7µs | $context->{repeat}->{odd} = $$count%2 ? 1 : 0; | ||
259 | 10 | 7µs | $context->{repeat}->{start} = $$count == 1 ? 1 : 0; | ||
260 | 10 | 8µs | $context->{repeat}->{end} = $last && $idx == $#$array ? 1 : 0; | ||
261 | 10 | 11µs | $context->{repeat}->{inner} = $context->{repeat}->{start} || $context->{repeat}->{end} ? 0 : 1; | ||
262 | |||||
263 | 10 | 22µs | 20 | 86µs | push @result, $self->makeitso_node(_deep_copy($node), $context); # spent 86µs making 10 calls to Petal::Tiny::_deep_copy, avg 9µs/call
# spent 542µs making 10 calls to Petal::Tiny::makeitso_node, avg 54µs/call, recursion: max depth 4, sum of overlapping time 542µs |
264 | } | ||||
265 | } | ||||
266 | 10 | 22µs | return @result; | ||
267 | } | ||||
268 | |||||
269 | |||||
270 | # spent 131ms (49.2+82.3) within Petal::Tiny::resolve_expression which was called 2190 times, avg 60µs/call:
# 980 times (23.8ms+41.1ms) by Petal::Tiny::makeitso_node at line 209, avg 66µs/call
# 930 times (8.70ms+33.5ms) by Petal::Tiny::makeitso_node at line 191, avg 45µs/call
# 210 times (16.1ms+5.75ms) by Petal::Tiny::makeitso_node at line 180, avg 104µs/call
# 50 times (463µs+1.52ms) by Petal::Tiny::makeitso_node at line 201, avg 40µs/call
# 10 times (95µs+309µs) by Petal::Tiny::__ANON__[lib/Petal/Tiny.pm:127] at line 123, avg 40µs/call
# 10 times (99µs+159µs) by Petal::Tiny::_do_repeat at line 243, avg 26µs/call | ||||
271 | 2190 | 550µs | my ($self, $expr, $context) = @_; | ||
272 | |||||
273 | 2190 | 311µs | $expr = "" unless defined $expr; | ||
274 | 2190 | 3.57ms | 2190 | 1.33ms | $expr =~ s/[\n\r]/ /g; # spent 1.33ms making 2190 calls to Petal::Tiny::CORE:subst, avg 606ns/call |
275 | 2190 | 3.02ms | 2190 | 943µs | $expr =~ s/^\s+//; # spent 943µs making 2190 calls to Petal::Tiny::CORE:subst, avg 430ns/call |
276 | 2190 | 8.06ms | 2190 | 1.44ms | $expr =~ s/\s+$//; # spent 1.44ms making 2190 calls to Petal::Tiny::CORE:subst, avg 658ns/call |
277 | |||||
278 | 2190 | 3.00ms | 2190 | 1.06ms | $expr =~ s/([;\$])\1/$1/g; # spent 1.06ms making 2190 calls to Petal::Tiny::CORE:subst, avg 484ns/call |
279 | 2190 | 397µs | $expr eq 'nothing' and return undef; | ||
280 | 2190 | 17.3ms | 2190 | 430µs | $expr =~ s/^fresh\s+//; # spent 430µs making 2190 calls to Petal::Tiny::CORE:subst, avg 197ns/call |
281 | 2190 | 7.08ms | 2190 | 435µs | my $structure = ($expr =~ s/^structure\s+//); # spent 435µs making 2190 calls to Petal::Tiny::CORE:subst, avg 199ns/call |
282 | 2190 | 1.63ms | 2190 | 73.2ms | my $resolved = $self->resolve($expr, $context); # spent 73.2ms making 2190 calls to Petal::Tiny::resolve, avg 33µs/call |
283 | 2190 | 13.1ms | 2150 | 3.44ms | return $structure ? $resolved : xmlencode($resolved); # spent 3.44ms making 2150 calls to Petal::Tiny::xmlencode, avg 2µs/call |
284 | } | ||||
285 | |||||
286 | # spent 5.05ms within Petal::Tiny::reftype which was called 8250 times, avg 612ns/call:
# 4120 times (2.66ms+0s) by Petal::Tiny::resolve at line 313, avg 647ns/call
# 4120 times (2.38ms+0s) by Petal::Tiny::resolve at line 333, avg 578ns/call
# 10 times (6µs+0s) by Petal::Tiny::modifier_true at line 367, avg 560ns/call | ||||
287 | 8250 | 1.41ms | my ($self, $obj) = @_; | ||
288 | 8250 | 13.1ms | return ref $obj; | ||
289 | } | ||||
290 | |||||
291 | # spent 73.2ms (62.7+10.5) within Petal::Tiny::resolve which was called 4950 times, avg 15µs/call:
# 2550 times (11.5ms+-11.5ms) by Petal::Tiny::resolve at line 307, avg 0s/call
# 2190 times (48.9ms+24.3ms) by Petal::Tiny::resolve_expression at line 282, avg 33µs/call
# 210 times (2.28ms+-2.28ms) by Petal::Tiny::modifier_true at line 366, avg 0s/call | ||||
292 | 4950 | 1.18ms | my ($self, $expr, $context) = @_; | ||
293 | 4950 | 10.3ms | 4950 | 855µs | $expr =~ /:(?!pattern)/ and do { # XXX what is :pattern? # spent 855µs making 4950 calls to Petal::Tiny::CORE:match, avg 173ns/call |
294 | 210 | 250µs | my ($mod, $expr) = split /:(?!pattern)\s*/, $expr, 2; | ||
295 | 210 | 546µs | 210 | 205µs | my $meth = $self->can("modifier_$mod"); # spent 205µs making 210 calls to UNIVERSAL::can, avg 977ns/call |
296 | 210 | 425µs | 210 | 3.39ms | return $self->$meth($expr, $context) if $meth; # spent 2.13ms making 130 calls to Petal::Tiny::modifier_true, avg 16µs/call
# spent 1.26ms making 80 calls to Petal::Tiny::modifier_false, avg 16µs/call |
297 | confess "unknown modifier $mod"; | ||||
298 | }; | ||||
299 | 4740 | 9.41ms | 4740 | 2.46ms | return $expr if $expr =~ s/^--//; # spent 2.46ms making 4740 calls to Petal::Tiny::CORE:subst, avg 520ns/call |
300 | |||||
301 | 2210 | 2.13ms | my ($what, @args) = split ' ', $expr; | ||
302 | 2210 | 277µs | defined $what or return; | ||
303 | |||||
304 | 2210 | 1.63ms | my (@path) = split /\//, $what; | ||
305 | 2210 | 304µs | my @resolved; | ||
306 | 2210 | 376µs | my $obj = $context; | ||
307 | 4760 | 3.89ms | 2550 | 0s | @args = map { $self->resolve($_, $context) } @args; # spent 13.8ms making 2550 calls to Petal::Tiny::resolve, avg 5µs/call, recursion: max depth 1, sum of overlapping time 13.8ms |
308 | 2210 | 637µs | while (@path) { | ||
309 | 4120 | 837µs | my $attribute_or_method = shift @path; | ||
310 | 4120 | 962µs | push @resolved, $attribute_or_method; | ||
311 | 4120 | 1.30ms | my $resolved = join '/', @resolved; | ||
312 | 4120 | 520µs | $obj or confess "cannot fetch $what, because $resolved is undefined"; | ||
313 | 4120 | 2.42ms | 4120 | 2.66ms | my $reftype = $self->reftype($obj); # spent 2.66ms making 4120 calls to Petal::Tiny::reftype, avg 647ns/call |
314 | 4120 | 469µs | $reftype or confess "cannot fetch $what, because $resolved is not a reference"; | ||
315 | |||||
316 | 4120 | 1.86ms | if ($reftype eq 'ARRAY') { | ||
317 | $obj = $obj->[$attribute_or_method]; | ||||
318 | } | ||||
319 | elsif ($reftype eq 'HASH') { | ||||
320 | $obj = $obj->{$attribute_or_method}; | ||||
321 | } | ||||
322 | elsif ($obj->can($attribute_or_method)) { | ||||
323 | if (@path) { | ||||
324 | $obj = $obj->$attribute_or_method(); | ||||
325 | } | ||||
326 | else { | ||||
327 | $obj = $obj->$attribute_or_method(@args); | ||||
328 | @args = (); | ||||
329 | } | ||||
330 | } | ||||
331 | |||||
332 | # now, check if what we found was a code-ref | ||||
333 | 4120 | 2.14ms | 4120 | 2.38ms | $reftype = $self->reftype($obj); # spent 2.38ms making 4120 calls to Petal::Tiny::reftype, avg 578ns/call |
334 | 4120 | 862µs | if ($reftype eq 'CODE') { | ||
335 | 1880 | 504µs | if (@path) { | ||
336 | $obj = $obj->(); | ||||
337 | } | ||||
338 | else { | ||||
339 | 1880 | 1.48ms | 1880 | 1.26ms | $obj = $obj->(@args); # spent 478µs making 570 calls to main::__ANON__[opt.pl:19], avg 838ns/call
# spent 228µs making 450 calls to main::__ANON__[opt.pl:17], avg 506ns/call
# spent 213µs making 370 calls to main::__ANON__[opt.pl:18], avg 575ns/call
# spent 101µs making 180 calls to main::__ANON__[opt.pl:16], avg 561ns/call
# spent 42µs making 80 calls to main::__ANON__[opt.pl:14], avg 530ns/call
# spent 39µs making 60 calls to main::__ANON__[opt.pl:13], avg 657ns/call
# spent 36µs making 50 calls to main::__ANON__[opt.pl:12], avg 720ns/call
# spent 32µs making 40 calls to main::__ANON__[opt.pl:15], avg 805ns/call
# spent 23µs making 30 calls to main::__ANON__[opt.pl:11], avg 777ns/call
# spent 20µs making 10 calls to main::__ANON__[opt.pl:8], avg 2µs/call
# spent 19µs making 20 calls to main::__ANON__[opt.pl:10], avg 965ns/call
# spent 13µs making 10 calls to main::__ANON__[opt.pl:9], avg 1µs/call
# spent 10µs making 10 calls to main::__ANON__[opt.pl:25], avg 1µs/call |
340 | 1880 | 658µs | @args = (); | ||
341 | } | ||||
342 | } | ||||
343 | |||||
344 | # if we're done with @path and there's a single arg, use it to look up in array/hash | ||||
345 | 4120 | 926µs | if (not @path and @args == 1) { | ||
346 | $reftype = $self->reftype($obj); | ||||
347 | |||||
348 | if ($reftype eq 'ARRAY') { | ||||
349 | $obj = $obj->[ $args[0] ]; | ||||
350 | last; | ||||
351 | } | ||||
352 | elsif ($reftype eq 'HASH') { | ||||
353 | $obj = $obj->{ $args[0] }; | ||||
354 | last; | ||||
355 | } | ||||
356 | } | ||||
357 | |||||
358 | 4120 | 1.82ms | not @path and @args and confess "cannot resolve expression $expr"; | ||
359 | } | ||||
360 | 2210 | 3.11ms | return $obj; | ||
361 | } | ||||
362 | |||||
363 | |||||
364 | sub modifier_true { | ||||
365 | 210 | 58µs | my ($self, $expr, $context) = @_; | ||
366 | 210 | 155µs | 210 | 0s | my $arg = $self->resolve($expr, $context); # spent 2.67ms making 210 calls to Petal::Tiny::resolve, avg 13µs/call, recursion: max depth 1, sum of overlapping time 2.67ms |
367 | 210 | 52µs | 10 | 6µs | ref $arg and $self->reftype($arg) eq 'ARRAY' and return scalar @$arg; # spent 6µs making 10 calls to Petal::Tiny::reftype, avg 560ns/call |
368 | 200 | 241µs | return $arg ? 1 : 0; | ||
369 | } | ||||
370 | |||||
371 | |||||
372 | # spent 1.26ms (174µs+1.09) within Petal::Tiny::modifier_false which was called 80 times, avg 16µs/call:
# 80 times (174µs+1.09ms) by Petal::Tiny::resolve at line 296, avg 16µs/call | ||||
373 | 80 | 14µs | my $self = shift; | ||
374 | 80 | 155µs | 80 | 1.09ms | return not $self->modifier_true(@_); # spent 1.09ms making 80 calls to Petal::Tiny::modifier_true, avg 14µs/call |
375 | } | ||||
376 | |||||
377 | |||||
378 | sub modifier_string { | ||||
379 | my ($self, $string, $context) = @_; | ||||
380 | $string = $self->_interpolate_dollar($context, $string, 'resolve'); | ||||
381 | return $string; | ||||
382 | } | ||||
383 | |||||
384 | |||||
385 | # spent 25.7ms within Petal::Tiny::node2txt which was called 2860 times, avg 9µs/call:
# 2860 times (25.7ms+0s) by Petal::Tiny::makeitso_node at line 235, avg 9µs/call | ||||
386 | 2860 | 449µs | my $node = shift; | ||
387 | |||||
388 | 2860 | 575µs | return $node unless ref $node eq 'HASH'; # handle textnodes introduced in makeitso_node | ||
389 | 2860 | 567µs | return $node->{_elem} if $node->{_simple}; | ||
390 | |||||
391 | 2860 | 796µs | delete $node->{_ns}; | ||
392 | 2860 | 643µs | delete $node->{_has_tal}; | ||
393 | 2860 | 4.21ms | delete $node->{_kids}; | ||
394 | |||||
395 | 2860 | 719µs | my $change = delete $node->{_change}; | ||
396 | 2860 | 940µs | my $elem = delete $node->{_elem}; | ||
397 | 2860 | 902µs | my $tag = delete $node->{_tag}; | ||
398 | 2860 | 760µs | my $close = delete $node->{_selfclose}; | ||
399 | 2860 | 719µs | my $quotes = delete $node->{_quotes}; | ||
400 | 2860 | 848µs | my $contents = delete $node->{_contents}; | ||
401 | 9440 | 7.30ms | my $att = join ' ', map { my $q = $quotes->{$_} || '"'; qq|$_=$q$node->{$_}$q| } keys %$node; | ||
402 | |||||
403 | 2860 | 1.71ms | if ($close) { | ||
404 | return $change ? ($att ? "<$tag $att />" : "<$tag />") : $elem; | ||||
405 | } | ||||
406 | |||||
407 | 2140 | 1.06ms | my $start = $change ? ($att ? "<$tag $att>" : "<$tag>") : $elem; | ||
408 | 2140 | 844µs | my $end = "</$tag>"; | ||
409 | |||||
410 | 2140 | 294µs | $contents = "" unless defined $contents; | ||
411 | |||||
412 | 2140 | 8.54ms | return $start . $contents . $end; | ||
413 | } | ||||
414 | |||||
415 | # spent 187ms (79.1+108) within Petal::Tiny::tag2node which was called 14960 times, avg 13µs/call:
# 14960 times (79.1ms+108ms) by Petal::Tiny::xml2nodes at line 80, avg 13µs/call | ||||
416 | 14960 | 3.22ms | my ($elem, $ns) = @_; | ||
417 | |||||
418 | 14960 | 51.2ms | 14960 | 18.1ms | if ($elem =~ m,^<(/?)([A-Za-z0-9][A-Za-z0-9_:-]*).*?(/?)>$,) { # spent 18.1ms making 14960 calls to Petal::Tiny::CORE:match, avg 1µs/call |
419 | 8020 | 5.43ms | my ($has_close, $tag, $has_self_close) = ($1,$2,$3); | ||
420 | |||||
421 | 8020 | 10.4ms | return { _tag => $tag, _close => 1 } if $has_close; # don't waste any time on </...> nodes, they're just for book-keeping | ||
422 | |||||
423 | 4430 | 6.43ms | 4430 | 90.2ms | my %node = extract_attributes($elem); # spent 90.2ms making 4430 calls to Petal::Tiny::extract_attributes, avg 20µs/call |
424 | 4430 | 1.37ms | $node{_ns} ||= $ns; | ||
425 | |||||
426 | 4430 | 2.12ms | $node{_has_tal} = exists $node{_ns_prefix}{ $node{_ns} }; | ||
427 | 4430 | 1.48ms | $node{_tag} = $tag; | ||
428 | 4430 | 1.54ms | $node{_selfclose} = $has_self_close; | ||
429 | 4430 | 1.48ms | $node{_elem} = $elem; | ||
430 | 4430 | 1.52ms | $node{_kids} = []; | ||
431 | |||||
432 | 4430 | 1.51ms | delete $node{_ns_prefix}; | ||
433 | |||||
434 | 4430 | 21.0ms | return \%node; | ||
435 | } | ||||
436 | |||||
437 | return { | ||||
438 | 6940 | 18.4ms | _elem => $elem, | ||
439 | _simple => 1, | ||||
440 | }; | ||||
441 | } | ||||
442 | |||||
443 | # spent 90.2ms (66.1+24.1) within Petal::Tiny::extract_attributes which was called 4430 times, avg 20µs/call:
# 4430 times (66.1ms+24.1ms) by Petal::Tiny::tag2node at line 423, avg 20µs/call | ||||
444 | 4430 | 639µs | my $tag = shift; | ||
445 | |||||
446 | 4430 | 29.0ms | 4431 | 11.1ms | my %attr = $tag =~ /$ATTR_RE/og; # spent 11.1ms making 4430 calls to Petal::Tiny::CORE:match, avg 3µs/call
# spent 900ns making 1 call to Petal::Tiny::CORE:regcomp |
447 | |||||
448 | 4430 | 463µs | my (%quotes, %prefix); | ||
449 | |||||
450 | 4430 | 3.26ms | foreach my $key (keys %attr) { | ||
451 | 6600 | 30.0ms | 6600 | 10.8ms | $attr{$key} =~ s/^(['"])(.*?)\1$/$2/; # spent 10.8ms making 6600 calls to Petal::Tiny::CORE:subst, avg 2µs/call |
452 | 6600 | 1.98ms | my $q = $1 || '"'; | ||
453 | |||||
454 | 6600 | 8.79ms | 6600 | 2.15ms | if ($key =~ /^(.*?):/) { # spent 2.15ms making 6600 calls to Petal::Tiny::CORE:match, avg 326ns/call |
455 | 3310 | 957µs | if ($1 eq 'xmlns' && $attr{$key} eq 'http://purl.org/petal/1.0/') { | ||
456 | 50 | 41µs | delete $attr{$key}; | ||
457 | 50 | 125µs | 50 | 49µs | $key =~ s/^xmlns\://; # spent 49µs making 50 calls to Petal::Tiny::CORE:subst, avg 984ns/call |
458 | 50 | 27µs | $attr{_ns} = $key; | ||
459 | 50 | 20µs | $attr{_change} = 1; | ||
460 | 50 | 36µs | next; | ||
461 | } | ||||
462 | 3260 | 1.71ms | $prefix{$1} = 1; | ||
463 | } | ||||
464 | 6550 | 4.48ms | $quotes{$key} = $q; | ||
465 | } | ||||
466 | |||||
467 | 4430 | 1.32ms | $attr{_quotes} = \%quotes; | ||
468 | 4430 | 1.08ms | $attr{_ns_prefix} = \%prefix; | ||
469 | |||||
470 | 4430 | 14.5ms | %attr; | ||
471 | } | ||||
472 | |||||
473 | 1 | 2µs | my %_encode_dict = ( | ||
474 | '&' => '&', | ||||
475 | '<' => '<', | ||||
476 | '>' => '>', | ||||
477 | '"' => '"', | ||||
478 | "'" => ''', | ||||
479 | ); | ||||
480 | |||||
481 | # spent 3.44ms (2.94+499µs) within Petal::Tiny::xmlencode which was called 2150 times, avg 2µs/call:
# 2150 times (2.94ms+499µs) by Petal::Tiny::resolve_expression at line 283, avg 2µs/call | ||||
482 | 2150 | 390µs | my $string = shift; | ||
483 | 2150 | 1.37ms | return $string if !$string or ref $string; | ||
484 | 1120 | 1.60ms | 1120 | 499µs | $string =~ s/([&<>"'])/$_encode_dict{$1}/g; # spent 499µs making 1120 calls to Petal::Tiny::CORE:subst, avg 445ns/call |
485 | 1120 | 6.02ms | return $string; | ||
486 | } | ||||
487 | |||||
488 | |||||
489 | 1 | 13µs | 1; | ||
490 | |||||
491 | |||||
492 | __END__ | ||||
# spent 47.5ms within Petal::Tiny::CORE:match which was called 34910 times, avg 1µs/call:
# 14960 times (18.1ms+0s) by Petal::Tiny::tag2node at line 418, avg 1µs/call
# 6600 times (2.15ms+0s) by Petal::Tiny::extract_attributes at line 454, avg 326ns/call
# 4950 times (855µs+0s) by Petal::Tiny::resolve at line 293, avg 173ns/call
# 4430 times (11.1ms+0s) by Petal::Tiny::extract_attributes at line 446, avg 3µs/call
# 3870 times (596µs+0s) by Petal::Tiny::_interpolate_dollar at line 120, avg 154ns/call
# 50 times (14.6ms+0s) by Petal::Tiny::xml2nodes at line 75, avg 292µs/call
# 50 times (116µs+0s) by Petal::Tiny::new at line 52, avg 2µs/call | |||||
# spent 2µs within Petal::Tiny::CORE:qr which was called:
# once (2µs+0s) by main::BEGIN@2 at line 43 | |||||
sub Petal::Tiny::CORE:regcomp; # opcode | |||||
# spent 20.0ms within Petal::Tiny::CORE:subst which was called 26660 times, avg 749ns/call:
# 6600 times (10.8ms+0s) by Petal::Tiny::extract_attributes at line 451, avg 2µs/call
# 4740 times (2.46ms+0s) by Petal::Tiny::resolve at line 299, avg 520ns/call
# 2190 times (1.44ms+0s) by Petal::Tiny::resolve_expression at line 276, avg 658ns/call
# 2190 times (1.33ms+0s) by Petal::Tiny::resolve_expression at line 274, avg 606ns/call
# 2190 times (1.06ms+0s) by Petal::Tiny::resolve_expression at line 278, avg 484ns/call
# 2190 times (943µs+0s) by Petal::Tiny::resolve_expression at line 275, avg 430ns/call
# 2190 times (435µs+0s) by Petal::Tiny::resolve_expression at line 281, avg 199ns/call
# 2190 times (430µs+0s) by Petal::Tiny::resolve_expression at line 280, avg 197ns/call
# 1120 times (499µs+0s) by Petal::Tiny::xmlencode at line 484, avg 445ns/call
# 980 times (516µs+0s) by Petal::Tiny::makeitso_node at line 208, avg 526ns/call
# 50 times (49µs+0s) by Petal::Tiny::extract_attributes at line 457, avg 984ns/call
# 10 times (26µs+0s) by Petal::Tiny::_interpolate_dollar at line 129, avg 3µs/call
# 10 times (2µs+0s) by Petal::Tiny::_interpolate_dollar at line 130, avg 210ns/call
# 10 times (1µs+0s) by Petal::Tiny::_interpolate_dollar at line 131, avg 130ns/call | |||||
# spent 14µs within Petal::Tiny::CORE:substcont which was called 20 times, avg 700ns/call:
# 20 times (14µs+0s) by Petal::Tiny::_interpolate_dollar at line 129, avg 700ns/call |