File | /wise/base/deliv/dev/lib/perl/WISE/IPACTbl.pm | Statements Executed | 210479 | Total Time | 0.210701000000103 seconds |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine | |
---|---|---|---|---|---|---|
1 | 1 | 1 | 0.20209 | 0.20757 | WISE::IPACTbl:: | new |
2 | 2 | 1 | 4.2e-5 | 4.2e-5 | WISE::IPACTbl:: | _is_opt |
2 | 2 | 1 | 4.1e-5 | 4.1e-5 | WISE::IPACTbl:: | _rotate_data |
1 | 1 | 1 | 3.6e-5 | 0.06187 | WISE::IPACTbl:: | data_out |
1 | 1 | 1 | 3.2e-5 | 3.2e-5 | WISE::IPACTbl:: | _modes |
1 | 1 | 1 | 1.6e-5 | 0.06189 | WISE::IPACTbl:: | data |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | BEGIN |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl::Meta:: | BEGIN |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl::Meta:: | _meta_unit |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl::Meta:: | meta_band_merge |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl::Meta:: | meta_hash |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl::Meta:: | meta_item |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl::Meta:: | meta_rotate |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl::Meta:: | meta_unit |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl::Meta:: | metafile_meta |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl::Meta:: | new |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | _get_meta |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | _init_as_null |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | _read_tbl |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | _unpack |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | addcol |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | col_pack_templates |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | column_blanks |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | column_index |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | column_names |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | column_types |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | column_units |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | columns |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | columns_read |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | comments |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | done |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | dump_tbl |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | error |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | keepcol |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | keys |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | last_row_nums |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | meta |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | meta_ipac |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | mvcol |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | rmcol |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | rotate_data |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | rows |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | sort_tbl |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | title |
0 | 0 | 0 | 0 | 0 | WISE::IPACTbl:: | totrows |
Line | Stmts. | Exclusive Time | Avg. | Code |
---|---|---|---|---|
1 | ||||
2 | 3 | 3.5e-5 | 1.2e-5 | use strict; # spent 14µs making 1 call to strict::import |
3 | 3 | 5.4e-5 | 1.8e-5 | use warnings; # spent 78µs making 1 call to warnings::import |
4 | ||||
5 | package WISE::IPACTbl; | |||
6 | ||||
7 | 6 | 0.00010 | 1.7e-5 | use 5.010; # spent 47µs making 1 call to feature::import |
8 | ||||
9 | 1 | 1.0e-6 | 1.0e-6 | my $version = '$Id: IPACTbl.pm 7906 2010-05-20 00:56:04Z tim $ '; |
10 | ||||
11 | 3 | 4.3e-5 | 1.4e-5 | use WISE::IOUtils; # spent 35µs making 1 call to Exporter::import |
12 | ||||
13 | 1 | 1.0e-5 | 1.0e-5 | use vars qw/&ncols &ncolumns &nrows &types &type &column_type # spent 385µs making 1 call to vars::import |
14 | &names &name &tblrow &tblrows &key &ipac_meta | |||
15 | &write_tblrows &tblrows_out &addcols &rmcols &keepcols &cols | |||
16 | 2 | 0.00692 | 0.00346 | &blank &blanks &unit &units &mvcols &colix/; |
17 | ||||
18 | # spent 208ms (202+5.48) within WISE::IPACTbl::new which was called
# once (202ms+5.48ms) at line 1199 of /wise/base/deliv/dev/bin/getfix | |||
19 | 1 | 3.0e-6 | 3.0e-6 | my $this = shift; |
20 | # The weird '@_&&$_[-1]' form is needed to avoid a mysterious | |||
21 | # "Modfication of non-creatable array value" error when 'new' is | |||
22 | # mistakenly called as a function instead of a method. | |||
23 | 1 | 1.5e-5 | 1.5e-5 | my $opts = _is_opt(@_&&$_[-1]) ? pop(@_) : {}; # spent 26µs making 1 call to WISE::IPACTbl::_is_opt |
24 | 1 | 6.0e-6 | 6.0e-6 | my $err = "*** $0/WISE::IPACTbl::new"; |
25 | 1 | 2.0e-6 | 2.0e-6 | my $warn = "=== $0/WISE::IPACTbl::new"; |
26 | 1 | 2.0e-6 | 2.0e-6 | my $file = shift || $opts->{file}; |
27 | 1 | 1.0e-6 | 1.0e-6 | die "$err: No input file specified (did you not call new as a method?).\n" |
28 | if ! defined $file; | |||
29 | 1 | 2.0e-6 | 2.0e-6 | my $rawmode = shift || $opts->{mode} || 'r'; |
30 | 1 | 1.5e-5 | 1.5e-5 | my $mode = _modes($rawmode) # spent 32µs making 1 call to WISE::IPACTbl::_modes |
31 | or die "$err: I/O mode '$rawmode' not recognized.\n"; | |||
32 | 1 | 2.0e-6 | 2.0e-6 | my $colnames = $opts->{colnames} || $opts->{cols}; |
33 | 1 | 0 | 0 | $colnames = undef if $colnames && $colnames eq '*'; |
34 | 1 | 1.0e-6 | 1.0e-6 | $colnames = [$colnames] if $colnames && ! ref $colnames; |
35 | 1 | 6.0e-6 | 6.0e-6 | my @ok_mbrs = qw(packed nrows keys comments names types blanks units lens |
36 | start fmts ix read_pack_template); | |||
37 | 1 | 1.0e-6 | 1.0e-6 | my $class = ref($this) || $this; |
38 | 1 | 2.0e-6 | 2.0e-6 | my $fast = $opts->{fast} && ! $opts->{chunk}; |
39 | ||||
40 | 1 | 0 | 0 | my ($obj); |
41 | ||||
42 | # Options for read or write | |||
43 | 1 | 3.0e-6 | 3.0e-6 | $obj->{packed} = $opts->{packed}; |
44 | 1 | 2.0e-6 | 2.0e-6 | $obj->{chunk} = $opts->{chunk}; |
45 | 1 | 1.0e-6 | 1.0e-6 | $obj->{file} = $file; |
46 | 1 | 2.0e-6 | 2.0e-6 | $obj->{file_name} = ! ref($file) ? $file : '<Internal>'; |
47 | 1 | 1.0e-6 | 1.0e-6 | $obj->{debug} = $opts->{debug}; |
48 | 1 | 1.0e-6 | 1.0e-6 | $obj->{fast} = $fast; |
49 | 1 | 2.0e-6 | 2.0e-6 | $obj->{robust} = $opts->{robust}; |
50 | 1 | 2.0e-6 | 2.0e-6 | $obj->{error} = 1; # Reset to 0 uppon success below |
51 | ||||
52 | 1 | 2.0e-6 | 2.0e-6 | if($mode eq 'r') { |
53 | ||||
54 | # Read mode | |||
55 | ||||
56 | $obj->{mode} = 'r'; | |||
57 | $obj->{single} = $opts->{single}; | |||
58 | $obj->{hashrow} = $opts->{hashrow}; | |||
59 | $obj->{aryrow} = $opts->{aryrow}; | |||
60 | $obj->{skip_overflow} = $opts->{skip_overflow}; | |||
61 | $obj->{colnames}= $colnames; | |||
62 | $obj->{pdl} = $opts->{pdl}; | |||
63 | $obj->{cat} = $opts->{cat}; | |||
64 | ||||
65 | if(! $obj->{robust} || ref $file || $file eq '-' || | |||
66 | (-e $file && ! -z _)) { | |||
67 | # Normal error handling; undef return on error | |||
68 | _read_tbl($obj,{hdronly => $opts->{hdronly}}) | |||
69 | or return; | |||
70 | } else { | |||
71 | # Robust handling. | |||
72 | # Return a null table entry so caller can continue processing | |||
73 | warn "$err: File '$file' ".(! -e _ ? "doesn't exist" : "is empty"). | |||
74 | ".\n"; | |||
75 | _init_as_null($obj,$opts); | |||
76 | return bless $obj,$class; | |||
77 | } | |||
78 | ||||
79 | if($obj->{cat} && $opts->{data} && $obj->{rows}) { | |||
80 | my $new = $obj->{rows}; | |||
81 | my $nnew = $obj->{nrows}; | |||
82 | my $old = $opts->{data}; | |||
83 | my $nold = 0; | |||
84 | if(keys %$old) { | |||
85 | ($nold) = grep {$_} # Count of first non-empty column | |||
86 | map { scalar @{$old->{$_}} } keys %$old; | |||
87 | } | |||
88 | my %seen; | |||
89 | my @cols = grep {! $seen{$_}++} (keys %$new, keys %$old); | |||
90 | for my $col (@cols) { | |||
91 | if($old->{$col} && $new->{$col}) { | |||
92 | push @{$old->{$col}}, @{$new->{$col}}; | |||
93 | } elsif($old->{$col}) { | |||
94 | push @{$old->{$col}}, (undef) x $nnew; | |||
95 | } else { | |||
96 | $old->{$col} = [(undef) x $nold]; | |||
97 | push @{$old->{$col}}, @{$new->{$col}}; | |||
98 | } | |||
99 | } | |||
100 | } | |||
101 | ||||
102 | } else { | |||
103 | ||||
104 | # Write or append mode | |||
105 | ||||
106 | 1 | 1.0e-6 | 1.0e-6 | die "$err: Can't handle data ref as file in write mode.\n" |
107 | if ref $file; | |||
108 | ||||
109 | 1 | 1.0e-6 | 1.0e-6 | my $meta_in; |
110 | ||||
111 | 1 | 1.2e-5 | 1.2e-5 | my $append = $mode eq 'a' || $opts->{append}; |
112 | ||||
113 | # Inherit from object | |||
114 | 1 | 0 | 0 | @{$meta_in}{@ok_mbrs} = @{$this}{@ok_mbrs} if ref $this; |
115 | ||||
116 | 1 | 1.0e-6 | 1.0e-6 | $meta_in = shift || $opts->{meta}; # Override |
117 | ||||
118 | 1 | 2.0e-6 | 2.0e-6 | if(($append && ! $opts->{csv}) || $opts->{meta_from}) { |
119 | # Get from existing table file | |||
120 | my $from = $append ? $file : $opts->{meta_from}; | |||
121 | $meta_in = _get_meta($from) | |||
122 | or die "$err: Unable to get header meta info from '$from'.\n"; | |||
123 | if($append && $opts->{data}) { | |||
124 | warn "$warn: Can't resize columns from data in append mode.\n" | |||
125 | if $opts->{data}; | |||
126 | $opts->{data} = undef; | |||
127 | } | |||
128 | } | |||
129 | ||||
130 | # Sterilize meta_in of unwanted members and make a copy | |||
131 | 1 | 1.0e-6 | 1.0e-6 | my %meta_in; |
132 | 1 | 5.2e-5 | 5.2e-5 | @meta_in{@ok_mbrs} = @{$meta_in}{@ok_mbrs}; |
133 | 1 | 1.0e-6 | 1.0e-6 | $meta_in = \%meta_in; |
134 | ||||
135 | 1 | 2.0e-6 | 2.0e-6 | $meta_in->{append} = $append; |
136 | 1 | 2.0e-6 | 2.0e-6 | if($opts->{csv}) { |
137 | $meta_in->{csv} = $opts->{csv}; | |||
138 | $meta_in->{nohdr} = 1; | |||
139 | $meta_in->{nokeys} = 1; | |||
140 | $meta_in->{nocoms} = 1; | |||
141 | } else { | |||
142 | 1 | 2.0e-6 | 2.0e-6 | $meta_in->{nohdr} = $opts->{nohdr}; |
143 | 1 | 2.0e-6 | 2.0e-6 | $meta_in->{nokeys} = $opts->{nokeys}; |
144 | 1 | 1.0e-6 | 1.0e-6 | $meta_in->{nocoms} = $opts->{nocoms}; |
145 | } | |||
146 | ||||
147 | 1 | 1.0e-6 | 1.0e-6 | my $keys = $meta_in->{nokeys} |
148 | ? undef | |||
149 | : $opts->{keys}//$meta_in->{keys}; | |||
150 | 1 | 2.0e-6 | 2.0e-6 | my $coms = $meta_in->{nocoms} |
151 | ? undef | |||
152 | : $opts->{comments}//$meta_in->{comments}; | |||
153 | ||||
154 | 1 | 2.0e-6 | 2.0e-6 | if(! $meta_in->{csv}) { |
155 | # Regular IPAC table file; header data required | |||
156 | 1 | 3.0e-6 | 3.0e-6 | my @need = qw(names types); |
157 | 1 | 3.0e-6 | 3.0e-6 | my @missing = grep { ! $meta_in->{$_} } @need; |
158 | 1 | 1.0e-6 | 1.0e-6 | die "$err: Missing mandatory meta keys '@missing'.\n" if @missing; |
159 | } | |||
160 | ||||
161 | 1 | 1.0e-6 | 1.0e-6 | my $data = $opts->{data}; |
162 | 1 | 1.6e-5 | 1.6e-5 | my @names = map {lc $_} @{$meta_in->{names}}; |
163 | ||||
164 | 1 | 2.0e-6 | 2.0e-6 | if($data && ! $meta_in->{csv}) { |
165 | # Look for widest column values and widen the o/p column to suit | |||
166 | # if data is supplied | |||
167 | 1 | 1.0e-6 | 1.0e-6 | my %lenix; |
168 | 1 | 1.1e-5 | 1.1e-5 | @lenix{@names} = (0..$#names); |
169 | 1 | 1.1e-5 | 1.1e-5 | $data = _rotate_data($meta_in,$data); # spent 23µs making 1 call to WISE::IPACTbl::_rotate_data |
170 | 1 | 9.0e-6 | 9.0e-6 | for my $col (@names) { |
171 | 8 | 1.6e-5 | 2.0e-6 | next if ! $data->{$col}; |
172 | 8 | 2.4e-5 | 3.0e-6 | my $len = $meta_in->{lens}[$lenix{$col}] || length($col)+1; |
173 | 8 | 5.7e-5 | 7.1e-6 | for my $i (0 .. $#{ $data->{$col} || [] }) { |
174 | 70072 | 0.10116 | 1.4e-6 | my $val = $data->{$col}[$i]||'XX'; |
175 | 70072 | 0.03371 | 4.8e-7 | my $lenval = length($val); |
176 | 70072 | 0.06586 | 9.4e-7 | $len = $lenval+1 if $lenval >= $len; |
177 | } | |||
178 | 8 | 5.0e-5 | 6.3e-6 | $meta_in->{lens}[$lenix{$col}] = $len; |
179 | } | |||
180 | } | |||
181 | ||||
182 | # Massage keys ... | |||
183 | 1 | 1.0e-6 | 1.0e-6 | if($keys) { |
184 | 1 | 2.0e-6 | 2.0e-6 | my($key,$val); |
185 | 1 | 3.0e-6 | 3.0e-6 | my $newkeys = []; |
186 | 1 | 2.0e-6 | 2.0e-6 | while (@$keys) { |
187 | 26 | 2.4e-5 | 9.2e-7 | $key = shift @$keys; |
188 | 26 | 1.5e-5 | 5.8e-7 | if(! ref $key) { |
189 | $val = shift @$keys; | |||
190 | $key = {name=>$key, value=>$val}; | |||
191 | } | |||
192 | 26 | 2.7e-5 | 1.0e-6 | push @$newkeys, $key; |
193 | } | |||
194 | 1 | 1.0e-6 | 1.0e-6 | $keys = $newkeys; |
195 | } | |||
196 | 1 | 5.0e-6 | 5.0e-6 | if(! $meta_in->{nokeys}) { |
197 | 1 | 1.0e-6 | 1.0e-6 | $keys ||= []; |
198 | 1 | 5.3e-5 | 5.3e-5 | push @$keys, {name=>'wsds_release', # spent 100µs making 1 call to WISE::Release::new
# spent 13µs making 1 call to WISE::Release::release |
199 | value=>WISE::Release->new()->release()//'NONE'}; | |||
200 | } | |||
201 | ||||
202 | # Just write the header and leave the file open | |||
203 | 1 | 2.6e-5 | 2.6e-5 | my $fh = WISE::IOUtils::make_ipac_tbl( # spent 5.28ms making 1 call to WISE::IOUtils::make_ipac_tbl |
204 | $file, | |||
205 | $meta_in, | |||
206 | $keys, | |||
207 | undef, # No data; wait for call to data() method | |||
208 | { | |||
209 | noclose => 1, | |||
210 | com => $coms, | |||
211 | nohdr => $meta_in->{nohdr}, | |||
212 | append => $meta_in->{append}, | |||
213 | }) | |||
214 | or die "$err: Unable to create table '$file'.\n"; | |||
215 | # Init meta | |||
216 | 1 | 3.4e-5 | 3.4e-5 | $obj = {%$obj, %$meta_in}; |
217 | # Fill out rest of object meta-data; cribbed from slurp_ipac_tbl(). | |||
218 | # !!! Should be provided by a method or helper func. | |||
219 | 1 | 2.0e-6 | 2.0e-6 | $obj->{obj_fh} = $fh; |
220 | 1 | 2.0e-6 | 2.0e-6 | $obj->{mode} = 'w'; |
221 | 1 | 1.2e-5 | 1.2e-5 | $obj->{cols} = [map {lc $_} @names]; |
222 | 1 | 1.0e-6 | 1.0e-6 | $obj->{nrows} = 0; |
223 | 1 | 2.0e-6 | 2.0e-6 | $obj->{totrows}= 0; |
224 | 1 | 0 | 0 | $obj->{keys} = $keys; |
225 | 1 | 3.0e-6 | 3.0e-6 | $obj->{comments} = $opts->{comments}||$meta_in->{comments}; |
226 | 1 | 2.0e-6 | 2.0e-6 | $obj->{fh} = $fh; |
227 | 1 | 9.0e-6 | 9.0e-6 | $obj->{eof} = 0; |
228 | } | |||
229 | ||||
230 | 1 | 2.0e-6 | 2.0e-6 | $obj->{error} = 0; |
231 | ||||
232 | 1 | 5.2e-5 | 5.2e-5 | return bless $obj,$class; |
233 | } | |||
234 | ||||
235 | sub rotate_data { | |||
236 | my $this = shift; | |||
237 | my $opts = _is_opt(@_&&$_[-1]) ? pop(@_) : {}; | |||
238 | my $data = shift || $opts->{data}; | |||
239 | return _rotate_data($this,$data); | |||
240 | } | |||
241 | ||||
242 | sub meta { | |||
243 | return { %{$_[0]} }; # Unbless !!! Make deeper copy | |||
244 | } | |||
245 | ||||
246 | sub meta_ipac { | |||
247 | my $meta = shift; | |||
248 | $meta = shift if ref $_[0]; | |||
249 | return { | |||
250 | names => [ @{$meta->{names} || []} ], | |||
251 | types => [ @{$meta->{types} || []} ], | |||
252 | units => [ @{$meta->{units} || []} ], | |||
253 | blanks=> [ @{$meta->{blanks}|| []} ], | |||
254 | lens => [ @{$meta->{lens} || []} ], | |||
255 | start => [ @{$meta->{start} || []} ], | |||
256 | fmts => [ @{$meta->{fmts} || []} ], | |||
257 | ix => { %{$meta->{ix} || {}} }, | |||
258 | }; | |||
259 | } | |||
260 | 1 | 4.0e-6 | 4.0e-6 | *ipac_meta = \&meta_ipac; |
261 | ||||
262 | sub _get_meta { | |||
263 | my $file = shift; | |||
264 | my $meta; | |||
265 | (undef,$meta) = | |||
266 | WISE::IOUtils::slurp_ipac_tbl($file, {lc => 1, hdronly => 1}) | |||
267 | or return; | |||
268 | ||||
269 | return $meta; | |||
270 | } | |||
271 | ||||
272 | sub _read_tbl { | |||
273 | my $meta = shift; | |||
274 | my $opts = shift || {}; | |||
275 | my $fast = $opts->{fast} || $meta->{fast}; | |||
276 | ||||
277 | my ($rows,$tmpmeta); | |||
278 | if(! $fast) { | |||
279 | ($rows,$tmpmeta) = | |||
280 | WISE::IOUtils::slurp_ipac_tbl($meta->{file}, | |||
281 | { | |||
282 | meta => $opts->{meta}, | |||
283 | nrows => $meta->{chunk}, | |||
284 | lc => 1, | |||
285 | cols => $meta->{colnames}, | |||
286 | skip_overflow => | |||
287 | $meta->{skip_overflow}, | |||
288 | packed => $meta->{packed}, | |||
289 | ($meta->{pdl} ? (nanblank=>1) : ()), | |||
290 | hdronly => $opts->{hdronly}, | |||
291 | debug => $opts->{debug} || | |||
292 | $meta->{debug}, | |||
293 | }) | |||
294 | or return; | |||
295 | } else { | |||
296 | ($rows,$tmpmeta) = | |||
297 | WISE::IOUtils::gulp_ipac_tbl($meta->{file}, | |||
298 | { | |||
299 | cols=>$meta->{colnames}, | |||
300 | } | |||
301 | ) | |||
302 | or return; | |||
303 | } | |||
304 | ||||
305 | # $tmpmeta also contains 'file', 'ix', 'nrows', etc. | |||
306 | @{$meta}{CORE::keys %$tmpmeta} = values %$tmpmeta; | |||
307 | ||||
308 | $meta->{rows} = $rows; | |||
309 | ||||
310 | return 1; | |||
311 | } | |||
312 | ||||
313 | sub col_pack_templates { | |||
314 | my $this = shift; | |||
315 | state $type_tmpl8s = WISE::IOUtils::type_pack_templates(); | |||
316 | if(! @_) { | |||
317 | my $col_tmpl8s = { map { ( $_ => | |||
318 | $type_tmpl8s-> | |||
319 | {$this->{types}[$this->{ix}{$_}]} ) | |||
320 | } map {lc} @{ $this->{names} } | |||
321 | }; | |||
322 | return wantarray ? %$col_tmpl8s : $col_tmpl8s; | |||
323 | } | |||
324 | my @tmpl8s=@{$type_tmpl8s}{@{$this->{types}}[@{$this->{ix}}{map {lc} @_}]}; | |||
325 | return wantarray | |||
326 | ? @tmpl8s | |||
327 | : join("",@tmpl8s); | |||
328 | } | |||
329 | ||||
330 | sub error { | |||
331 | my $this = shift; | |||
332 | return $this->{error}; | |||
333 | } | |||
334 | ||||
335 | sub comments { | |||
336 | my $this = shift; | |||
337 | return @{$this->{comments}}; | |||
338 | } | |||
339 | ||||
340 | sub column_names { | |||
341 | my $this = shift; | |||
342 | my $opts = _is_opt(@_&&$_[-1]) ? pop(@_) : {}; | |||
343 | my $name = shift || $opts->{name}; | |||
344 | if(! defined $name) { | |||
345 | return wantarray ? @{$this->{names}} : [@{$this->{names}}]; | |||
346 | } else { | |||
347 | return grep { lc($_) eq lc($name) } @{$this->{names}}; | |||
348 | } | |||
349 | } | |||
350 | 1 | 1.0e-6 | 1.0e-6 | *names = \&column_names; |
351 | 1 | 1.0e-6 | 1.0e-6 | *name = \&column_names; |
352 | ||||
353 | sub column_index { | |||
354 | my $this = shift; | |||
355 | my $opts = _is_opt(@_&&$_[-1]) ? pop(@_) : {}; | |||
356 | my $name = shift || $opts->{name}; | |||
357 | if(! defined $name) { | |||
358 | return wantarray ? %{$this->{ix}} : {%{$this->{ix}}}; | |||
359 | } else { | |||
360 | return $this->{ix}{lc $name}; | |||
361 | } | |||
362 | } | |||
363 | 1 | 1.0e-6 | 1.0e-6 | *colix = \&column_index; |
364 | ||||
365 | sub column_types { | |||
366 | my $this = shift; | |||
367 | my $opts = _is_opt(@_&&$_[-1]) ? pop(@_) : {}; | |||
368 | my $col = shift; | |||
369 | my %kv = map { (lc($this->{names}[$_]) => $this->{types}[$_]) } | |||
370 | 0..$#{$this->{names}}; | |||
371 | return $kv{lc $col} if defined $col; | |||
372 | if(! $opts->{kv}) { | |||
373 | return @{$this->{types}}; | |||
374 | } else { | |||
375 | return wantarray ? %kv : \%kv; | |||
376 | } | |||
377 | } | |||
378 | 1 | 1.0e-6 | 1.0e-6 | *types = \&column_types; |
379 | 1 | 1.0e-6 | 1.0e-6 | *column_type = \&column_types; |
380 | 1 | 1.0e-6 | 1.0e-6 | *type = \&column_type; |
381 | ||||
382 | sub column_units { | |||
383 | my $this = shift; | |||
384 | my $opts = _is_opt(@_&&$_[-1]) ? pop(@_) : {}; | |||
385 | my $col = shift; | |||
386 | my %kv = map { (lc($this->{names}[$_]) => $this->{units}[$_]) } | |||
387 | 0..$#{$this->{names}}; | |||
388 | return $kv{lc $col} if defined $col; | |||
389 | if(! $opts->{kv}) { | |||
390 | return @{$this->{types}}; | |||
391 | } else { | |||
392 | return wantarray ? %kv : \%kv; | |||
393 | } | |||
394 | } | |||
395 | 1 | 1.0e-6 | 1.0e-6 | *units = \&column_units; |
396 | 1 | 1.0e-6 | 1.0e-6 | *column_unit = \&column_units; |
397 | 1 | 1.0e-6 | 1.0e-6 | *unit = \&column_unit; |
398 | ||||
399 | sub column_blanks { | |||
400 | my $this = shift; | |||
401 | my $opts = _is_opt(@_&&$_[-1]) ? pop(@_) : {}; | |||
402 | my $col = shift; | |||
403 | my %kv = map { (lc($this->{names}[$_]) => $this->{blanks}[$_]) } | |||
404 | 0..$#{$this->{names}}; | |||
405 | return $kv{lc $col} if defined $col; | |||
406 | if(! $opts->{kv}) { | |||
407 | return @{$this->{types}}; | |||
408 | } else { | |||
409 | return wantarray ? %kv : \%kv; | |||
410 | } | |||
411 | } | |||
412 | 1 | 1.0e-6 | 1.0e-6 | *blanks = \&column_blanks; |
413 | 1 | 1.0e-6 | 1.0e-6 | *column_blank = \&column_blanks; |
414 | 1 | 1.0e-6 | 1.0e-6 | *blank = \&column_blank; |
415 | ||||
416 | sub columns_read { | |||
417 | my $this = shift; | |||
418 | return wantarray ? @{$this->{cols}} : [@{$this->{cols}}];; | |||
419 | } | |||
420 | 1 | 2.0e-6 | 2.0e-6 | *cols = \&columns_read; |
421 | ||||
422 | sub rows { | |||
423 | my $this = shift; | |||
424 | return $this->{nrows}; | |||
425 | } | |||
426 | 1 | 2.0e-6 | 2.0e-6 | *nrows = \&rows; |
427 | ||||
428 | sub totrows { | |||
429 | my $this = shift; | |||
430 | return $this->{totrows}; | |||
431 | } | |||
432 | ||||
433 | sub columns { | |||
434 | my $this = shift; | |||
435 | return scalar @{$this->{cols}}; | |||
436 | } | |||
437 | 1 | 2.0e-6 | 2.0e-6 | *ncols = \&columns; |
438 | 1 | 2.0e-6 | 2.0e-6 | *ncolumns = \&columns; |
439 | ||||
440 | sub done { | |||
441 | my $this = shift; | |||
442 | return $this->{eof}; | |||
443 | } | |||
444 | ||||
445 | # spent 61.9ms (16µs+61.9) within WISE::IPACTbl::data which was called
# once (16µs+61.9ms) at line 1240 of /wise/base/deliv/dev/bin/getfix | |||
446 | 1 | 1.0e-6 | 1.0e-6 | my $this = shift; |
447 | 1 | 1.2e-5 | 1.2e-5 | return data_out($this,@_) if $this->{mode} eq 'w'; # <<<< Output # spent 61.9ms making 1 call to WISE::IPACTbl::data_out |
448 | # vvvv Input vvvv | |||
449 | my $err = "*** $0/WISE::IPACTbl::data(in)"; | |||
450 | my $opts = _is_opt(@_&&$_[-1]) ? pop(@_) : {}; | |||
451 | my $colnames = shift || $opts->{colnames} || $opts->{cols}; | |||
452 | $colnames = [$colnames] if $colnames && ! ref $colnames; | |||
453 | $colnames = undef if $colnames && $colnames->[0] eq '*'; | |||
454 | my $rownums = shift; | |||
455 | $rownums = [$rownums] if defined $rownums && ! ref $rownums; | |||
456 | $rownums = undef if defined $rownums && $rownums->[0] eq '*'; | |||
457 | my $single = $opts->{single} // $this->{single}; | |||
458 | my $ary = ($opts->{aryrow } // $this->{aryrow}); | |||
459 | my $hash = ($opts->{hashrow} // $this->{hashrow}) | |||
460 | || ($rownums && ! $ary); | |||
461 | my $byrow = $ary || $hash; | |||
462 | my $fast = $opts->{fast} // $this->{fast}; | |||
463 | my $lookup = $opts->{lookup}; | |||
464 | my $lookupre = $opts->{lookupre}; | |||
465 | my $lookupcol= $opts->{lookupcol} || 1; | |||
466 | my $aspacked = $opts->{aspacked} && $this->{packed}; | |||
467 | my $aspdl = $this->{pdl}; | |||
468 | my @colnms = map {lc $_} | |||
469 | ($colnames && @$colnames ? @$colnames : @{$this->{cols}}); | |||
470 | ||||
471 | die "$err: Conversion to PDL requested too late.\n" | |||
472 | if ! $aspdl && $opts->{pdl}; | |||
473 | ||||
474 | die "$err: Conversion to PDL is incompatible with byrow and aspacked options.\n" | |||
475 | if $aspdl && ($aspacked || $byrow); | |||
476 | ||||
477 | # In non-incremental mode, all data already exists in the 'rows' | |||
478 | # meta-data. If chunk was specified, we must read a chunk on each | |||
479 | # call of the data method | |||
480 | if($this->{chunk}) { | |||
481 | return 0 if $this->{eof}; | |||
482 | _read_tbl($this,{meta=>$this}) | |||
483 | or return; | |||
484 | return 0 if $this->{eof} && $this->{nrows} == 0; | |||
485 | } | |||
486 | ||||
487 | if(! $byrow) { | |||
488 | # Column-ordered output; most efficient | |||
489 | if(@colnms != 1 || ! $single) { | |||
490 | # Multi column return | |||
491 | my %return = (! $colnames | |||
492 | ? % { _unpack($this,$this->{rows},$aspacked) } | |||
493 | : map { ($_ => | |||
494 | _unpack($this,$this->{rows}{$_},$aspacked,$_)) | |||
495 | } @colnms); | |||
496 | if($aspdl) { | |||
497 | require PDL::Lite; PDL::Lite->import; | |||
498 | for my $col (keys %return) { | |||
499 | if(defined $return{$col}) { | |||
500 | $return{$col} = PDL::Core::pdl($return{$col}); | |||
501 | } | |||
502 | } | |||
503 | } | |||
504 | return wantarray ? %return : \%return; | |||
505 | } else { | |||
506 | # Single column return | |||
507 | my @cols = @{ _unpack($this,$this->{rows}{$colnms[0]}, | |||
508 | $aspacked,$colnms[0]) }; | |||
509 | if($aspdl) { | |||
510 | require PDL::Lite; PDL::Lite->import; | |||
511 | @cols = ( PDL::Core::pdl(\@cols) ); | |||
512 | } | |||
513 | return wantarray ? @cols : \@cols; | |||
514 | } | |||
515 | } else { | |||
516 | # Row-ordered output | |||
517 | die "$err: Don't know how to do row retrieval for packed data.\n" | |||
518 | if $this->{packed}; | |||
519 | my @rows; | |||
520 | push @colnms, $lookupcol if ! grep { lc($lookupcol) eq lc($_) } @colnms; | |||
521 | $rownums ||= [0..$this->{nrows}-1]; | |||
522 | for my $i (@$rownums) { | |||
523 | if(! $single || @colnms != 1) { | |||
524 | push @rows, { map { ($_ => $this->{rows}{$_}[$i]) } @colnms } | |||
525 | if $hash; | |||
526 | push @rows, [ map { $this->{rows}{$_}[$i] } @colnms ] | |||
527 | if $ary; | |||
528 | } else { | |||
529 | push @rows, $this->{rows}{$colnms[0]}[$i]; | |||
530 | } | |||
531 | } | |||
532 | if($lookup || $lookupre) { | |||
533 | $lookupcol = $colnms[0] if @colnms == 1 && $lookup eq '1'; # Default | |||
534 | return if ! $this->{rows}{lc $lookupcol}; | |||
535 | if($lookup) { | |||
536 | # Exact matching (case independent) | |||
537 | $lookup = [$lookup] if ! ref $lookup; | |||
538 | if($opts->{stripap}) { s/^.*:+// for @$lookup; } | |||
539 | my %lookup = map { (lc($_)=>1) } @$lookup; | |||
540 | $rownums = [grep { | |||
541 | my $x = lc $rows[$_]{lc $lookupcol}; | |||
542 | if($opts->{stripap}) { $x =~ s/^.*:+//; } | |||
543 | $lookup{$x} | |||
544 | } | |||
545 | @$rownums]; | |||
546 | } else { | |||
547 | # Regex matching | |||
548 | $lookupre = [$lookupre] if ! ref $lookupre; | |||
549 | $lookupre = [ @$lookupre ]; # Shallow copy to avoid modifying arg | |||
550 | # Make initial '^' or traing '$' refer to the whole RE as a group | |||
551 | # rather than just the first/last eements | |||
552 | my $front = $lookupre->[0] =~ s/^\^(:?)// | |||
553 | ? '^'.($1 ? "(?:.*:)?" : "") : ''; | |||
554 | my $back = $lookupre->[-1] =~ s/\$$// ? '$' : ''; | |||
555 | $lookupre = "$front(?:(?:".join(")|(?:",@$lookupre)."))$back"; | |||
556 | # Maybe I shouldn't do this, but I want to make matching | |||
557 | # easy, so I'm replacing dash and underscores with [-_]* | |||
558 | # in case people are lazy with their pattern | |||
559 | $lookupre =~ s|[-_]|[-_]*|g; | |||
560 | $rownums = [grep { my $tmp = lc $rows[$_]{lc $lookupcol}; | |||
561 | $tmp =~ s/[-_]+//g; | |||
562 | $tmp =~ /$lookupre/i } | |||
563 | @$rownums]; | |||
564 | } | |||
565 | return if ! $rownums; | |||
566 | @rows = @rows[@$rownums]; | |||
567 | } | |||
568 | return (wantarray | |||
569 | ? @rows | |||
570 | : (! $single | |||
571 | ? \@rows | |||
572 | : (@rows <= 1 | |||
573 | ? $rows[0] | |||
574 | : undef | |||
575 | ) | |||
576 | ) | |||
577 | ); | |||
578 | } | |||
579 | } | |||
580 | 1 | 2.0e-6 | 2.0e-6 | *tblrow = \&data; |
581 | 1 | 1.0e-6 | 1.0e-6 | *tblrows = \&data; |
582 | ||||
583 | sub _unpack { | |||
584 | return $_[1] if $_[2] || ! $_[0]->{packed}; # Keep set: Leave as is | |||
585 | my $meta = shift; | |||
586 | my $data = shift; | |||
587 | my $keep = shift; # Already used above | |||
588 | my $newdata; | |||
589 | if(ref($data) =~ /hash/i) { | |||
590 | # Multi-column hash ref | |||
591 | $newdata->{$_} | |||
592 | = [ unpack(col_pack_templates($meta,$_)."*",$data->{$_})] | |||
593 | for keys %$data; | |||
594 | } else { | |||
595 | # Single-column array ref | |||
596 | my $colnm = lc shift; | |||
597 | $newdata = [ unpack(col_pack_templates($meta,$colnm)."*",$data) ]; | |||
598 | } | |||
599 | return $newdata; | |||
600 | } | |||
601 | ||||
602 | sub last_row_nums { | |||
603 | return $_[0]->{_last_row_nums}; | |||
604 | } | |||
605 | ||||
606 | sub keys { | |||
607 | my $this = shift; | |||
608 | my $opts = _is_opt(@_&&$_[-1]) ? pop(@_) : {}; | |||
609 | my $key = shift; | |||
610 | my $kv = ! $opts->{array}; | |||
611 | if(defined $key) { | |||
612 | if(ref $key) { | |||
613 | my @vals = map { $this->{keyhash}{lc $_} } @$key; | |||
614 | return wantarray ? @vals : \@vals; | |||
615 | } else { | |||
616 | return $this->{keyhash}{lc $key}; | |||
617 | } | |||
618 | } else { | |||
619 | if(! $kv) { | |||
620 | return wantarray ? @{$this->{keys}} : $this->{keys}; | |||
621 | } else { | |||
622 | return wantarray ? %{$this->{keyhash}} : $this->{keyhash}; | |||
623 | } | |||
624 | } | |||
625 | } | |||
626 | 1 | 1.0e-6 | 1.0e-6 | *key = \&keys; |
627 | ||||
628 | sub title { | |||
629 | my $this = shift; | |||
630 | my $r = $this->keys({kv=>1}); | |||
631 | return $r->{title}; | |||
632 | } | |||
633 | ||||
634 | # spent 61.9ms (36µs+61.8) within WISE::IPACTbl::data_out which was called
# once (36µs+61.8ms) by WISE::IPACTbl::data at line 447 | |||
635 | 1 | 1.0e-6 | 1.0e-6 | my $meta = shift; |
636 | 1 | 1.1e-5 | 1.1e-5 | my $opts = _is_opt(@_&&$_[-1]) && # Could still be data hash ... # spent 16µs making 1 call to WISE::IPACTbl::_is_opt |
637 | (@_>1 || ref($_[-1]{data})=~/hash/i) ? pop(@_) : {}; | |||
638 | 1 | 1.0e-6 | 1.0e-6 | my $data = shift || $opts->{data} || $opts->{rows}; |
639 | 1 | 4.0e-6 | 4.0e-6 | my $err = "*** $0/WISE::IPACTbl::data(out)"; |
640 | 1 | 9.0e-6 | 9.0e-6 | $data = _rotate_data($meta,$data); # spent 18µs making 1 call to WISE::IPACTbl::_rotate_data |
641 | #if($data) { | |||
642 | 1 | 1.3e-5 | 1.3e-5 | WISE::IOUtils::make_ipac_tbl($meta->{obj_fh},$meta,undef,$data, # spent 61.8ms making 1 call to WISE::IOUtils::make_ipac_tbl |
643 | {nohdr=>1, | |||
644 | fast=>$meta->{fast}, | |||
645 | %$opts}) | |||
646 | or die "$err: Unable to write to table '$meta->{file}'.\n"; | |||
647 | #} | |||
648 | # Return true even if $data is undef (a header will have been written) | |||
649 | 1 | 5.0e-6 | 5.0e-6 | return $data || 1; |
650 | } | |||
651 | 1 | 1.0e-6 | 1.0e-6 | *write_tblrows = \&data_out; |
652 | 1 | 1.0e-6 | 1.0e-6 | *tblrows_out = \&data_out; |
653 | ||||
654 | sub addcol { | |||
655 | my $this = shift; | |||
656 | my $opts = _is_opt(@_&&$_[-1]) && # Could still be col. def. hash ... | |||
657 | (@_>1 || ! defined $_[-1]{name}) ? pop(@_) : {}; | |||
658 | my $def = shift || $opts->{def}; | |||
659 | my $meta = $opts->{meta} || (ref($this) ? $this : undef); | |||
660 | my $err = "*** $0/WISE::IPACTbl::addcol"; | |||
661 | die "$err: Can't call addcol as a class method unless meta is defined.\n" | |||
662 | if ! ref $this && ! $meta; | |||
663 | die "$err: No meta defined.\n" | |||
664 | if ! $meta; | |||
665 | die "$err: Column definition must be a reference.\n" | |||
666 | if ! ref $def; | |||
667 | if(ref($def) !~ /array/i) { | |||
668 | $def = [$def]; | |||
669 | } | |||
670 | my @defs; | |||
671 | for my $d (@$def) { | |||
672 | # Convert to flat array form expected by underlying utility | |||
673 | push @defs, (ref($d) =~ /array/i | |||
674 | ? $d | |||
675 | : [ | |||
676 | $d->{name}, | |||
677 | $d->{type}, | |||
678 | $d->{fmt}, | |||
679 | $d->{after}, | |||
680 | $d->{blank}, | |||
681 | $d->{unit}, | |||
682 | ] | |||
683 | ); | |||
684 | } | |||
685 | WISE::IOUtils::add_ipac_cols($meta, \@defs) | |||
686 | or die "$err: Unable to add column(s).\n"; | |||
687 | return $meta; | |||
688 | } | |||
689 | 1 | 1.0e-6 | 1.0e-6 | *addcols = \&addcol; |
690 | ||||
691 | sub rmcol { | |||
692 | my $this = shift; | |||
693 | my $opts = _is_opt(@_&&$_[-1]) && # Could still be col. def. hash ... | |||
694 | (@_>1 || ref($_[-1]{data})=~/hash/i) ? pop(@_) : {}; | |||
695 | my $cols = shift || $opts->{cols}; | |||
696 | my $meta = $opts->{meta} || (ref($this) ? $this : undef); | |||
697 | my $err = "*** $0/KEEPCOL"; | |||
698 | die "$err: Can't call rmcol as a class method unless meta is defined.\n" | |||
699 | if ! ref $this && ! $meta; | |||
700 | die "$err: No meta defined.\n" | |||
701 | if ! $meta; | |||
702 | my @cols = ref $cols ? @$cols : ($cols); | |||
703 | WISE::IOUtils::del_ipac_cols($meta, @cols) | |||
704 | or die "$err: Unable to remove column(s).\n"; | |||
705 | return $meta; | |||
706 | } | |||
707 | 1 | 1.0e-6 | 1.0e-6 | *rmcols = \&rmcol; |
708 | ||||
709 | sub keepcol { | |||
710 | my $this = shift; | |||
711 | my $opts = _is_opt(@_&&$_[-1]) && # Could still be col. def. hash ... | |||
712 | (@_>1 || ref($_[-1]{data})=~/hash/i) ? pop(@_) : {}; | |||
713 | my $cols = shift || $opts->{cols}; | |||
714 | my $meta = $opts->{meta} || (ref($this) ? $this : undef); | |||
715 | my $err = "*** $0/KEEPCOL"; | |||
716 | die "$err: Can't call keepcol as a class method unless meta is defined.\n" | |||
717 | if ! ref $this && ! $meta; | |||
718 | die "$err: No meta defined.\n" | |||
719 | if ! $meta; | |||
720 | my %keepcols = map { lc($_)=>1 } (ref $cols ? @$cols : ($cols)); | |||
721 | my @rmcols = grep { ! $keepcols{lc $_} } @{$meta->{names}}; | |||
722 | $meta = meta_ipac($meta); # Get just tbl header stuff | |||
723 | WISE::IOUtils::del_ipac_cols($meta, @rmcols) | |||
724 | or die "$err: Unable to remove column(s).\n"; | |||
725 | return $meta; | |||
726 | } | |||
727 | 1 | 1.0e-6 | 1.0e-6 | *keepcols = \&keepcol; |
728 | ||||
729 | sub mvcol { | |||
730 | my $this = shift; | |||
731 | my $opts = _is_opt(@_&&$_[-1]) && # Could still be col. def. hash ... | |||
732 | (@_>1 || ref($_[-1]{data})=~/hash/i) ? pop(@_) : {}; | |||
733 | my $cols = shift || $opts->{cols}; | |||
734 | my $meta = $opts->{meta} || (ref($this) ? $this : undef); | |||
735 | my $err = "*** $0/WISE::IPACTbl::mvcol"; | |||
736 | die "$err/MVCOL: Column list not a reference.\n" | |||
737 | if ! ref $cols; | |||
738 | my @cols = ref($cols) =~ /hash/i ? %$cols : @$cols; | |||
739 | return 1 if ! @cols; | |||
740 | die "$err/MVCOL: Column list not paired.\n" | |||
741 | if (@cols%2) != 0; | |||
742 | if(! $meta->{ix}) { | |||
743 | $meta->{ix} = map { (lc($meta->{names})=>$_) } 0..$#{$meta->{names}}; | |||
744 | } | |||
745 | while(@cols) { | |||
746 | my ($old,$new) = (shift(@cols), shift(@cols)); | |||
747 | my $ix = $meta->{ix}{lc $old}; | |||
748 | die "$err/MVCOL: Can't find column '$old'.\n" | |||
749 | if ! defined $ix; | |||
750 | $meta->{names}[$ix] = $new; | |||
751 | delete $meta->{ix}{lc $old}; | |||
752 | $meta->{ix}{lc $new} = $ix; | |||
753 | } | |||
754 | return $meta; | |||
755 | } | |||
756 | 1 | 1.1e-5 | 1.1e-5 | *mvcols = \&mvcol; |
757 | ||||
758 | sub sort_tbl { | |||
759 | my $this = shift; | |||
760 | my $opts = _is_opt(@_&&$_[-1]) && # Could still be col. def. hash ... | |||
761 | (@_>1 || ref($_[-1]{data})=~/hash/i) ? pop(@_) : {}; | |||
762 | my $cols = shift || $opts->{cols}; | |||
763 | my $data = $opts->{data} || $this->{rows}; | |||
764 | my $err = "*** $0/WISE::IPACTbl::sort_tbl"; | |||
765 | my $types = $this->types({kv=>1}); | |||
766 | WISE::IOUtils::sort_cols($data,$cols,$types,$opts) | |||
767 | or die "$err: Sort failed on '".$this->{file_name}."'.\n"; | |||
768 | return $this; | |||
769 | } | |||
770 | ||||
771 | sub dump_tbl { | |||
772 | my $this = shift; | |||
773 | my $opts = _is_opt(@_&&$_[-1]) && # Could still be col. def. hash ... | |||
774 | (@_>1 || ref($_[-1]{data})=~/hash/i) ? pop(@_) : {}; | |||
775 | my $cols = shift || $opts->{cols}; | |||
776 | my $data = $opts->{data} || $this->{rows}; | |||
777 | my $err = "*** $0/WISE::IPACTbl::dump_tbl"; | |||
778 | my $out = WISE::IPACTbl->new("-","w", | |||
779 | {meta=>$this,cols=>$cols,data=>$data, | |||
780 | %$opts}) | |||
781 | or die "$err: Couldn't dump '".$this->{file_name}."'.\n"; | |||
782 | return $out->data($data); | |||
783 | } | |||
784 | ||||
785 | # spent 32µs within WISE::IPACTbl::_modes which was called
# once (32µs+0) by WISE::IPACTbl::new at line 30 | |||
786 | 1 | 2.4e-5 | 2.4e-5 | return {qw/ |
787 | read_only r read r in r i r < r r r | |||
788 | write_only w write w out w o w > w w w | |||
789 | append a app a ap a >> a a a | |||
790 | / | |||
791 | }->{lc $_[0]}; | |||
792 | } | |||
793 | ||||
794 | # We want a hash, but not a hash that's a meta definition | |||
795 | sub _is_opt { | |||
796 | 2 | 2.8e-5 | 1.4e-5 | return @_ && $_[0] && ref($_[0])=~/hash/i && |
797 | ! (ref($_[0]->{names})=~/array/i && | |||
798 | ref($_[0]->{types})=~/array/i); | |||
799 | } | |||
800 | ||||
801 | sub _rotate_data { | |||
802 | 2 | 2.0e-6 | 1.0e-6 | my $meta = shift; |
803 | 2 | 2.0e-6 | 1.0e-6 | my $data = shift; |
804 | 2 | 5.0e-6 | 2.5e-6 | my $err = "*** $0/WISE::IPACTbl::rotdata"; |
805 | 2 | 5.0e-6 | 2.5e-6 | my $warn = "=== $0/WISE::IPACTbl::rotdata"; |
806 | 2 | 3.0e-6 | 1.5e-6 | my $newdata = {}; |
807 | 2 | 2.0e-6 | 1.0e-6 | if(! ref($data) ) { |
808 | warn "$warn: Bad row data provided for output; Rows=". | |||
809 | (! defined $data ? "undef" : | |||
810 | (ref($data) ? "$data ref" : "non-ref")).".\n"; | |||
811 | return; | |||
812 | } | |||
813 | 2 | 8.0e-6 | 4.0e-6 | return $data if ref($data) =~ /hash/i; |
814 | for my $row (@$data) { | |||
815 | if(ref($row) =~ /array/i) { # Arrays | |||
816 | push @{$newdata->{lc $meta->{names}[$_]}}, $row->[$_] | |||
817 | for 0..$#$row; | |||
818 | } else { # hash | |||
819 | my @cols = map {lc $_} @{ $meta->{names} }; | |||
820 | push @{$newdata->{lc $_}}, $row->{$_} for @cols; | |||
821 | } | |||
822 | } | |||
823 | return $newdata; | |||
824 | } | |||
825 | ||||
826 | sub _init_as_null { | |||
827 | my $obj = shift; | |||
828 | my $opts = shift; | |||
829 | my $meta = $opts->{meta} || {}; | |||
830 | $obj->{names} = [ @{$meta->{names} || []} ]; | |||
831 | $obj->{types} = [ @{$meta->{types} || []} ]; | |||
832 | $obj->{lens} = { @{$meta->{lens} || []} }; | |||
833 | $obj->{start} = [ @{$meta->{start} || []} ]; | |||
834 | $obj->{fmts} = [ @{$meta->{fmts} || []} ]; | |||
835 | $obj->{blanks} = [ @{$meta->{blanks}|| []} ]; | |||
836 | $obj->{units} = [ @{$meta->{units} || []} ]; | |||
837 | $obj->{ix} = { %{$meta->{ix} || {}} }; | |||
838 | $obj->{comments}= []; | |||
839 | $obj->{keys} = []; | |||
840 | $obj->{keyhash} = {}; | |||
841 | $obj->{totrows} = 0; | |||
842 | $obj->{nrows} = 0; | |||
843 | $obj->{cols} = []; | |||
844 | $obj->{rows} = {}; | |||
845 | return $obj; | |||
846 | } | |||
847 | ||||
848 | ||||
849 | package WISE::IPACTbl::Meta; | |||
850 | ||||
851 | # Sub-class for reading meta-data tables | |||
852 | ||||
853 | 3 | 3.9e-5 | 1.3e-5 | use vars qw(@ISA); # spent 32µs making 1 call to vars::import |
854 | ||||
855 | 1 | 1.1e-5 | 1.1e-5 | @ISA = qw(WISE::IPACTbl); |
856 | ||||
857 | 3 | 0.00190 | 0.00063 | use vars qw//; |
858 | ||||
859 | sub new { | |||
860 | my $this = shift; | |||
861 | my $opts = _is_opt(@_&&$_[-1]) ? pop(@_) : {}; | |||
862 | my $file = shift || $opts->{file}; | |||
863 | my $rawmode = shift || $opts->{mode} || 'r'; | |||
864 | my $mode = _modes($rawmode); | |||
865 | ||||
866 | if($mode eq 'r') { | |||
867 | } else { | |||
868 | $opts = {%$opts, meta=>metafile_meta($this,$opts)}; | |||
869 | } | |||
870 | ||||
871 | return $this->SUPER::new($file,$rawmode,$opts); | |||
872 | } | |||
873 | ||||
874 | sub meta_item { | |||
875 | my $this = shift; | |||
876 | my $opts = _is_opt(@_&&$_[-1]) ? pop(@_) : {}; | |||
877 | my $key = shift; | |||
878 | my $band = shift || $opts->{band}; | |||
879 | my $re = $opts->{re}; | |||
880 | my $v = $this->tblrow($opts->{colnames}||$opts->{cols}||'*','*', | |||
881 | {%$opts,single=>0,hashrow=>1, | |||
882 | lookupcol=>'name', | |||
883 | ($re?(lookupre=>$key):(lookup=>$key)), | |||
884 | }); | |||
885 | if($band) { | |||
886 | # Reduce to one band if the band col is non-empty/zero | |||
887 | $v = [ grep { ! $_->{band} || $_->{band} == $band } @$v ]; | |||
888 | } | |||
889 | if(! ($opts->{cols} || $opts->{colnames})) { | |||
890 | # Reduce to just the value column | |||
891 | $v = [ map { $_->{value} } @$v ]; | |||
892 | } | |||
893 | if($opts->{single} // $this->{single}) { | |||
894 | if(@$v <= 1) { | |||
895 | $v = $v->[0]; | |||
896 | } | |||
897 | else { | |||
898 | return; | |||
899 | } | |||
900 | } | |||
901 | return $v; | |||
902 | } | |||
903 | ||||
904 | sub meta_hash { | |||
905 | my $this = shift; | |||
906 | my $opts = _is_opt(@_&&$_[-1]) ? pop(@_) : {}; | |||
907 | my $whatband = $opts->{band}; | |||
908 | my $v = $this->tblrows({%$opts,single=>0,hashrow=>1}); | |||
909 | my %byname; | |||
910 | for my $val (@$v) { | |||
911 | my $band = $val->{band} > 0 ? $val->{band} : 0; | |||
912 | next if defined $whatband && $band != $whatband; | |||
913 | my $name = $val->{name}; | |||
914 | $name =~ s/^.*:// if $opts->{short}; | |||
915 | $val = $val->{value} if $opts->{simple}; | |||
916 | if($opts->{single} && (! $band || $whatband)) { | |||
917 | # Reduce data structure depth when possible | |||
918 | $byname{$name} = $val; | |||
919 | $byname{lc $name} = $val if $name ne lc $name; | |||
920 | } else { | |||
921 | $byname{$name}[$band] = $val; | |||
922 | $byname{lc $name}[$band] = $val if $name ne lc $name; | |||
923 | } | |||
924 | } | |||
925 | return wantarray ? %byname : \%byname; | |||
926 | } | |||
927 | ||||
928 | sub metafile_meta { | |||
929 | my $this = shift; | |||
930 | my $opts = _is_opt(@_&&$_[-1]) ? pop(@_) : {}; | |||
931 | ||||
932 | my $meta = $opts->{meta} || | |||
933 | { | |||
934 | names => [qw/name band hdrname type value comment/], | |||
935 | types => [qw/c i c c c c /], | |||
936 | lens => [ 33, 5, 10, 5, 33, 51 ], | |||
937 | blanks=> [qw/null null null null null null /], | |||
938 | }; | |||
939 | ||||
940 | return $meta; | |||
941 | } | |||
942 | ||||
943 | sub meta_unit { | |||
944 | my $this = shift; | |||
945 | my $opts = _is_opt(@_&&$_[-1]) ? pop(@_) : {}; | |||
946 | my $val = shift; | |||
947 | return _meta_unit($val->{comment}||""); | |||
948 | } | |||
949 | ||||
950 | sub _meta_unit { | |||
951 | my $comment = shift; | |||
952 | my ($unit) = $comment =~ /^\s*\[\s*([^\]]*?)\s*\]/; | |||
953 | return $unit; | |||
954 | } | |||
955 | ||||
956 | sub meta_band_merge { | |||
957 | my $this = shift; # Object instance or class name (not used) | |||
958 | my $opts = _is_opt(@_&&$_[-1]) ? pop(@_) : {}; | |||
959 | my $mrgmeta = shift; | |||
960 | my $metas = shift; | |||
961 | my $err = "*** $0/METABMRG"; | |||
962 | my $metadef; | |||
963 | my @merge; | |||
964 | for my $metafile (@$metas) { | |||
965 | my $meta = WISE::IPACTbl->new($metafile) | |||
966 | or die "$err: Unable to read meta file '$metafile'.\n"; | |||
967 | my $data = $meta->data({hashrow=>1}) | |||
968 | or die "$err: Unable to get data from meta file '$metafile]'.\n"; | |||
969 | # First all non-band dependent parts | |||
970 | if(! $metadef) { | |||
971 | push @merge, $data->[$_] | |||
972 | for grep {! $data->[$_]{band}} 0..$#$data; | |||
973 | $metadef = $meta->meta_ipac(); | |||
974 | } | |||
975 | # Now band-dependent lines | |||
976 | push @merge, $data->[$_] for grep {$data->[$_]{band}} 0..$#$data; | |||
977 | } | |||
978 | # Write merged meta-data | |||
979 | print "Writing new, band-merged meta-data file '$mrgmeta' ...\n" | |||
980 | if $opts->{verbose}; | |||
981 | my $meta = WISE::IPACTbl->new($mrgmeta,'w', | |||
982 | {meta=>$metadef,data=>\@merge}) | |||
983 | or die "$err: Unable to write coadd meta file '$mrgmeta'.\n"; | |||
984 | my $data = $meta->data(\@merge) | |||
985 | or die "$err: Unable to write data for coadd meta file ". | |||
986 | "'$mrgmeta'.\n"; | |||
987 | return $data; | |||
988 | } | |||
989 | ||||
990 | # Turn a selection of meta-rows into columns in a table row, updating | |||
991 | # an optionally-supplied meta-table structure and row. | |||
992 | sub meta_rotate { | |||
993 | my $this = shift; | |||
994 | my $opts = _is_opt(@_&&$_[-1]) ? pop(@_) : {}; | |||
995 | my $names = shift; | |||
996 | my $band = shift || $opts->{band}; | |||
997 | my $fillband = $opts->{fillband} && ! $band; | |||
998 | my $rotmeta = $opts->{meta} || {}; | |||
999 | my $rotrow = $opts->{row} || {}; | |||
1000 | my $rotdata = exists $opts->{data} ? $opts->{data}||1 : undef; | |||
1001 | my $datarow = $opts->{rownum}; | |||
1002 | my $stripap = $opts->{stripap}; | |||
1003 | my $noband = $opts->{noband}; | |||
1004 | my $real = $opts->{real}; | |||
1005 | my $re = $opts->{re}; | |||
1006 | my $keywords = $opts->{keywords}; | |||
1007 | my @keywords = $keywords ? (ref($keywords) ? @$keywords : $keywords) : (); | |||
1008 | my $nadded = 0; | |||
1009 | my $err = "*** $0/METAROT"; | |||
1010 | die "$err: Need name list to match.\n" if ! $names; | |||
1011 | my %noband; | |||
1012 | if(ref $noband) { | |||
1013 | $noband{lc $_} = 1 for @$noband; | |||
1014 | $noband = 0; | |||
1015 | } | |||
1016 | SEARCH: { | |||
1017 | my $vals = $this->meta_item($names,$band, | |||
1018 | {cols=>'*', # Get all col.s, not just value | |||
1019 | re=>$re, | |||
1020 | }); | |||
1021 | last SEARCH if ! $vals || ! @$vals; | |||
1022 | if(@keywords) { | |||
1023 | # Add values based on matching keywords in the header | |||
1024 | my $keys = $this->keys(); | |||
1025 | for my $key (@keywords) { | |||
1026 | my $keyval = $keys->{lc $key}; | |||
1027 | if(defined $keyval) { | |||
1028 | push @$vals,{name=>lc($key), band=>0, type=>'c', value=>$keyval}; | |||
1029 | } | |||
1030 | } | |||
1031 | } | |||
1032 | for my $v (@$vals) { | |||
1033 | next if ! defined $v; | |||
1034 | my $name = $v->{name}; | |||
1035 | $name =~ s/^.*:+// if $stripap; | |||
1036 | $name =~ s/:+/_/g; | |||
1037 | $name = "w$v->{band}$name" | |||
1038 | if $v->{band} && ! $noband && ! $noband{lc $name}; | |||
1039 | if(! defined $rotmeta->{ix}{lc $name}) { | |||
1040 | my $type = ($v->{type} eq 'c' || $v->{type} eq 'r' | |||
1041 | ? $v->{type} | |||
1042 | : $real # type i; translte to 'r' or not? | |||
1043 | ? 'r' | |||
1044 | : 'i'); | |||
1045 | my $unit = _meta_unit($v->{comment}||""); | |||
1046 | my @add = ($name); | |||
1047 | if($v->{band} && $fillband) { | |||
1048 | # Add columns for all bands if they're not there yet | |||
1049 | @add = (grep { ! defined $rotmeta->{ix}{lc $_} } | |||
1050 | map { my $n=$name; $n=~s/^w\d/w$_/; $n; } | |||
1051 | 1..4); | |||
1052 | } | |||
1053 | for my $thisname (@add) { | |||
1054 | $this->addcol({name => $thisname, | |||
1055 | type => $type, | |||
1056 | blank => | |||
1057 | {r=>"null", i=>"null", c=>"null"}->{$type}, | |||
1058 | unit => $unit, | |||
1059 | }, | |||
1060 | { | |||
1061 | meta => $rotmeta, | |||
1062 | }); | |||
1063 | } | |||
1064 | } | |||
1065 | ++$nadded; | |||
1066 | $rotrow->{lc $name} = $v->{value}; | |||
1067 | if($rotdata) { | |||
1068 | $rotdata = {} if $rotdata eq '1'; | |||
1069 | $rotdata->{lc $name} ||= []; | |||
1070 | $datarow //= @{$rotdata->{lc $name}}; | |||
1071 | $rotdata->{lc $name}[$datarow] = $v->{value}; | |||
1072 | } | |||
1073 | } | |||
1074 | } | |||
1075 | return wantarray ? ($rotrow,$rotmeta,$rotdata eq '1' ? undef : $rotdata) | |||
1076 | : $rotrow; | |||
1077 | } | |||
1078 | ||||
1079 | # Copy utility routine names into this package | |||
1080 | 1 | 1.0e-6 | 1.0e-6 | *_modes = \&WISE::IPACTbl::_modes; |
1081 | 1 | 1.0e-6 | 1.0e-6 | *_is_opt = \&WISE::IPACTbl::_is_opt; |
1082 | ||||
1083 | ||||
1084 | 1 | 2.7e-5 | 2.7e-5 | 1; |
1085 |