Filename | /home/lbr/project/petal-tiny/lib/Petal/Tiny.pm |
Statements | Executed 454786 statements in 463ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
14960 | 1 | 1 | 70.2ms | 169ms | tag2node | Petal::Tiny::
4430 | 3 | 1 | 60.1ms | 70.2ms | resolve (recurses: max depth 1, inclusive time 15.2ms) | Petal::Tiny::
4050 | 1 | 1 | 59.5ms | 82.2ms | extract_attributes | Petal::Tiny::
50 | 1 | 1 | 48.4ms | 233ms | xml2nodes | Petal::Tiny::
34050 | 7 | 1 | 46.1ms | 46.1ms | CORE:match (opcode) | Petal::Tiny::
1870 | 3 | 1 | 39.5ms | 229ms | makeitso (recurses: max depth 11, inclusive time 1.48s) | Petal::Tiny::
2810 | 2 | 1 | 38.7ms | 228ms | makeitso_node (recurses: max depth 11, inclusive time 1.43s) | Petal::Tiny::
1980 | 6 | 1 | 29.5ms | 108ms | resolve_expression | Petal::Tiny::
2630 | 1 | 1 | 26.2ms | 26.2ms | node2txt | Petal::Tiny::
24140 | 14 | 1 | 19.1ms | 19.1ms | CORE:subst (opcode) | Petal::Tiny::
4520 | 1 | 1 | 14.2ms | 15.5ms | _interpolate_dollar | Petal::Tiny::
7440 | 2 | 1 | 4.73ms | 4.73ms | reftype | Petal::Tiny::
1 | 1 | 1 | 2.89ms | 3.10ms | BEGIN@5 | Petal::Tiny::
1960 | 1 | 1 | 2.81ms | 3.22ms | xmlencode | Petal::Tiny::
50 | 1 | 1 | 558µs | 462ms | process | Petal::Tiny::
150 | 2 | 1 | 471µs | 2.36ms | modifier_true | Petal::Tiny::
50 | 1 | 1 | 462µs | 628µs | new | Petal::Tiny::
10 | 1 | 1 | 269µs | 1.25ms | _do_repeat | Petal::Tiny::
3 | 3 | 1 | 210µs | 210µs | CORE:regcomp (opcode) | Petal::Tiny::
60 | 1 | 1 | 190µs | 1.18ms | modifier_false | Petal::Tiny::
10 | 1 | 1 | 92µs | 92µs | _deep_copy | Petal::Tiny::
10 | 1 | 1 | 47µs | 517µs | __ANON__[lib/Petal/Tiny.pm:127] | Petal::Tiny::
20 | 1 | 1 | 18µs | 18µs | CORE:substcont (opcode) | Petal::Tiny::
1 | 1 | 1 | 11µs | 16µs | BEGIN@3 | Petal::Tiny::
1 | 1 | 1 | 7µs | 16µ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 | 16µs | 2 | 21µ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 | 25µs | # spent 16µs (7+9) within Petal::Tiny::BEGIN@4 which was called:
# once (7µs+9µs) by main::BEGIN@2 at line 4 # spent 16µs making 1 call to Petal::Tiny::BEGIN@4
# spent 9µs making 1 call to strict::import |
5 | 2 | 2.23ms | 2 | 3.16ms | # spent 3.10ms (2.89+211µs) within Petal::Tiny::BEGIN@5 which was called:
# once (2.89ms+211µs) by main::BEGIN@2 at line 5 # spent 3.10ms making 1 call to Petal::Tiny::BEGIN@5
# spent 56µ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 | 500ns | my $TextSE = "[^<]+"; | ||
16 | 1 | 100ns | my $UntilHyphen = "[^-]*-"; | ||
17 | 1 | 900ns | my $Until2Hyphens = "$UntilHyphen(?:[^-]$UntilHyphen)*-"; | ||
18 | 1 | 500ns | my $CommentCE = "$Until2Hyphens>?"; | ||
19 | 1 | 100ns | my $UntilRSBs = "[^\\]]*](?:[^\\]]+])*]+"; | ||
20 | 1 | 600ns | 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 | 200ns | my $QuoteSE = "\"[^\"]*\"|'[^']*'"; | ||
26 | 1 | 2µs | my $DT_IdentSE = "$S$Name(?:$S(?:$Name|$QuoteSE))*"; | ||
27 | 1 | 500ns | 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 | 1µ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 | 1µs | my $DeclCE = "--(?:$CommentCE)?|\\[CDATA\\[(?:$CDATA_CE)?|DOCTYPE(?:$DocTypeCE)?"; | ||
34 | 1 | 500ns | 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 | 2µs | my $XML_SPE = "$TextSE|$MarkupSPE"; | ||
41 | # REX END - thank you Robert for this 26 line XML parser - awesome ... | ||||
42 | |||||
43 | 1 | 44µs | 2 | 34µs | my $ATTR_RE = qr /$ElemTagCE_Mod/; # spent 33µ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 628µs (462+167) within Petal::Tiny::new which was called 50 times, avg 13µs/call:
# 50 times (462µs+167µs) by main::RUNTIME at line 59 of opt.pl, avg 13µs/call | ||||
48 | 50 | 21µs | my $class = shift; | ||
49 | 50 | 27µs | $class = ref $class || $class; | ||
50 | 50 | 124µs | my $thing = shift; | ||
51 | 50 | 52µs | my $self = bless {}, $class; | ||
52 | 50 | 313µs | 50 | 167µs | if (defined $thing and $thing =~ /(\<|\n|\>)/) { # spent 167µs making 50 calls to Petal::Tiny::CORE:match, avg 3µ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 | 89µs | return $self; | ||
61 | } | ||||
62 | |||||
63 | |||||
64 | # spent 462ms (558µs+462) within Petal::Tiny::process which was called 50 times, avg 9.24ms/call:
# 50 times (558µs+462ms) by main::RUNTIME at line 60 of opt.pl, avg 9.24ms/call | ||||
65 | 50 | 14µs | my $self = shift; | ||
66 | 50 | 150µs | my $context = { @_ }; | ||
67 | 50 | 29µs | my $data = $self->{xmldata}; | ||
68 | 50 | 16µs | defined $data or return; # empty data, empty result. | ||
69 | 50 | 308µs | 100 | 462ms | return $self->makeitso($self->xml2nodes($data), $context); # earl grey. hot. # spent 233ms making 50 calls to Petal::Tiny::xml2nodes, avg 4.66ms/call
# spent 229ms making 50 calls to Petal::Tiny::makeitso, avg 4.57ms/call |
70 | } | ||||
71 | |||||
72 | # spent 233ms (48.4+185) within Petal::Tiny::xml2nodes which was called 50 times, avg 4.66ms/call:
# 50 times (48.4ms+185ms) by Petal::Tiny::process at line 69, avg 4.66ms/call | ||||
73 | 50 | 25µs | my ($self, $xml) = @_; | ||
74 | |||||
75 | 50 | 16.3ms | 51 | 15.2ms | my @flat = ( $xml =~ /$XML_SPE/og ); # spent 15.0ms making 50 calls to Petal::Tiny::CORE:match, avg 300µs/call
# spent 176µs making 1 call to Petal::Tiny::CORE:regcomp |
76 | |||||
77 | 50 | 98µs | my $top = { _kids => [], _ns => $DEFAULT_NS }; | ||
78 | 50 | 25µs | my @nest = ( $top ); | ||
79 | 50 | 39µs | for my $tag (@flat) { | ||
80 | 14960 | 9.28ms | 14960 | 169ms | my $node = tag2node($tag, $nest[-1]{_ns}); # if ns is not explicitly set, inherit parent ns # spent 169ms making 14960 calls to Petal::Tiny::tag2node, avg 11µs/call |
81 | |||||
82 | 14960 | 7.53ms | if ($node->{_close}) { | ||
83 | 3220 | 528µs | my $open = pop @nest; | ||
84 | 3220 | 804µs | confess "unbalanced close-tag '</$node->{_tag}>'" if $open == $top; | ||
85 | 3220 | 1.76ms | confess "wrong close-tag '</$node->{_tag}>' for '<$open->{_tag}>'" if lc($node->{_tag}) ne lc($open->{_tag}); | ||
86 | } | ||||
87 | else { | ||||
88 | 11740 | 4.04ms | push @{ $nest[-1]{_kids} }, $node; | ||
89 | 11740 | 2.68ms | push @nest, $node unless ($node->{_simple} or $node->{_selfclose}); | ||
90 | } | ||||
91 | } | ||||
92 | 50 | 28µs | confess "Unbalanced tree, more open than close nodes" if @nest > 1; | ||
93 | |||||
94 | 50 | 58µs | my @nodes = @{ $top->{_kids} }; | ||
95 | |||||
96 | 50 | 894µs | return \@nodes; | ||
97 | } | ||||
98 | |||||
99 | # spent 229ms (39.5+189) within Petal::Tiny::makeitso which was called 1870 times, avg 122µs/call:
# 1790 times (32.8ms+-32.8ms) by Petal::Tiny::makeitso_node at line 232, avg 0s/call
# 50 times (327µs+228ms) by Petal::Tiny::process at line 69, avg 4.57ms/call
# 30 times (6.36ms+-6.36ms) by Petal::Tiny::makeitso_node at line 227, avg 0s/call | ||||
100 | 1870 | 433µs | my ($self, $nodes, $context) = @_; | ||
101 | |||||
102 | 1870 | 1.24ms | return "" unless @$nodes; | ||
103 | |||||
104 | 1100 | 132µs | my @res; | ||
105 | 1100 | 453µs | for my $node (@$nodes) { | ||
106 | 7320 | 7.38ms | 4520 | 15.5ms | if ($node->{_simple}) { # spent 15.5ms making 4520 calls to Petal::Tiny::_interpolate_dollar, avg 3µs/call |
107 | push @res, $self->_interpolate_dollar($context, $node->{_elem}, 'resolve_expression'); | ||||
108 | } | ||||
109 | else { | ||||
110 | 2800 | 2.49ms | 2800 | 228ms | push @res, $self->makeitso_node($node, $context); # spent 1.66s making 2800 calls to Petal::Tiny::makeitso_node, avg 592µs/call, recursion: max depth 11, sum of overlapping time 1.43s |
111 | } | ||||
112 | } | ||||
113 | |||||
114 | 1100 | 3.48ms | return join "", @res; | ||
115 | } | ||||
116 | |||||
117 | # spent 15.5ms (14.2+1.28) within Petal::Tiny::_interpolate_dollar which was called 4520 times, avg 3µs/call:
# 4520 times (14.2ms+1.28ms) by Petal::Tiny::makeitso at line 106, avg 3µs/call | ||||
118 | 4520 | 1.27ms | my ($self, $context, $string, $method) = @_; | ||
119 | |||||
120 | 4520 | 11.0ms | 4520 | 710µs | if ($string =~ /\$/) { # spent 710µs making 4520 calls to Petal::Tiny::CORE:match, avg 157ns/call |
121 | # spent 517µs (47+470) within Petal::Tiny::__ANON__[lib/Petal/Tiny.pm:127] which was called 10 times, avg 52µs/call:
# 10 times (47µs+470µs) by Petal::Tiny::_interpolate_dollar at line 129, avg 52µs/call | ||||
122 | 10 | 7µs | my $what = shift; | ||
123 | 10 | 16µs | 10 | 470µs | my $res = $self->$method($what, $context); # spent 470µs making 10 calls to Petal::Tiny::resolve_expression, avg 47µs/call |
124 | 10 | 22µs | return $res if defined $res; | ||
125 | carp "'$what' in \$-interpolation resolved to undef"; | ||||
126 | return ""; | ||||
127 | 10 | 35µs | }; | ||
128 | |||||
129 | 20 | 134µs | 40 | 565µs | $string =~ s/(?<!\$) \$\{ ( [^{}]+ ) \} / $subst->($1) /xegi; # spent 517µs making 10 calls to Petal::Tiny::__ANON__[lib/Petal/Tiny.pm:127], avg 52µs/call
# spent 30µs making 10 calls to Petal::Tiny::CORE:subst, avg 3µs/call
# spent 18µs making 20 calls to Petal::Tiny::CORE:substcont, avg 900ns/call |
130 | 10 | 18µs | 10 | 3µs | $string =~ s/(?<!\$) \$\{? ( [a-z0-9-\/:_]+ ) \}? / $subst->($1) /xegi; # spent 3µs making 10 calls to Petal::Tiny::CORE:subst, avg 300ns/call |
131 | 10 | 50µs | 10 | 2µs | $string =~ s/\$\$/\$/g; # spent 2µs making 10 calls to Petal::Tiny::CORE:subst, avg 230ns/call |
132 | } | ||||
133 | 4520 | 20.5ms | return $string; | ||
134 | } | ||||
135 | |||||
136 | # spent 92µs within Petal::Tiny::_deep_copy which was called 10 times, avg 9µs/call:
# 10 times (92µs+0s) by Petal::Tiny::_do_repeat at line 263, avg 9µs/call | ||||
137 | 10 | 3µs | my $node = shift; | ||
138 | 10 | 51µ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 | 31µs | return \%copy; | ||
145 | } | ||||
146 | |||||
147 | sub makeitso_node { | ||||
148 | 2810 | 559µs | my ($self, $node, $context) = @_; | ||
149 | |||||
150 | 2810 | 955µs | my $TAL = $node->{_ns}; | ||
151 | |||||
152 | 2810 | 396µs | my $STOP_RECURSE = 0; | ||
153 | |||||
154 | 2810 | 1.02ms | if ($node->{_has_tal}) { | ||
155 | 1530 | 512µs | $node->{_change} = 1; | ||
156 | |||||
157 | 1530 | 950µ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 | 1530 | 4.37ms | $context = { %$context }; | ||
170 | |||||
171 | 1530 | 859µ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 | 1530 | 937µs | if (defined( my $stuff = delete $node->{"$TAL:condition"} )) { | ||
179 | 150 | 140µs | for my $cond (split /;(?!;)/, $stuff) { | ||
180 | 150 | 344µs | 150 | 5.91ms | return '' unless $self->resolve_expression($cond, $context); # spent 5.91ms making 150 calls to Petal::Tiny::resolve_expression, avg 39µs/call |
181 | } | ||||
182 | } | ||||
183 | |||||
184 | 1440 | 710µs | if (defined( my $stuff = delete $node->{"$TAL:repeat"} )) { | ||
185 | 10 | 16µs | my @loops = split /;(?!;)/, $stuff; | ||
186 | 10 | 4µs | my $count = 0; | ||
187 | 10 | 57µs | 10 | 1.25ms | return join "", $self->_do_repeat(\$count, 1, \@loops, $node, $context); # spent 1.25ms making 10 calls to Petal::Tiny::_do_repeat, avg 125µs/call |
188 | } | ||||
189 | |||||
190 | 1430 | 1.20ms | if (defined( my $stuff = delete $node->{"$TAL:content"} )) { | ||
191 | 840 | 700µs | 840 | 39.8ms | my $res = $self->resolve_expression($stuff, $context); # spent 39.8ms making 840 calls to Petal::Tiny::resolve_expression, avg 47µs/call |
192 | 840 | 423µs | $node->{_contents} = defined $res ? $res : ""; | ||
193 | 840 | 373µ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 | 840 | 243µs | $STOP_RECURSE = 1; | ||
198 | } | ||||
199 | |||||
200 | 1430 | 747µs | if (defined( my $stuff = delete $node->{"$TAL:replace"} )) { | ||
201 | 50 | 44µs | 50 | 7.58ms | my $res = $self->resolve_expression($stuff, $context); # spent 7.58ms making 50 calls to Petal::Tiny::resolve_expression, avg 152µs/call |
202 | 50 | 127µs | return defined $res ? $res : ''; | ||
203 | } | ||||
204 | |||||
205 | 1380 | 1.22ms | if (defined( my $stuff = delete $node->{"$TAL:attributes"} )) { | ||
206 | 740 | 947µs | for my $att (split /;(?!;)/, $stuff) { | ||
207 | 920 | 783µs | my ($symbol, $expression) = split ' ', $att, 2; | ||
208 | 920 | 1.67ms | 920 | 536µs | my $add = ($symbol =~ s/^\+//); # spent 536µs making 920 calls to Petal::Tiny::CORE:subst, avg 583ns/call |
209 | 920 | 692µs | 920 | 54.3ms | my $new = $self->resolve_expression($expression, $context); # spent 54.3ms making 920 calls to Petal::Tiny::resolve_expression, avg 59µs/call |
210 | 920 | 690µs | if (defined $new) { | ||
211 | 320 | 53µs | if ($add) { | ||
212 | 50 | 25µs | my $old = $node->{$symbol}; | ||
213 | 50 | 18µs | $old = "" unless defined $old; | ||
214 | 50 | 28µs | $new = $old . $new; | ||
215 | } | ||||
216 | 320 | 206µs | $node->{$symbol} = $new; | ||
217 | } | ||||
218 | else { | ||||
219 | 600 | 147µs | delete $node->{$symbol} unless $add; | ||
220 | } | ||||
221 | } | ||||
222 | } | ||||
223 | |||||
224 | 1380 | 1.08ms | if (defined(my $stuff = delete $node->{"$TAL:omit-tag"})) { | ||
225 | 30 | 13µs | if ($stuff eq '' or $self->resolve_expression($stuff, $context)) { | ||
226 | 30 | 8µs | return $node->{_contents} if $STOP_RECURSE; | ||
227 | 30 | 130µs | 30 | 0s | return $self->makeitso($node->{_kids}, $context); # spent 165ms making 30 calls to Petal::Tiny::makeitso, avg 5.50ms/call, recursion: max depth 4, sum of overlapping time 165ms |
228 | } | ||||
229 | } | ||||
230 | } | ||||
231 | |||||
232 | 2630 | 2.18ms | 1790 | 0s | unless ($STOP_RECURSE) { # spent 1.32s making 1790 calls to Petal::Tiny::makeitso, avg 737µs/call, recursion: max depth 11, sum of overlapping time 1.32s |
233 | $node->{_contents} = $self->makeitso($node->{_kids}, $context); | ||||
234 | } | ||||
235 | 2630 | 10.8ms | 2630 | 26.2ms | return node2txt($node); # spent 26.2ms making 2630 calls to Petal::Tiny::node2txt, avg 10µs/call |
236 | } | ||||
237 | |||||
238 | # spent 1.25ms (269µs+982µs) within Petal::Tiny::_do_repeat which was called 10 times, avg 125µs/call:
# 10 times (269µs+982µs) by Petal::Tiny::makeitso_node at line 187, avg 125µs/call | ||||
239 | 10 | 6µs | my ($self, $count, $last, $loops_ref, $node, $context) = @_; | ||
240 | 10 | 9µs | my @loops = @$loops_ref; | ||
241 | 10 | 6µs | my $stuff = shift @loops; | ||
242 | 10 | 14µs | my ($symbol, $expression) = split ' ', $stuff, 2; | ||
243 | 10 | 12µs | 10 | 308µs | my $array = $self->resolve_expression($expression, $context); # spent 308µs making 10 calls to Petal::Tiny::resolve_expression, avg 31µs/call |
244 | 10 | 9µs | $array = [ $array ] unless ref $array; # we don't judge | ||
245 | 10 | 2µs | my @result; | ||
246 | 10 | 18µs | foreach my $idx (0 .. $#$array) { | ||
247 | 10 | 4µs | my $item = $array->[$idx]; | ||
248 | 10 | 9µ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 | 10µs | $context->{repeat} = {}; | ||
255 | 10 | 8µs | $context->{repeat}->{index} = $$count; | ||
256 | 10 | 7µs | $context->{repeat}->{number} = $$count; | ||
257 | 10 | 14µs | $context->{repeat}->{even} = $$count%2 ? 0 : 1; | ||
258 | 10 | 8µs | $context->{repeat}->{odd} = $$count%2 ? 1 : 0; | ||
259 | 10 | 11µs | $context->{repeat}->{start} = $$count == 1 ? 1 : 0; | ||
260 | 10 | 10µs | $context->{repeat}->{end} = $last && $idx == $#$array ? 1 : 0; | ||
261 | 10 | 16µs | $context->{repeat}->{inner} = $context->{repeat}->{start} || $context->{repeat}->{end} ? 0 : 1; | ||
262 | |||||
263 | 10 | 27µs | 20 | 92µs | push @result, $self->makeitso_node(_deep_copy($node), $context); # spent 92µs making 10 calls to Petal::Tiny::_deep_copy, avg 9µs/call
# spent 582µs making 10 calls to Petal::Tiny::makeitso_node, avg 58µs/call, recursion: max depth 4, sum of overlapping time 582µs |
264 | } | ||||
265 | } | ||||
266 | 10 | 24µs | return @result; | ||
267 | } | ||||
268 | |||||
269 | |||||
270 | # spent 108ms (29.5+78.9) within Petal::Tiny::resolve_expression which was called 1980 times, avg 55µs/call:
# 920 times (18.9ms+35.4ms) by Petal::Tiny::makeitso_node at line 209, avg 59µs/call
# 840 times (8.29ms+31.5ms) by Petal::Tiny::makeitso_node at line 191, avg 47µs/call
# 150 times (1.51ms+4.40ms) by Petal::Tiny::makeitso_node at line 180, avg 39µs/call
# 50 times (487µs+7.10ms) by Petal::Tiny::makeitso_node at line 201, avg 152µs/call
# 10 times (108µs+363µs) by Petal::Tiny::__ANON__[lib/Petal/Tiny.pm:127] at line 123, avg 47µs/call
# 10 times (123µs+185µs) by Petal::Tiny::_do_repeat at line 243, avg 31µs/call | ||||
271 | 1980 | 495µs | my ($self, $expr, $context) = @_; | ||
272 | |||||
273 | 1980 | 312µs | $expr = "" unless defined $expr; | ||
274 | 1980 | 3.38ms | 1980 | 1.24ms | $expr =~ s/[\n\r]/ /g; # spent 1.24ms making 1980 calls to Petal::Tiny::CORE:subst, avg 626ns/call |
275 | 1980 | 2.78ms | 1980 | 905µs | $expr =~ s/^\s+//; # spent 905µs making 1980 calls to Petal::Tiny::CORE:subst, avg 457ns/call |
276 | 1980 | 3.25ms | 1980 | 1.43ms | $expr =~ s/\s+$//; # spent 1.43ms making 1980 calls to Petal::Tiny::CORE:subst, avg 724ns/call |
277 | |||||
278 | 1980 | 2.93ms | 1980 | 1.04ms | $expr =~ s/([;\$])\1/$1/g; # spent 1.04ms making 1980 calls to Petal::Tiny::CORE:subst, avg 525ns/call |
279 | 1980 | 390µs | $expr eq 'nothing' and return undef; | ||
280 | 1980 | 7.02ms | 1980 | 444µs | $expr =~ s/^fresh\s+//; # spent 444µs making 1980 calls to Petal::Tiny::CORE:subst, avg 224ns/call |
281 | 1980 | 2.46ms | 1980 | 424µs | my $structure = ($expr =~ s/^structure\s+//); # spent 424µs making 1980 calls to Petal::Tiny::CORE:subst, avg 214ns/call |
282 | 1980 | 1.52ms | 1980 | 70.2ms | my $resolved = $self->resolve($expr, $context); # spent 70.2ms making 1980 calls to Petal::Tiny::resolve, avg 35µs/call |
283 | 1980 | 3.84ms | 1960 | 3.22ms | return $structure ? $resolved : xmlencode($resolved); # spent 3.22ms making 1960 calls to Petal::Tiny::xmlencode, avg 2µs/call |
284 | } | ||||
285 | |||||
286 | sub reftype { | ||||
287 | 7440 | 1.24ms | my ($self, $obj) = @_; | ||
288 | 7440 | 8.01ms | return ref $obj; | ||
289 | } | ||||
290 | |||||
291 | # spent 70.2ms (60.1+10.1) within Petal::Tiny::resolve which was called 4430 times, avg 16µs/call:
# 2300 times (11.1ms+-11.1ms) by Petal::Tiny::resolve at line 307, avg 0s/call
# 1980 times (47.4ms+22.8ms) by Petal::Tiny::resolve_expression at line 282, avg 35µs/call
# 150 times (1.62ms+-1.62ms) by Petal::Tiny::modifier_true at line 366, avg 0s/call | ||||
292 | 4430 | 1.03ms | my ($self, $expr, $context) = @_; | ||
293 | 4430 | 10.5ms | 4430 | 785µs | $expr =~ /:(?!pattern)/ and do { # XXX what is :pattern? # spent 785µs making 4430 calls to Petal::Tiny::CORE:match, avg 177ns/call |
294 | 150 | 191µs | my ($mod, $expr) = split /:(?!pattern)\s*/, $expr, 2; | ||
295 | 150 | 490µs | 150 | 198µs | my $meth = $self->can("modifier_$mod"); # spent 198µs making 150 calls to UNIVERSAL::can, avg 1µs/call |
296 | 150 | 343µs | 150 | 2.55ms | return $self->$meth($expr, $context) if $meth; # spent 1.37ms making 90 calls to Petal::Tiny::modifier_true, avg 15µs/call
# spent 1.18ms making 60 calls to Petal::Tiny::modifier_false, avg 20µs/call |
297 | confess "unknown modifier $mod"; | ||||
298 | }; | ||||
299 | 4280 | 19.2ms | 4280 | 2.33ms | return $expr if $expr =~ s/^--//; # spent 2.33ms making 4280 calls to Petal::Tiny::CORE:subst, avg 546ns/call |
300 | |||||
301 | 1980 | 2.10ms | my ($what, @args) = split ' ', $expr; | ||
302 | 1980 | 268µs | defined $what or return; | ||
303 | |||||
304 | 1980 | 1.49ms | my (@path) = split /\//, $what; | ||
305 | 1980 | 269µs | my @resolved; | ||
306 | 1980 | 332µs | my $obj = $context; | ||
307 | 4280 | 3.57ms | 2300 | 0s | @args = map { $self->resolve($_, $context) } @args; # spent 13.3ms making 2300 calls to Petal::Tiny::resolve, avg 6µs/call, recursion: max depth 1, sum of overlapping time 13.3ms |
308 | 1980 | 639µs | while (@path) { | ||
309 | 3720 | 743µs | my $attribute_or_method = shift @path; | ||
310 | 3720 | 882µs | push @resolved, $attribute_or_method; | ||
311 | 3720 | 1.20ms | my $resolved = join '/', @resolved; | ||
312 | 3720 | 483µs | $obj or confess "cannot fetch $what, because $resolved is undefined"; | ||
313 | 3720 | 2.32ms | 3720 | 2.49ms | my $reftype = $self->reftype($obj); # spent 2.49ms making 3720 calls to Petal::Tiny::reftype, avg 668ns/call |
314 | 3720 | 434µs | $reftype or confess "cannot fetch $what, because $resolved is not a reference"; | ||
315 | |||||
316 | 3720 | 1.91ms | 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 | 3720 | 2.07ms | 3720 | 2.24ms | $reftype = $self->reftype($obj); # spent 2.24ms making 3720 calls to Petal::Tiny::reftype, avg 603ns/call |
334 | 3720 | 847µs | if ($reftype eq 'CODE') { | ||
335 | 1730 | 485µs | if (@path) { | ||
336 | $obj = $obj->(); | ||||
337 | } | ||||
338 | else { | ||||
339 | 1730 | 1.50ms | 1730 | 1.39ms | $obj = $obj->(@args); # spent 559µs making 560 calls to main::__ANON__[opt.pl:19], avg 998ns/call
# spent 252µs making 450 calls to main::__ANON__[opt.pl:17], avg 560ns/call
# spent 203µs making 290 calls to main::__ANON__[opt.pl:18], avg 700ns/call
# spent 117µs making 180 calls to main::__ANON__[opt.pl:16], avg 651ns/call
# spent 58µs making 50 calls to main::__ANON__[opt.pl:12], avg 1µs/call
# spent 57µs making 60 calls to main::__ANON__[opt.pl:13], avg 955ns/call
# spent 55µs making 80 calls to main::__ANON__[opt.pl:14], avg 682ns/call
# spent 40µs making 30 calls to main::__ANON__[opt.pl:11], avg 1µs/call
# spent 18µs making 10 calls to main::__ANON__[opt.pl:9], avg 2µs/call
# spent 17µs making 10 calls to main::__ANON__[opt.pl:8], avg 2µs/call
# spent 15µs making 10 calls to main::__ANON__[opt.pl:25], avg 2µs/call |
340 | 1730 | 542µ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 | 3720 | 884µ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 | 3720 | 1.74ms | not @path and @args and confess "cannot resolve expression $expr"; | ||
359 | } | ||||
360 | 1980 | 2.86ms | return $obj; | ||
361 | } | ||||
362 | |||||
363 | |||||
364 | sub modifier_true { | ||||
365 | 150 | 52µs | my ($self, $expr, $context) = @_; | ||
366 | 150 | 129µs | 150 | 0s | my $arg = $self->resolve($expr, $context); # spent 1.89ms making 150 calls to Petal::Tiny::resolve, avg 13µs/call, recursion: max depth 1, sum of overlapping time 1.89ms |
367 | 150 | 44µs | ref $arg and $self->reftype($arg) eq 'ARRAY' and return scalar @$arg; | ||
368 | 150 | 230µs | return $arg ? 1 : 0; | ||
369 | } | ||||
370 | |||||
371 | |||||
372 | # spent 1.18ms (190µs+986µs) within Petal::Tiny::modifier_false which was called 60 times, avg 20µs/call:
# 60 times (190µs+986µs) by Petal::Tiny::resolve at line 296, avg 20µs/call | ||||
373 | 60 | 15µs | my $self = shift; | ||
374 | 60 | 147µs | 60 | 986µs | return not $self->modifier_true(@_); # spent 986µs making 60 calls to Petal::Tiny::modifier_true, avg 16µ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 26.2ms within Petal::Tiny::node2txt which was called 2630 times, avg 10µs/call:
# 2630 times (26.2ms+0s) by Petal::Tiny::makeitso_node at line 235, avg 10µs/call | ||||
386 | 2630 | 425µs | my $node = shift; | ||
387 | |||||
388 | 2630 | 596µs | return $node unless ref $node eq 'HASH'; # handle textnodes introduced in makeitso_node | ||
389 | 2630 | 561µs | return $node->{_elem} if $node->{_simple}; | ||
390 | |||||
391 | 2630 | 726µs | delete $node->{_ns}; | ||
392 | 2630 | 689µs | delete $node->{_has_tal}; | ||
393 | 2630 | 4.67ms | delete $node->{_kids}; | ||
394 | |||||
395 | 2630 | 680µs | my $change = delete $node->{_change}; | ||
396 | 2630 | 1.05ms | my $elem = delete $node->{_elem}; | ||
397 | 2630 | 884µs | my $tag = delete $node->{_tag}; | ||
398 | 2630 | 751µs | my $close = delete $node->{_selfclose}; | ||
399 | 2630 | 792µs | my $quotes = delete $node->{_quotes}; | ||
400 | 2630 | 865µs | my $contents = delete $node->{_contents}; | ||
401 | 8870 | 7.21ms | my $att = join ' ', map { my $q = $quotes->{$_} || '"'; qq|$_=$q$node->{$_}$q| } keys %$node; | ||
402 | |||||
403 | 2630 | 7.59ms | if ($close) { | ||
404 | return $change ? ($att ? "<$tag $att />" : "<$tag />") : $elem; | ||||
405 | } | ||||
406 | |||||
407 | 1910 | 1.02ms | my $start = $change ? ($att ? "<$tag $att>" : "<$tag>") : $elem; | ||
408 | 1910 | 803µs | my $end = "</$tag>"; | ||
409 | |||||
410 | 1910 | 285µs | $contents = "" unless defined $contents; | ||
411 | |||||
412 | 1910 | 4.16ms | return $start . $contents . $end; | ||
413 | } | ||||
414 | |||||
415 | # spent 169ms (70.2+99.1) within Petal::Tiny::tag2node which was called 14960 times, avg 11µs/call:
# 14960 times (70.2ms+99.1ms) by Petal::Tiny::xml2nodes at line 80, avg 11µs/call | ||||
416 | 14960 | 3.38ms | my ($elem, $ns) = @_; | ||
417 | |||||
418 | 14960 | 36.3ms | 14960 | 17.0ms | if ($elem =~ m,^<(/?)([A-Za-z0-9][A-Za-z0-9_:-]+).*?(/?)>$,) { # spent 17.0ms making 14960 calls to Petal::Tiny::CORE:match, avg 1µs/call |
419 | 7270 | 4.14ms | my ($has_close, $tag, $has_self_close) = ($1,$2,$3); | ||
420 | |||||
421 | 7270 | 5.65ms | return { _tag => $tag, _close => 1 } if $has_close; # don't waste any time on </...> nodes, they're just for book-keeping | ||
422 | |||||
423 | 4050 | 6.27ms | 4050 | 82.2ms | my %node = extract_attributes($elem); # spent 82.2ms making 4050 calls to Petal::Tiny::extract_attributes, avg 20µs/call |
424 | 4050 | 1.41ms | $node{_ns} ||= $ns; | ||
425 | |||||
426 | 4050 | 2.09ms | $node{_has_tal} = exists $node{_ns_prefix}{ $node{_ns} }; | ||
427 | 4050 | 1.43ms | $node{_tag} = $tag; | ||
428 | 4050 | 1.35ms | $node{_selfclose} = $has_self_close; | ||
429 | 4050 | 1.44ms | $node{_elem} = $elem; | ||
430 | 4050 | 1.57ms | $node{_kids} = []; | ||
431 | |||||
432 | 4050 | 1.53ms | delete $node{_ns_prefix}; | ||
433 | |||||
434 | 4050 | 15.7ms | return \%node; | ||
435 | } | ||||
436 | |||||
437 | return { | ||||
438 | 7690 | 10.5ms | _elem => $elem, | ||
439 | _simple => 1, | ||||
440 | }; | ||||
441 | } | ||||
442 | |||||
443 | # spent 82.2ms (59.5+22.6) within Petal::Tiny::extract_attributes which was called 4050 times, avg 20µs/call:
# 4050 times (59.5ms+22.6ms) by Petal::Tiny::tag2node at line 423, avg 20µs/call | ||||
444 | 4050 | 600µs | my $tag = shift; | ||
445 | |||||
446 | 4050 | 17.4ms | 4051 | 10.4ms | my %attr = $tag =~ /$ATTR_RE/og; # spent 10.4ms making 4050 calls to Petal::Tiny::CORE:match, avg 3µs/call
# spent 1µs making 1 call to Petal::Tiny::CORE:regcomp |
447 | |||||
448 | 4050 | 423µs | my (%quotes, %prefix); | ||
449 | |||||
450 | 4050 | 3.21ms | foreach my $key (keys %attr) { | ||
451 | 5990 | 23.1ms | 5990 | 10.2ms | $attr{$key} =~ s/^(['"])(.*?)\1$/$2/; # spent 10.2ms making 5990 calls to Petal::Tiny::CORE:subst, avg 2µs/call |
452 | 5990 | 1.81ms | my $q = $1 || '"'; | ||
453 | |||||
454 | 5990 | 19.6ms | 5990 | 1.97ms | if ($key =~ /^(.*?):/) { # spent 1.97ms making 5990 calls to Petal::Tiny::CORE:match, avg 329ns/call |
455 | 2940 | 921µs | if ($1 eq 'xmlns' && $attr{$key} eq 'http://purl.org/petal/1.0/') { | ||
456 | 50 | 51µs | delete $attr{$key}; | ||
457 | 50 | 153µs | 50 | 78µs | $key =~ s/^xmlns\://; # spent 78µs making 50 calls to Petal::Tiny::CORE:subst, avg 2µs/call |
458 | 50 | 31µs | $attr{_ns} = $key; | ||
459 | 50 | 19µs | $attr{_change} = 1; | ||
460 | 50 | 46µs | next; | ||
461 | } | ||||
462 | 2890 | 1.71ms | $prefix{$1} = 1; | ||
463 | } | ||||
464 | 5940 | 4.51ms | $quotes{$key} = $q; | ||
465 | } | ||||
466 | |||||
467 | 4050 | 1.23ms | $attr{_quotes} = \%quotes; | ||
468 | 4050 | 950µs | $attr{_ns_prefix} = \%prefix; | ||
469 | |||||
470 | 4050 | 20.3ms | %attr; | ||
471 | } | ||||
472 | |||||
473 | 1 | 2µs | my %_encode_dict = ( | ||
474 | '&' => '&', | ||||
475 | '<' => '<', | ||||
476 | '>' => '>', | ||||
477 | '"' => '"', | ||||
478 | "'" => ''', | ||||
479 | ); | ||||
480 | |||||
481 | # spent 3.22ms (2.81+412µs) within Petal::Tiny::xmlencode which was called 1960 times, avg 2µs/call:
# 1960 times (2.81ms+412µs) by Petal::Tiny::resolve_expression at line 283, avg 2µs/call | ||||
482 | 1960 | 380µs | my $string = shift; | ||
483 | 1960 | 6.91ms | return $string if !$string or ref $string; | ||
484 | 990 | 1.43ms | 990 | 412µs | $string =~ s/([&<>"'])/$_encode_dict{$1}/g; # spent 412µs making 990 calls to Petal::Tiny::CORE:subst, avg 416ns/call |
485 | 990 | 1.07ms | return $string; | ||
486 | } | ||||
487 | |||||
488 | |||||
489 | 1 | 13µs | 1; | ||
490 | |||||
491 | |||||
492 | __END__ | ||||
# spent 46.1ms within Petal::Tiny::CORE:match which was called 34050 times, avg 1µs/call:
# 14960 times (17.0ms+0s) by Petal::Tiny::tag2node at line 418, avg 1µs/call
# 5990 times (1.97ms+0s) by Petal::Tiny::extract_attributes at line 454, avg 329ns/call
# 4520 times (710µs+0s) by Petal::Tiny::_interpolate_dollar at line 120, avg 157ns/call
# 4430 times (785µs+0s) by Petal::Tiny::resolve at line 293, avg 177ns/call
# 4050 times (10.4ms+0s) by Petal::Tiny::extract_attributes at line 446, avg 3µs/call
# 50 times (15.0ms+0s) by Petal::Tiny::xml2nodes at line 75, avg 300µs/call
# 50 times (167µs+0s) by Petal::Tiny::new at line 52, avg 3µ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 19.1ms within Petal::Tiny::CORE:subst which was called 24140 times, avg 789ns/call:
# 5990 times (10.2ms+0s) by Petal::Tiny::extract_attributes at line 451, avg 2µs/call
# 4280 times (2.33ms+0s) by Petal::Tiny::resolve at line 299, avg 546ns/call
# 1980 times (1.43ms+0s) by Petal::Tiny::resolve_expression at line 276, avg 724ns/call
# 1980 times (1.24ms+0s) by Petal::Tiny::resolve_expression at line 274, avg 626ns/call
# 1980 times (1.04ms+0s) by Petal::Tiny::resolve_expression at line 278, avg 525ns/call
# 1980 times (905µs+0s) by Petal::Tiny::resolve_expression at line 275, avg 457ns/call
# 1980 times (444µs+0s) by Petal::Tiny::resolve_expression at line 280, avg 224ns/call
# 1980 times (424µs+0s) by Petal::Tiny::resolve_expression at line 281, avg 214ns/call
# 990 times (412µs+0s) by Petal::Tiny::xmlencode at line 484, avg 416ns/call
# 920 times (536µs+0s) by Petal::Tiny::makeitso_node at line 208, avg 583ns/call
# 50 times (78µs+0s) by Petal::Tiny::extract_attributes at line 457, avg 2µs/call
# 10 times (30µs+0s) by Petal::Tiny::_interpolate_dollar at line 129, avg 3µs/call
# 10 times (3µs+0s) by Petal::Tiny::_interpolate_dollar at line 130, avg 300ns/call
# 10 times (2µs+0s) by Petal::Tiny::_interpolate_dollar at line 131, avg 230ns/call | |||||
# spent 18µs within Petal::Tiny::CORE:substcont which was called 20 times, avg 900ns/call:
# 20 times (18µs+0s) by Petal::Tiny::_interpolate_dollar at line 129, avg 900ns/call |