Filename | /opt/flows/lib/lib/perl5/Data/OptList.pm |
Statements | Executed 716 statements in 1.78ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 2.12ms | 2.43ms | BEGIN@7 | Data::OptList::
1 | 1 | 1 | 1.46ms | 1.72ms | BEGIN@8 | Data::OptList::
29 | 2 | 2 | 536µs | 611µs | mkopt | Data::OptList::
12 | 2 | 1 | 66µs | 311µs | mkopt_hash | Data::OptList::
23 | 1 | 1 | 31µs | 31µs | __ANON__[:172] | Data::OptList::
1 | 1 | 1 | 20µs | 34µs | BEGIN@1 | Sub::Exporter::
3 | 1 | 1 | 14µs | 44µs | __ANON__[:164] | Data::OptList::
1 | 1 | 1 | 12µs | 20µs | BEGIN@232 | Data::OptList::
1 | 1 | 1 | 8µs | 13µs | BEGIN@2 | Sub::Exporter::
1 | 1 | 1 | 7µs | 7µs | BEGIN@125 | Data::OptList::
1 | 1 | 1 | 4µs | 4µs | BEGIN@6 | Data::OptList::
0 | 0 | 0 | 0s | 0s | __ANON__[:156] | Data::OptList::
0 | 0 | 0 | 0s | 0s | __ANON__[:163] | Data::OptList::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | 2 | 28µs | 2 | 47µs | # spent 34µs (20+14) within Sub::Exporter::BEGIN@1 which was called:
# once (20µs+14µs) by Sub::Exporter::BEGIN@11 at line 1 # spent 34µs making 1 call to Sub::Exporter::BEGIN@1
# spent 14µs making 1 call to strict::import |
2 | 2 | 41µs | 2 | 17µs | # spent 13µs (8+4) within Sub::Exporter::BEGIN@2 which was called:
# once (8µs+4µs) by Sub::Exporter::BEGIN@11 at line 2 # spent 13µs making 1 call to Sub::Exporter::BEGIN@2
# spent 4µs making 1 call to warnings::import |
3 | package Data::OptList; | ||||
4 | # ABSTRACT: parse and validate simple name/value option pairs | ||||
5 | 1 | 600ns | $Data::OptList::VERSION = '0.110'; | ||
6 | 2 | 22µs | 1 | 4µs | # spent 4µs within Data::OptList::BEGIN@6 which was called:
# once (4µs+0s) by Sub::Exporter::BEGIN@11 at line 6 # spent 4µs making 1 call to Data::OptList::BEGIN@6 |
7 | 2 | 155µs | 1 | 2.43ms | # spent 2.43ms (2.12+316µs) within Data::OptList::BEGIN@7 which was called:
# once (2.12ms+316µs) by Sub::Exporter::BEGIN@11 at line 7 # spent 2.43ms making 1 call to Data::OptList::BEGIN@7 |
8 | 3 | 204µs | 2 | 1.73ms | # spent 1.72ms (1.46+261µs) within Data::OptList::BEGIN@8 which was called:
# once (1.46ms+261µs) by Sub::Exporter::BEGIN@11 at line 8 # spent 1.72ms making 1 call to Data::OptList::BEGIN@8
# spent 11µs making 1 call to UNIVERSAL::VERSION |
9 | |||||
10 | #pod =head1 SYNOPSIS | ||||
11 | #pod | ||||
12 | #pod use Data::OptList; | ||||
13 | #pod | ||||
14 | #pod my $options = Data::OptList::mkopt([ | ||||
15 | #pod qw(key1 key2 key3 key4), | ||||
16 | #pod key5 => { ... }, | ||||
17 | #pod key6 => [ ... ], | ||||
18 | #pod key7 => sub { ... }, | ||||
19 | #pod key8 => { ... }, | ||||
20 | #pod key8 => [ ... ], | ||||
21 | #pod ]); | ||||
22 | #pod | ||||
23 | #pod ...is the same thing, more or less, as: | ||||
24 | #pod | ||||
25 | #pod my $options = [ | ||||
26 | #pod [ key1 => undef, ], | ||||
27 | #pod [ key2 => undef, ], | ||||
28 | #pod [ key3 => undef, ], | ||||
29 | #pod [ key4 => undef, ], | ||||
30 | #pod [ key5 => { ... }, ], | ||||
31 | #pod [ key6 => [ ... ], ], | ||||
32 | #pod [ key7 => sub { ... }, ], | ||||
33 | #pod [ key8 => { ... }, ], | ||||
34 | #pod [ key8 => [ ... ], ], | ||||
35 | #pod ]); | ||||
36 | #pod | ||||
37 | #pod =head1 DESCRIPTION | ||||
38 | #pod | ||||
39 | #pod Hashes are great for storing named data, but if you want more than one entry | ||||
40 | #pod for a name, you have to use a list of pairs. Even then, this is really boring | ||||
41 | #pod to write: | ||||
42 | #pod | ||||
43 | #pod $values = [ | ||||
44 | #pod foo => undef, | ||||
45 | #pod bar => undef, | ||||
46 | #pod baz => undef, | ||||
47 | #pod xyz => { ... }, | ||||
48 | #pod ]; | ||||
49 | #pod | ||||
50 | #pod Just look at all those undefs! Don't worry, we can get rid of those: | ||||
51 | #pod | ||||
52 | #pod $values = [ | ||||
53 | #pod map { $_ => undef } qw(foo bar baz), | ||||
54 | #pod xyz => { ... }, | ||||
55 | #pod ]; | ||||
56 | #pod | ||||
57 | #pod Aaaauuugh! We've saved a little typing, but now it requires thought to read, | ||||
58 | #pod and thinking is even worse than typing... and it's got a bug! It looked right, | ||||
59 | #pod didn't it? Well, the C<< xyz => { ... } >> gets consumed by the map, and we | ||||
60 | #pod don't get the data we wanted. | ||||
61 | #pod | ||||
62 | #pod With Data::OptList, you can do this instead: | ||||
63 | #pod | ||||
64 | #pod $values = Data::OptList::mkopt([ | ||||
65 | #pod qw(foo bar baz), | ||||
66 | #pod xyz => { ... }, | ||||
67 | #pod ]); | ||||
68 | #pod | ||||
69 | #pod This works by assuming that any defined scalar is a name and any reference | ||||
70 | #pod following a name is its value. | ||||
71 | #pod | ||||
72 | #pod =func mkopt | ||||
73 | #pod | ||||
74 | #pod my $opt_list = Data::OptList::mkopt($input, \%arg); | ||||
75 | #pod | ||||
76 | #pod Valid arguments are: | ||||
77 | #pod | ||||
78 | #pod moniker - a word used in errors to describe the opt list; encouraged | ||||
79 | #pod require_unique - if true, no name may appear more than once | ||||
80 | #pod must_be - types to which opt list values are limited (described below) | ||||
81 | #pod name_test - a coderef used to test whether a value can be a name | ||||
82 | #pod (described below, but you probably don't want this) | ||||
83 | #pod | ||||
84 | #pod This produces an array of arrays; the inner arrays are name/value pairs. | ||||
85 | #pod Values will be either "undef" or a reference. | ||||
86 | #pod | ||||
87 | #pod Positional parameters may be used for compatibility with the old C<mkopt> | ||||
88 | #pod interface: | ||||
89 | #pod | ||||
90 | #pod my $opt_list = Data::OptList::mkopt($input, $moniker, $req_uni, $must_be); | ||||
91 | #pod | ||||
92 | #pod Valid values for C<$input>: | ||||
93 | #pod | ||||
94 | #pod undef -> [] | ||||
95 | #pod hashref -> [ [ key1 => value1 ] ... ] # non-ref values become undef | ||||
96 | #pod arrayref -> every name followed by a non-name becomes a pair: [ name => ref ] | ||||
97 | #pod every name followed by undef becomes a pair: [ name => undef ] | ||||
98 | #pod otherwise, it becomes [ name => undef ] like so: | ||||
99 | #pod [ "a", "b", [ 1, 2 ] ] -> [ [ a => undef ], [ b => [ 1, 2 ] ] ] | ||||
100 | #pod | ||||
101 | #pod By default, a I<name> is any defined non-reference. The C<name_test> parameter | ||||
102 | #pod can be a code ref that tests whether the argument passed it is a name or not. | ||||
103 | #pod This should be used rarely. Interactions between C<require_unique> and | ||||
104 | #pod C<name_test> are not yet particularly elegant, as C<require_unique> just tests | ||||
105 | #pod string equality. B<This may change.> | ||||
106 | #pod | ||||
107 | #pod The C<must_be> parameter is either a scalar or array of scalars; it defines | ||||
108 | #pod what kind(s) of refs may be values. If an invalid value is found, an exception | ||||
109 | #pod is thrown. If no value is passed for this argument, any reference is valid. | ||||
110 | #pod If C<must_be> specifies that values must be CODE, HASH, ARRAY, or SCALAR, then | ||||
111 | #pod Params::Util is used to check whether the given value can provide that | ||||
112 | #pod interface. Otherwise, it checks that the given value is an object of the kind. | ||||
113 | #pod | ||||
114 | #pod In other words: | ||||
115 | #pod | ||||
116 | #pod [ qw(SCALAR HASH Object::Known) ] | ||||
117 | #pod | ||||
118 | #pod Means: | ||||
119 | #pod | ||||
120 | #pod _SCALAR0($value) or _HASH($value) or _INSTANCE($value, 'Object::Known') | ||||
121 | #pod | ||||
122 | #pod =cut | ||||
123 | |||||
124 | 1 | 100ns | my %test_for; | ||
125 | # spent 7µs within Data::OptList::BEGIN@125 which was called:
# once (7µs+0s) by Sub::Exporter::BEGIN@11 at line 132 | ||||
126 | 1 | 7µs | %test_for = ( | ||
127 | CODE => \&Params::Util::_CODELIKE, ## no critic | ||||
128 | HASH => \&Params::Util::_HASHLIKE, ## no critic | ||||
129 | ARRAY => \&Params::Util::_ARRAYLIKE, ## no critic | ||||
130 | SCALAR => \&Params::Util::_SCALAR0, ## no critic | ||||
131 | ); | ||||
132 | 1 | 542µs | 1 | 7µs | } # spent 7µs making 1 call to Data::OptList::BEGIN@125 |
133 | |||||
134 | # spent 611µs (536+75) within Data::OptList::mkopt which was called 29 times, avg 21µs/call:
# 23 times (347µs+18µs) by Sub::Exporter::__ANON__[/opt/flows/lib/lib/perl5/Sub/Exporter.pm:337] at line 316 of /opt/flows/lib/lib/perl5/Sub/Exporter.pm, avg 16µs/call
# 6 times (189µs+56µs) by Data::OptList::mkopt_hash at line 221, avg 41µs/call | ||||
135 | 29 | 10µs | my ($opt_list) = shift; | ||
136 | |||||
137 | 29 | 5µs | my ($moniker, $require_unique, $must_be); # the old positional args | ||
138 | my ($name_test, $is_a); | ||||
139 | |||||
140 | 29 | 9µs | if (@_) { | ||
141 | 6 | 4µs | if (@_ == 1 and Params::Util::_HASHLIKE($_[0])) { | ||
142 | ($moniker, $require_unique, $must_be, $name_test) | ||||
143 | = @{$_[0]}{ qw(moniker require_unique must_be name_test) }; | ||||
144 | } else { | ||||
145 | 6 | 5µs | ($moniker, $require_unique, $must_be) = @_; | ||
146 | } | ||||
147 | |||||
148 | # Transform the $must_be specification into a closure $is_a | ||||
149 | # that will check if a value matches the spec | ||||
150 | |||||
151 | 6 | 2µs | if (defined $must_be) { | ||
152 | 6 | 2µs | $must_be = [ $must_be ] unless ref $must_be; | ||
153 | 14 | 2µs | my @checks = map { | ||
154 | 6 | 10µs | my $class = $_; | ||
155 | $test_for{$_} | ||||
156 | || sub { $_[1] = $class; goto \&Params::Util::_INSTANCE } | ||||
157 | 14 | 7µs | } @$must_be; | ||
158 | |||||
159 | $is_a = (@checks == 1) | ||||
160 | ? $checks[0] | ||||
161 | # spent 44µs (14+30) within Data::OptList::__ANON__[/opt/flows/lib/lib/perl5/Data/OptList.pm:164] which was called 3 times, avg 15µs/call:
# 3 times (14µs+30µs) by Data::OptList::mkopt at line 195, avg 15µs/call | ||||
162 | 3 | 700ns | my $value = $_[0]; | ||
163 | 4 | 35µs | 4 | 6µs | List::Util::first { defined($_->($value)) } @checks # spent 2µs making 1 call to Params::Util::_HASHLIKE
# spent 2µs making 2 calls to Params::Util::_CODELIKE, avg 1µs/call
# spent 900ns making 1 call to Params::Util::_ARRAYLIKE |
164 | 9 | 27µs | 3 | 30µs | }; # spent 30µs making 3 calls to List::Util::first, avg 10µs/call |
165 | |||||
166 | 6 | 3µs | $moniker = 'unnamed' unless defined $moniker; | ||
167 | } | ||||
168 | } | ||||
169 | |||||
170 | 29 | 6µs | return [] unless $opt_list; | ||
171 | |||||
172 | 52 | 139µs | # spent 31µs within Data::OptList::__ANON__[/opt/flows/lib/lib/perl5/Data/OptList.pm:172] which was called 23 times, avg 1µs/call:
# 23 times (31µs+0s) by Data::OptList::mkopt at line 191, avg 1µs/call | ||
173 | |||||
174 | $opt_list = [ | ||||
175 | 29 | 20µs | map { $_ => (ref $opt_list->{$_} ? $opt_list->{$_} : ()) } keys %$opt_list | ||
176 | ] if ref $opt_list eq 'HASH'; | ||||
177 | |||||
178 | 29 | 4µs | my @return; | ||
179 | 29 | 4µs | my %seen; | ||
180 | |||||
181 | 29 | 50µs | for (my $i = 0; $i < @$opt_list; $i++) { ## no critic | ||
182 | 46 | 17µs | my $name = $opt_list->[$i]; | ||
183 | |||||
184 | 46 | 14µs | if ($require_unique) { | ||
185 | Carp::croak "multiple definitions provided for $name" if $seen{$name}++; | ||||
186 | } | ||||
187 | |||||
188 | 46 | 5µs | my $value; | ||
189 | |||||
190 | 46 | 24µs | if ($i < $#$opt_list) { | ||
191 | 23 | 44µs | 23 | 31µs | if (not defined $opt_list->[$i+1]) { # spent 31µs making 23 calls to Data::OptList::__ANON__[/opt/flows/lib/lib/perl5/Data/OptList.pm:172], avg 1µs/call |
192 | $i++ | ||||
193 | } elsif (! $name_test->($opt_list->[$i+1])) { | ||||
194 | 6 | 3µs | $value = $opt_list->[++$i]; | ||
195 | 6 | 5µs | 3 | 44µs | if ($is_a && !$is_a->($value)) { # spent 44µs making 3 calls to Data::OptList::__ANON__[/opt/flows/lib/lib/perl5/Data/OptList.pm:164], avg 15µs/call |
196 | my $ref = ref $value; | ||||
197 | Carp::croak "$ref-ref values are not valid in $moniker opt list"; | ||||
198 | } | ||||
199 | } | ||||
200 | } | ||||
201 | |||||
202 | 46 | 47µs | push @return, [ $name => $value ]; | ||
203 | } | ||||
204 | |||||
205 | 29 | 173µs | return \@return; | ||
206 | } | ||||
207 | |||||
208 | #pod =func mkopt_hash | ||||
209 | #pod | ||||
210 | #pod my $opt_hash = Data::OptList::mkopt_hash($input, $moniker, $must_be); | ||||
211 | #pod | ||||
212 | #pod Given valid C<L</mkopt>> input, this routine returns a reference to a hash. It | ||||
213 | #pod will throw an exception if any name has more than one value. | ||||
214 | #pod | ||||
215 | #pod =cut | ||||
216 | |||||
217 | # spent 311µs (66+245) within Data::OptList::mkopt_hash which was called 12 times, avg 26µs/call:
# 8 times (54µs+194µs) by Sub::Exporter::_rewrite_build_config at line 253 of /opt/flows/lib/lib/perl5/Sub/Exporter.pm, avg 31µs/call
# 4 times (12µs+51µs) by Sub::Exporter::_rewrite_build_config at line 266 of /opt/flows/lib/lib/perl5/Sub/Exporter.pm, avg 16µs/call | ||||
218 | 12 | 9µs | my ($opt_list, $moniker, $must_be) = @_; | ||
219 | 12 | 15µs | return {} unless $opt_list; | ||
220 | |||||
221 | 6 | 7µs | 6 | 245µs | $opt_list = mkopt($opt_list, $moniker, 1, $must_be); # spent 245µs making 6 calls to Data::OptList::mkopt, avg 41µs/call |
222 | 6 | 22µs | my %hash = map { $_->[0] => $_->[1] } @$opt_list; | ||
223 | 6 | 18µs | return \%hash; | ||
224 | } | ||||
225 | |||||
226 | #pod =head1 EXPORTS | ||||
227 | #pod | ||||
228 | #pod Both C<mkopt> and C<mkopt_hash> may be exported on request. | ||||
229 | #pod | ||||
230 | #pod =cut | ||||
231 | |||||
232 | # spent 20µs (12+8) within Data::OptList::BEGIN@232 which was called:
# once (12µs+8µs) by Sub::Exporter::BEGIN@11 at line 236 | ||||
233 | 1 | 6µs | 1 | 8µs | *import = Sub::Install::exporter { # spent 8µs making 1 call to Sub::Install::exporter |
234 | exports => [qw(mkopt mkopt_hash)], | ||||
235 | }; | ||||
236 | 1 | 26µs | 1 | 20µs | } # spent 20µs making 1 call to Data::OptList::BEGIN@232 |
237 | |||||
238 | 1 | 3µs | 1; | ||
239 | |||||
240 | __END__ |