| Filename | /usr/lib/x86_64-linux-gnu/perl5/5.28/Template/VMethods.pm |
| Statements | Executed 31878 statements in 143ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1991 | 1 | 1 | 45.2ms | 66.7ms | Template::VMethods::list_sort |
| 3981 | 1 | 1 | 32.7ms | 32.7ms | Template::VMethods::text_substr |
| 1991 | 1 | 1 | 22.6ms | 22.6ms | Template::VMethods::list_import |
| 1991 | 1 | 1 | 21.4ms | 21.4ms | Template::VMethods::CORE:sort (opcode) |
| 1 | 1 | 1 | 13µs | 15µs | Template::VMethods::BEGIN@24 |
| 1 | 1 | 1 | 12µs | 29µs | Template::VMethods::BEGIN@469 |
| 1 | 1 | 1 | 11µs | 12µs | Template::VMethods::BEGIN@27 |
| 1 | 1 | 1 | 8µs | 34µs | Template::VMethods::BEGIN@118 |
| 1 | 1 | 1 | 8µs | 60µs | Template::VMethods::BEGIN@26 |
| 1 | 1 | 1 | 6µs | 18µs | Template::VMethods::BEGIN@496 |
| 1 | 1 | 1 | 5µs | 15µs | Template::VMethods::BEGIN@502 |
| 1 | 1 | 1 | 5µs | 16µs | Template::VMethods::BEGIN@124 |
| 1 | 1 | 1 | 5µs | 16µs | Template::VMethods::BEGIN@25 |
| 1 | 1 | 1 | 500ns | 500ns | Template::VMethods::__ANON__ (xsub) |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::__ANON__[:234] |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::__ANON__[:606] |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::_list_sort_make_key |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::hash_defined |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::hash_delete |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::hash_each |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::hash_empty |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::hash_exists |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::hash_hash |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::hash_import |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::hash_item |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::hash_items |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::hash_keys |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::hash_list |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::hash_nsort |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::hash_pairs |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::hash_size |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::hash_sort |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::hash_values |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_defined |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_empty |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_first |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_grep |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_hash |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_item |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_join |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_last |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_list |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_max |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_merge |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_nsort |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_pop |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_push |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_reverse |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_shift |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_size |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_slice |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_splice |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_unique |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::list_unshift |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::root_dec |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::root_inc |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_chunk |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_collapse |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_defined |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_dquote |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_empty |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_hash |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_item |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_lcfirst |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_length |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_list |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_lower |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_match |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_remove |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_repeat |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_replace |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_search |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_size |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_split |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_squote |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_trim |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_ucfirst |
| 0 | 0 | 0 | 0s | 0s | Template::VMethods::text_upper |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | #============================================================= -*-Perl-*- | ||||
| 2 | # | ||||
| 3 | # Template::VMethods | ||||
| 4 | # | ||||
| 5 | # DESCRIPTION | ||||
| 6 | # Module defining virtual methods for the Template Toolkit | ||||
| 7 | # | ||||
| 8 | # AUTHOR | ||||
| 9 | # Andy Wardley <abw@wardley.org> | ||||
| 10 | # | ||||
| 11 | # COPYRIGHT | ||||
| 12 | # Copyright (C) 1996-2015 Andy Wardley. All Rights Reserved. | ||||
| 13 | # | ||||
| 14 | # This module is free software; you can redistribute it and/or | ||||
| 15 | # modify it under the same terms as Perl itself. | ||||
| 16 | # | ||||
| 17 | # REVISION | ||||
| 18 | # $Id$ | ||||
| 19 | # | ||||
| 20 | #============================================================================ | ||||
| 21 | |||||
| 22 | package Template::VMethods; | ||||
| 23 | |||||
| 24 | 2 | 22µs | 2 | 17µs | # spent 15µs (13+2) within Template::VMethods::BEGIN@24 which was called:
# once (13µs+2µs) by Template::Stash::BEGIN@24 at line 24 # spent 15µs making 1 call to Template::VMethods::BEGIN@24
# spent 2µs making 1 call to strict::import |
| 25 | 2 | 84µs | 2 | 27µs | # spent 16µs (5+11) within Template::VMethods::BEGIN@25 which was called:
# once (5µs+11µs) by Template::Stash::BEGIN@24 at line 25 # spent 16µs making 1 call to Template::VMethods::BEGIN@25
# spent 11µs making 1 call to warnings::import |
| 26 | 2 | 27µs | 2 | 112µs | # spent 60µs (8+52) within Template::VMethods::BEGIN@26 which was called:
# once (8µs+52µs) by Template::Stash::BEGIN@24 at line 26 # spent 60µs making 1 call to Template::VMethods::BEGIN@26
# spent 52µs making 1 call to Exporter::import |
| 27 | 2 | 384µs | 2 | 12µs | # spent 12µs (11+500ns) within Template::VMethods::BEGIN@27 which was called:
# once (11µs+500ns) by Template::Stash::BEGIN@24 at line 27 # spent 12µs making 1 call to Template::VMethods::BEGIN@27
# spent 500ns making 1 call to Template::VMethods::__ANON__ |
| 28 | 1 | 600ns | require Template::Stash; | ||
| 29 | |||||
| 30 | 1 | 300ns | our $VERSION = 2.16; | ||
| 31 | 1 | 300ns | our $DEBUG = 0 unless defined $DEBUG; | ||
| 32 | 1 | 100ns | our $PRIVATE = $Template::Stash::PRIVATE; | ||
| 33 | |||||
| 34 | 1 | 2µs | our $ROOT_VMETHODS = { | ||
| 35 | inc => \&root_inc, | ||||
| 36 | dec => \&root_dec, | ||||
| 37 | }; | ||||
| 38 | |||||
| 39 | 1 | 14µs | our $TEXT_VMETHODS = { | ||
| 40 | item => \&text_item, | ||||
| 41 | list => \&text_list, | ||||
| 42 | hash => \&text_hash, | ||||
| 43 | length => \&text_length, | ||||
| 44 | size => \&text_size, | ||||
| 45 | empty => \&text_empty, | ||||
| 46 | defined => \&text_defined, | ||||
| 47 | upper => \&text_upper, | ||||
| 48 | lower => \&text_lower, | ||||
| 49 | ucfirst => \&text_ucfirst, | ||||
| 50 | lcfirst => \&text_lcfirst, | ||||
| 51 | match => \&text_match, | ||||
| 52 | search => \&text_search, | ||||
| 53 | repeat => \&text_repeat, | ||||
| 54 | replace => \&text_replace, | ||||
| 55 | remove => \&text_remove, | ||||
| 56 | split => \&text_split, | ||||
| 57 | chunk => \&text_chunk, | ||||
| 58 | substr => \&text_substr, | ||||
| 59 | trim => \&text_trim, | ||||
| 60 | collapse => \&text_collapse, | ||||
| 61 | squote => \&text_squote, | ||||
| 62 | dquote => \&text_dquote, | ||||
| 63 | html => \&Template::Filters::html_filter, | ||||
| 64 | xml => \&Template::Filters::xml_filter, | ||||
| 65 | }; | ||||
| 66 | |||||
| 67 | 1 | 7µs | our $HASH_VMETHODS = { | ||
| 68 | item => \&hash_item, | ||||
| 69 | hash => \&hash_hash, | ||||
| 70 | size => \&hash_size, | ||||
| 71 | empty => \&hash_empty, | ||||
| 72 | each => \&hash_each, | ||||
| 73 | keys => \&hash_keys, | ||||
| 74 | values => \&hash_values, | ||||
| 75 | items => \&hash_items, | ||||
| 76 | pairs => \&hash_pairs, | ||||
| 77 | list => \&hash_list, | ||||
| 78 | exists => \&hash_exists, | ||||
| 79 | defined => \&hash_defined, | ||||
| 80 | delete => \&hash_delete, | ||||
| 81 | import => \&hash_import, | ||||
| 82 | sort => \&hash_sort, | ||||
| 83 | nsort => \&hash_nsort, | ||||
| 84 | }; | ||||
| 85 | |||||
| 86 | 1 | 9µs | our $LIST_VMETHODS = { | ||
| 87 | item => \&list_item, | ||||
| 88 | list => \&list_list, | ||||
| 89 | hash => \&list_hash, | ||||
| 90 | push => \&list_push, | ||||
| 91 | pop => \&list_pop, | ||||
| 92 | unshift => \&list_unshift, | ||||
| 93 | shift => \&list_shift, | ||||
| 94 | max => \&list_max, | ||||
| 95 | size => \&list_size, | ||||
| 96 | empty => \&list_empty, | ||||
| 97 | defined => \&list_defined, | ||||
| 98 | first => \&list_first, | ||||
| 99 | last => \&list_last, | ||||
| 100 | reverse => \&list_reverse, | ||||
| 101 | grep => \&list_grep, | ||||
| 102 | join => \&list_join, | ||||
| 103 | sort => \&list_sort, | ||||
| 104 | nsort => \&list_nsort, | ||||
| 105 | unique => \&list_unique, | ||||
| 106 | import => \&list_import, | ||||
| 107 | merge => \&list_merge, | ||||
| 108 | slice => \&list_slice, | ||||
| 109 | splice => \&list_splice, | ||||
| 110 | }; | ||||
| 111 | |||||
| 112 | |||||
| 113 | #======================================================================== | ||||
| 114 | # root virtual methods | ||||
| 115 | #======================================================================== | ||||
| 116 | |||||
| 117 | sub root_inc { | ||||
| 118 | 2 | 44µs | 2 | 59µs | # spent 34µs (8+25) within Template::VMethods::BEGIN@118 which was called:
# once (8µs+25µs) by Template::Stash::BEGIN@24 at line 118 # spent 34µs making 1 call to Template::VMethods::BEGIN@118
# spent 25µs making 1 call to warnings::unimport |
| 119 | my $item = shift; | ||||
| 120 | ++$item; | ||||
| 121 | } | ||||
| 122 | |||||
| 123 | sub root_dec { | ||||
| 124 | 2 | 1.65ms | 2 | 26µs | # spent 16µs (5+11) within Template::VMethods::BEGIN@124 which was called:
# once (5µs+11µs) by Template::Stash::BEGIN@24 at line 124 # spent 16µs making 1 call to Template::VMethods::BEGIN@124
# spent 11µs making 1 call to warnings::unimport |
| 125 | my $item = shift; | ||||
| 126 | --$item; | ||||
| 127 | } | ||||
| 128 | |||||
| 129 | |||||
| 130 | #======================================================================== | ||||
| 131 | # text virtual methods | ||||
| 132 | #======================================================================== | ||||
| 133 | |||||
| 134 | sub text_item { | ||||
| 135 | $_[0]; | ||||
| 136 | } | ||||
| 137 | |||||
| 138 | sub text_list { | ||||
| 139 | [ $_[0] ]; | ||||
| 140 | } | ||||
| 141 | |||||
| 142 | sub text_hash { | ||||
| 143 | { value => $_[0] }; | ||||
| 144 | } | ||||
| 145 | |||||
| 146 | sub text_length { | ||||
| 147 | length $_[0]; | ||||
| 148 | } | ||||
| 149 | |||||
| 150 | sub text_size { | ||||
| 151 | return 1; | ||||
| 152 | } | ||||
| 153 | |||||
| 154 | sub text_empty { | ||||
| 155 | return 0 == text_length($_[0]) ? 1 : 0; | ||||
| 156 | } | ||||
| 157 | |||||
| 158 | sub text_defined { | ||||
| 159 | return 1; | ||||
| 160 | } | ||||
| 161 | |||||
| 162 | sub text_upper { | ||||
| 163 | return uc $_[0]; | ||||
| 164 | } | ||||
| 165 | |||||
| 166 | sub text_lower { | ||||
| 167 | return lc $_[0]; | ||||
| 168 | } | ||||
| 169 | |||||
| 170 | sub text_ucfirst { | ||||
| 171 | return ucfirst $_[0]; | ||||
| 172 | } | ||||
| 173 | |||||
| 174 | sub text_lcfirst { | ||||
| 175 | return lcfirst $_[0]; | ||||
| 176 | } | ||||
| 177 | |||||
| 178 | sub text_trim { | ||||
| 179 | for ($_[0]) { | ||||
| 180 | s/^\s+//; | ||||
| 181 | s/\s+$//; | ||||
| 182 | } | ||||
| 183 | return $_[0]; | ||||
| 184 | } | ||||
| 185 | |||||
| 186 | sub text_collapse { | ||||
| 187 | for ($_[0]) { | ||||
| 188 | s/^\s+//; | ||||
| 189 | s/\s+$//; | ||||
| 190 | s/\s+/ /g | ||||
| 191 | } | ||||
| 192 | return $_[0]; | ||||
| 193 | } | ||||
| 194 | |||||
| 195 | sub text_match { | ||||
| 196 | my ($str, $search, $global) = @_; | ||||
| 197 | return $str unless defined $str and defined $search; | ||||
| 198 | my @matches = $global ? ($str =~ /$search/g) | ||||
| 199 | : ($str =~ /$search/); | ||||
| 200 | return @matches ? \@matches : ''; | ||||
| 201 | } | ||||
| 202 | |||||
| 203 | sub text_search { | ||||
| 204 | my ($str, $pattern) = @_; | ||||
| 205 | return $str unless defined $str and defined $pattern; | ||||
| 206 | return $str =~ /$pattern/; | ||||
| 207 | } | ||||
| 208 | |||||
| 209 | sub text_repeat { | ||||
| 210 | my ($str, $count) = @_; | ||||
| 211 | $str = '' unless defined $str; | ||||
| 212 | return '' unless $count; | ||||
| 213 | $count ||= 1; | ||||
| 214 | return $str x $count; | ||||
| 215 | } | ||||
| 216 | |||||
| 217 | sub text_replace { | ||||
| 218 | my ($text, $pattern, $replace, $global) = @_; | ||||
| 219 | $text = '' unless defined $text; | ||||
| 220 | $pattern = '' unless defined $pattern; | ||||
| 221 | $replace = '' unless defined $replace; | ||||
| 222 | $global = 1 unless defined $global; | ||||
| 223 | |||||
| 224 | if ($replace =~ /\$\d+/) { | ||||
| 225 | # replacement string may contain backrefs | ||||
| 226 | my $expand = sub { | ||||
| 227 | my ($chunk, $start, $end) = @_; | ||||
| 228 | $chunk =~ s{ \\(\\|\$) | \$ (\d+) }{ | ||||
| 229 | $1 ? $1 | ||||
| 230 | : ($2 > $#$start || $2 == 0 || !defined $start->[$2]) ? '' | ||||
| 231 | : substr($text, $start->[$2], $end->[$2] - $start->[$2]); | ||||
| 232 | }exg; | ||||
| 233 | $chunk; | ||||
| 234 | }; | ||||
| 235 | if ($global) { | ||||
| 236 | $text =~ s{$pattern}{ &$expand($replace, [@-], [@+]) }eg; | ||||
| 237 | } | ||||
| 238 | else { | ||||
| 239 | $text =~ s{$pattern}{ &$expand($replace, [@-], [@+]) }e; | ||||
| 240 | } | ||||
| 241 | } | ||||
| 242 | else { | ||||
| 243 | if ($global) { | ||||
| 244 | $text =~ s/$pattern/$replace/g; | ||||
| 245 | } | ||||
| 246 | else { | ||||
| 247 | $text =~ s/$pattern/$replace/; | ||||
| 248 | } | ||||
| 249 | } | ||||
| 250 | return $text; | ||||
| 251 | } | ||||
| 252 | |||||
| 253 | sub text_remove { | ||||
| 254 | my ($str, $search) = @_; | ||||
| 255 | return $str unless defined $str and defined $search; | ||||
| 256 | $str =~ s/$search//g; | ||||
| 257 | return $str; | ||||
| 258 | } | ||||
| 259 | |||||
| 260 | sub text_split { | ||||
| 261 | my ($str, $split, $limit) = @_; | ||||
| 262 | $str = '' unless defined $str; | ||||
| 263 | |||||
| 264 | # For versions of Perl prior to 5.18 we have to be very careful about | ||||
| 265 | # spelling out each possible combination of arguments because split() | ||||
| 266 | # is very sensitive to them, for example C<split(' ', ...)> behaves | ||||
| 267 | # differently to C<$space=' '; split($space, ...)>. Test 33 of | ||||
| 268 | # vmethods/text.t depends on this behaviour. | ||||
| 269 | |||||
| 270 | if ($] < 5.018) { | ||||
| 271 | if (defined $limit) { | ||||
| 272 | return [ defined $split | ||||
| 273 | ? split($split, $str, $limit) | ||||
| 274 | : split(' ', $str, $limit) ]; | ||||
| 275 | } | ||||
| 276 | else { | ||||
| 277 | return [ defined $split | ||||
| 278 | ? split($split, $str) | ||||
| 279 | : split(' ', $str) ]; | ||||
| 280 | } | ||||
| 281 | } | ||||
| 282 | |||||
| 283 | # split's behavior changed in Perl 5.18.0 making this: | ||||
| 284 | # C<$space=' '; split($space, ...)> | ||||
| 285 | # behave the same as this: | ||||
| 286 | # C<split(' ', ...)> | ||||
| 287 | # qr// behaves the same, so use that for user-defined split. | ||||
| 288 | |||||
| 289 | my $split_re; | ||||
| 290 | if (defined $split) { | ||||
| 291 | eval { | ||||
| 292 | $split_re = qr/$split/; | ||||
| 293 | }; | ||||
| 294 | } | ||||
| 295 | $split_re = ' ' unless defined $split_re; | ||||
| 296 | $limit ||= 0; | ||||
| 297 | return [split($split_re, $str, $limit)]; | ||||
| 298 | } | ||||
| 299 | |||||
| 300 | sub text_chunk { | ||||
| 301 | my ($string, $size) = @_; | ||||
| 302 | my @list; | ||||
| 303 | $size ||= 1; | ||||
| 304 | if ($size < 0) { | ||||
| 305 | # sexeger! It's faster to reverse the string, search | ||||
| 306 | # it from the front and then reverse the output than to | ||||
| 307 | # search it from the end, believe it nor not! | ||||
| 308 | $string = reverse $string; | ||||
| 309 | $size = -$size; | ||||
| 310 | unshift(@list, scalar reverse $1) | ||||
| 311 | while ($string =~ /((.{$size})|(.+))/g); | ||||
| 312 | } | ||||
| 313 | else { | ||||
| 314 | push(@list, $1) while ($string =~ /((.{$size})|(.+))/g); | ||||
| 315 | } | ||||
| 316 | return \@list; | ||||
| 317 | } | ||||
| 318 | |||||
| 319 | # spent 32.7ms within Template::VMethods::text_substr which was called 3981 times, avg 8µs/call:
# 3981 times (32.7ms+0s) by Template::Stash::XS::get at line 1 of /root/tor-browser-build/input text, avg 8µs/call | ||||
| 320 | 3981 | 4.29ms | my ($text, $offset, $length, $replacement) = @_; | ||
| 321 | 3981 | 3.08ms | $offset ||= 0; | ||
| 322 | |||||
| 323 | 3981 | 2.47ms | if(defined $length) { | ||
| 324 | 3981 | 2.74ms | if (defined $replacement) { | ||
| 325 | substr( $text, $offset, $length, $replacement ); | ||||
| 326 | return $text; | ||||
| 327 | } | ||||
| 328 | else { | ||||
| 329 | 3981 | 26.0ms | return substr( $text, $offset, $length ); | ||
| 330 | } | ||||
| 331 | } | ||||
| 332 | else { | ||||
| 333 | return substr( $text, $offset ); | ||||
| 334 | } | ||||
| 335 | } | ||||
| 336 | |||||
| 337 | sub text_squote { | ||||
| 338 | my $text = shift; | ||||
| 339 | for ($text) { | ||||
| 340 | s/(['\\])/\\$1/g; | ||||
| 341 | } | ||||
| 342 | return $text; | ||||
| 343 | } | ||||
| 344 | |||||
| 345 | sub text_dquote { | ||||
| 346 | my $text = shift; | ||||
| 347 | for ($text) { | ||||
| 348 | s/(["\\])/\\$1/g; | ||||
| 349 | s/\n/\\n/g; | ||||
| 350 | } | ||||
| 351 | return $text; | ||||
| 352 | } | ||||
| 353 | |||||
| 354 | #======================================================================== | ||||
| 355 | # hash virtual methods | ||||
| 356 | #======================================================================== | ||||
| 357 | |||||
| 358 | |||||
| 359 | sub hash_item { | ||||
| 360 | my ($hash, $item) = @_; | ||||
| 361 | $item = '' unless defined $item; | ||||
| 362 | return if $PRIVATE && $item =~ /$PRIVATE/; | ||||
| 363 | $hash->{ $item }; | ||||
| 364 | } | ||||
| 365 | |||||
| 366 | sub hash_hash { | ||||
| 367 | $_[0]; | ||||
| 368 | } | ||||
| 369 | |||||
| 370 | sub hash_size { | ||||
| 371 | scalar keys %{$_[0]}; | ||||
| 372 | } | ||||
| 373 | |||||
| 374 | sub hash_empty { | ||||
| 375 | return 0 == hash_size($_[0]) ? 1 : 0; | ||||
| 376 | } | ||||
| 377 | |||||
| 378 | sub hash_each { | ||||
| 379 | # this will be changed in TT3 to do what hash_pairs() does | ||||
| 380 | [ %{ $_[0] } ]; | ||||
| 381 | } | ||||
| 382 | |||||
| 383 | sub hash_keys { | ||||
| 384 | [ keys %{ $_[0] } ]; | ||||
| 385 | } | ||||
| 386 | |||||
| 387 | sub hash_values { | ||||
| 388 | [ values %{ $_[0] } ]; | ||||
| 389 | } | ||||
| 390 | |||||
| 391 | sub hash_items { | ||||
| 392 | [ %{ $_[0] } ]; | ||||
| 393 | } | ||||
| 394 | |||||
| 395 | sub hash_pairs { | ||||
| 396 | [ map { | ||||
| 397 | { key => $_ , value => $_[0]->{ $_ } } | ||||
| 398 | } | ||||
| 399 | sort keys %{ $_[0] } | ||||
| 400 | ]; | ||||
| 401 | } | ||||
| 402 | |||||
| 403 | sub hash_list { | ||||
| 404 | my ($hash, $what) = @_; | ||||
| 405 | $what ||= ''; | ||||
| 406 | return ($what eq 'keys') ? [ keys %$hash ] | ||||
| 407 | : ($what eq 'values') ? [ values %$hash ] | ||||
| 408 | : ($what eq 'each') ? [ %$hash ] | ||||
| 409 | : # for now we do what pairs does but this will be changed | ||||
| 410 | # in TT3 to return [ $hash ] by default | ||||
| 411 | [ map { { key => $_ , value => $hash->{ $_ } } } | ||||
| 412 | sort keys %$hash | ||||
| 413 | ]; | ||||
| 414 | } | ||||
| 415 | |||||
| 416 | sub hash_exists { | ||||
| 417 | exists $_[0]->{ $_[1] }; | ||||
| 418 | } | ||||
| 419 | |||||
| 420 | sub hash_defined { | ||||
| 421 | # return the item requested, or 1 if no argument | ||||
| 422 | # to indicate that the hash itself is defined | ||||
| 423 | my $hash = shift; | ||||
| 424 | return @_ ? defined $hash->{ $_[0] } : 1; | ||||
| 425 | } | ||||
| 426 | |||||
| 427 | sub hash_delete { | ||||
| 428 | my $hash = shift; | ||||
| 429 | delete $hash->{ $_ } for @_; | ||||
| 430 | } | ||||
| 431 | |||||
| 432 | sub hash_import { | ||||
| 433 | my ($hash, $imp) = @_; | ||||
| 434 | $imp = {} unless ref $imp eq 'HASH'; | ||||
| 435 | @$hash{ keys %$imp } = values %$imp; | ||||
| 436 | return ''; | ||||
| 437 | } | ||||
| 438 | |||||
| 439 | sub hash_sort { | ||||
| 440 | my ($hash) = @_; | ||||
| 441 | [ sort { lc $hash->{$a} cmp lc $hash->{$b} } (keys %$hash) ]; | ||||
| 442 | } | ||||
| 443 | |||||
| 444 | sub hash_nsort { | ||||
| 445 | my ($hash) = @_; | ||||
| 446 | [ sort { $hash->{$a} <=> $hash->{$b} } (keys %$hash) ]; | ||||
| 447 | } | ||||
| 448 | |||||
| 449 | |||||
| 450 | #======================================================================== | ||||
| 451 | # list virtual methods | ||||
| 452 | #======================================================================== | ||||
| 453 | |||||
| 454 | |||||
| 455 | sub list_item { | ||||
| 456 | $_[0]->[ $_[1] || 0 ]; | ||||
| 457 | } | ||||
| 458 | |||||
| 459 | sub list_list { | ||||
| 460 | $_[0]; | ||||
| 461 | } | ||||
| 462 | |||||
| 463 | sub list_hash { | ||||
| 464 | my $list = shift; | ||||
| 465 | if (@_) { | ||||
| 466 | my $n = shift || 0; | ||||
| 467 | return { map { ($n++, $_) } @$list }; | ||||
| 468 | } | ||||
| 469 | 2 | 124µs | 2 | 47µs | # spent 29µs (12+18) within Template::VMethods::BEGIN@469 which was called:
# once (12µs+18µs) by Template::Stash::BEGIN@24 at line 469 # spent 29µs making 1 call to Template::VMethods::BEGIN@469
# spent 18µs making 1 call to warnings::unimport |
| 470 | return { @$list }; | ||||
| 471 | } | ||||
| 472 | |||||
| 473 | sub list_push { | ||||
| 474 | my $list = shift; | ||||
| 475 | push(@$list, @_); | ||||
| 476 | return ''; | ||||
| 477 | } | ||||
| 478 | |||||
| 479 | sub list_pop { | ||||
| 480 | my $list = shift; | ||||
| 481 | pop(@$list); | ||||
| 482 | } | ||||
| 483 | |||||
| 484 | sub list_unshift { | ||||
| 485 | my $list = shift; | ||||
| 486 | unshift(@$list, @_); | ||||
| 487 | return ''; | ||||
| 488 | } | ||||
| 489 | |||||
| 490 | sub list_shift { | ||||
| 491 | my $list = shift; | ||||
| 492 | shift(@$list); | ||||
| 493 | } | ||||
| 494 | |||||
| 495 | sub list_max { | ||||
| 496 | 2 | 39µs | 2 | 30µs | # spent 18µs (6+12) within Template::VMethods::BEGIN@496 which was called:
# once (6µs+12µs) by Template::Stash::BEGIN@24 at line 496 # spent 18µs making 1 call to Template::VMethods::BEGIN@496
# spent 12µs making 1 call to warnings::unimport |
| 497 | my $list = shift; | ||||
| 498 | $#$list; | ||||
| 499 | } | ||||
| 500 | |||||
| 501 | sub list_size { | ||||
| 502 | 2 | 908µs | 2 | 25µs | # spent 15µs (5+10) within Template::VMethods::BEGIN@502 which was called:
# once (5µs+10µs) by Template::Stash::BEGIN@24 at line 502 # spent 15µs making 1 call to Template::VMethods::BEGIN@502
# spent 10µs making 1 call to warnings::unimport |
| 503 | my $list = shift; | ||||
| 504 | $#$list + 1; | ||||
| 505 | } | ||||
| 506 | |||||
| 507 | sub list_empty { | ||||
| 508 | return 0 == list_size($_[0]) ? 1 : 0; | ||||
| 509 | } | ||||
| 510 | |||||
| 511 | sub list_defined { | ||||
| 512 | # return the item requested, or 1 if no argument to | ||||
| 513 | # indicate that the hash itself is defined | ||||
| 514 | my $list = shift; | ||||
| 515 | return 1 unless @_; # list.defined is always true | ||||
| 516 | return unless looks_like_number $_[0]; # list.defined('bah') is always false | ||||
| 517 | return defined $list->[$_[0]]; # list.defined(n) | ||||
| 518 | } | ||||
| 519 | |||||
| 520 | sub list_first { | ||||
| 521 | my $list = shift; | ||||
| 522 | return $list->[0] unless @_; | ||||
| 523 | return [ @$list[0..$_[0]-1] ]; | ||||
| 524 | } | ||||
| 525 | |||||
| 526 | sub list_last { | ||||
| 527 | my $list = shift; | ||||
| 528 | return $list->[-1] unless @_; | ||||
| 529 | return [ @$list[-$_[0]..-1] ]; | ||||
| 530 | } | ||||
| 531 | |||||
| 532 | sub list_reverse { | ||||
| 533 | my $list = shift; | ||||
| 534 | [ reverse @$list ]; | ||||
| 535 | } | ||||
| 536 | |||||
| 537 | sub list_grep { | ||||
| 538 | my ($list, $pattern) = @_; | ||||
| 539 | $pattern ||= ''; | ||||
| 540 | return [ grep /$pattern/, @$list ]; | ||||
| 541 | } | ||||
| 542 | |||||
| 543 | sub list_join { | ||||
| 544 | my ($list, $joint) = @_; | ||||
| 545 | join(defined $joint ? $joint : ' ', | ||||
| 546 | map { defined $_ ? $_ : '' } @$list); | ||||
| 547 | } | ||||
| 548 | |||||
| 549 | sub _list_sort_make_key { | ||||
| 550 | my ($item, $fields) = @_; | ||||
| 551 | my @keys; | ||||
| 552 | |||||
| 553 | if (ref($item) eq 'HASH') { | ||||
| 554 | @keys = map { $item->{ $_ } } @$fields; | ||||
| 555 | } | ||||
| 556 | elsif (blessed $item) { | ||||
| 557 | @keys = map { $item->can($_) ? $item->$_() : $item } @$fields; | ||||
| 558 | } | ||||
| 559 | else { | ||||
| 560 | @keys = $item; | ||||
| 561 | } | ||||
| 562 | |||||
| 563 | # ugly hack to generate a single string using a delimiter that is | ||||
| 564 | # unlikely (but not impossible) to be found in the wild. | ||||
| 565 | return lc join('/*^UNLIKELY^*/', map { defined $_ ? $_ : '' } @keys); | ||||
| 566 | } | ||||
| 567 | |||||
| 568 | # spent 66.7ms (45.2+21.4) within Template::VMethods::list_sort which was called 1991 times, avg 33µs/call:
# 1991 times (45.2ms+21.4ms) by Template::Stash::XS::get at line 11 of /root/tor-browser-build/input text, avg 33µs/call | ||||
| 569 | 1991 | 1.38ms | my ($list, @fields) = @_; | ||
| 570 | 1991 | 1.95ms | return $list unless @$list > 1; # no need to sort 1 item lists | ||
| 571 | return [ | ||||
| 572 | @fields # Schwartzian Transform | ||||
| 573 | ? map { $_->[0] } # for case insensitivity | ||||
| 574 | sort { $a->[1] cmp $b->[1] } | ||||
| 575 | map { [ $_, _list_sort_make_key($_, \@fields) ] } | ||||
| 576 | @$list | ||||
| 577 | : map { $_->[0] } | ||||
| 578 | sort { $a->[1] cmp $b->[1] } | ||||
| 579 | 1991 | 71.8ms | 1991 | 21.4ms | map { [ $_, lc $_ ] } # spent 21.4ms making 1991 calls to Template::VMethods::CORE:sort, avg 11µs/call |
| 580 | @$list, | ||||
| 581 | ]; | ||||
| 582 | } | ||||
| 583 | |||||
| 584 | sub list_nsort { | ||||
| 585 | my ($list, @fields) = @_; | ||||
| 586 | return $list unless @$list > 1; # no need to sort 1 item lists | ||||
| 587 | |||||
| 588 | my $sort = sub { | ||||
| 589 | my $cmp; | ||||
| 590 | |||||
| 591 | if(@fields) { | ||||
| 592 | # compare each field individually | ||||
| 593 | for my $field (@fields) { | ||||
| 594 | my $A = _list_sort_make_key($a, [ $field ]); | ||||
| 595 | my $B = _list_sort_make_key($b, [ $field ]); | ||||
| 596 | ($cmp = $A <=> $B) and last; | ||||
| 597 | } | ||||
| 598 | } | ||||
| 599 | else { | ||||
| 600 | my $A = _list_sort_make_key($a); | ||||
| 601 | my $B = _list_sort_make_key($b); | ||||
| 602 | $cmp = $A <=> $B; | ||||
| 603 | } | ||||
| 604 | |||||
| 605 | $cmp; | ||||
| 606 | }; | ||||
| 607 | |||||
| 608 | return [ sort $sort @{ $list } ]; | ||||
| 609 | } | ||||
| 610 | |||||
| 611 | sub list_unique { | ||||
| 612 | my %u; | ||||
| 613 | [ grep { ++$u{$_} == 1 } @{$_[0]} ]; | ||||
| 614 | } | ||||
| 615 | |||||
| 616 | # spent 22.6ms within Template::VMethods::list_import which was called 1991 times, avg 11µs/call:
# 1991 times (22.6ms+0s) by Template::Stash::XS::get at line 11 of /root/tor-browser-build/input text, avg 11µs/call | ||||
| 617 | 1991 | 1.35ms | my $list = shift; | ||
| 618 | 1991 | 15.3ms | push(@$list, grep defined, map ref eq 'ARRAY' ? @$_ : undef, @_); | ||
| 619 | 1991 | 9.33ms | return $list; | ||
| 620 | } | ||||
| 621 | |||||
| 622 | sub list_merge { | ||||
| 623 | my $list = shift; | ||||
| 624 | return [ @$list, grep defined, map ref eq 'ARRAY' ? @$_ : undef, @_ ]; | ||||
| 625 | } | ||||
| 626 | |||||
| 627 | sub list_slice { | ||||
| 628 | my ($list, $from, $to) = @_; | ||||
| 629 | $from ||= 0; | ||||
| 630 | $to = $#$list unless defined $to; | ||||
| 631 | $from += @$list if $from < 0; | ||||
| 632 | $to += @$list if $to < 0; | ||||
| 633 | return [ @$list[$from..$to] ]; | ||||
| 634 | } | ||||
| 635 | |||||
| 636 | sub list_splice { | ||||
| 637 | my ($list, $offset, $length, @replace) = @_; | ||||
| 638 | if (@replace) { | ||||
| 639 | # @replace can contain a list of multiple replace items, or | ||||
| 640 | # be a single reference to a list | ||||
| 641 | @replace = @{ $replace[0] } | ||||
| 642 | if @replace == 1 && ref $replace[0] eq 'ARRAY'; | ||||
| 643 | return [ splice @$list, $offset, $length, @replace ]; | ||||
| 644 | } | ||||
| 645 | elsif (defined $length) { | ||||
| 646 | return [ splice @$list, $offset, $length ]; | ||||
| 647 | } | ||||
| 648 | elsif (defined $offset) { | ||||
| 649 | return [ splice @$list, $offset ]; | ||||
| 650 | } | ||||
| 651 | else { | ||||
| 652 | return [ splice(@$list) ]; | ||||
| 653 | } | ||||
| 654 | } | ||||
| 655 | |||||
| 656 | 1 | 26µs | 1; | ||
| 657 | |||||
| 658 | __END__ | ||||
# spent 21.4ms within Template::VMethods::CORE:sort which was called 1991 times, avg 11µs/call:
# 1991 times (21.4ms+0s) by Template::VMethods::list_sort at line 579, avg 11µs/call | |||||
# spent 500ns within Template::VMethods::__ANON__ which was called:
# once (500ns+0s) by Template::VMethods::BEGIN@27 at line 27 |