source: trunk/Mars/mcore/fits.h@ 17128

Last change on this file since 17128 was 17128, checked in by tbretz, 11 years ago
Added missing includes etc which is necessary to include the files in any order.
File size: 30.4 KB
Line 
1#ifndef MARS_fits
2#define MARS_fits
3
4#include <stdint.h>
5
6#include <map>
7#include <string>
8#include <fstream>
9#include <sstream>
10#include <algorithm>
11#include <stdexcept>
12
13#ifdef __CINT__
14#define off_t size_t
15#endif
16
17#if !defined(__MARS__) && !defined(__CINT__)
18#include <unordered_map>
19#endif
20
21#ifndef __MARS__
22#include <vector>
23#include <iomanip>
24#include <iostream>
25#define gLog cerr
26#define ___err___ ""
27#define ___warn___ ""
28#define ___all___ ""
29#else
30#include "MLog.h"
31#include "MLogManip.h"
32#define ___err___ err
33#define ___warn___ warn
34#define ___all___ all
35#endif
36
37#if defined(HAVE_ZLIB) || defined(__CINT__)
38#include "izstream.h"
39#else
40#include <fstream>
41#define izstream ifstream
42#warning Support for zipped FITS files disabled.
43#endif
44
45#include "checksum.h"
46
47#ifndef __MARS__
48namespace std
49{
50#else
51using namespace std;
52#endif
53
54class fits : public izstream
55{
56public:
57 //I know I know, you're going to yiell that this does not belong here.
58 //It will belong in the global scope eventually, and it makes the coding of zfits much simpler this way.
59 enum Compression_t
60 {
61 kCompUnknown,
62 kCompFACT
63 };
64
65 struct Entry
66 {
67 char type;
68 string value;
69 string comment;
70 string fitsString;
71
72 template<typename T>
73 T Get() const
74 {
75 T t;
76
77 istringstream str(value);
78 str >> t;
79
80 return t;
81 }
82 };
83
84 struct Table
85 {
86 off_t offset;
87
88 bool is_compressed;
89
90 string name;
91 size_t bytes_per_row;
92 size_t num_rows;
93 size_t num_cols;
94 size_t total_bytes; // NAXIS1*NAXIS2
95
96 struct Column
97 {
98 size_t offset;
99 size_t num;
100 size_t size;
101 size_t bytes; // num*size
102 char type;
103 string unit;
104 Compression_t comp;
105 };
106
107 typedef map<string, Entry> Keys;
108 typedef map<string, Column> Columns;
109 typedef vector<Column> SortedColumns;
110
111 Columns cols;
112 SortedColumns sorted_cols;
113 Keys keys;
114
115 int64_t datasum;
116
117 string Trim(const string &str, char c=' ') const
118 {
119 // Trim Both leading and trailing spaces
120 const size_t pstart = str.find_first_not_of(c); // Find the first character position after excluding leading blank spaces
121 const size_t pend = str.find_last_not_of(c); // Find the first character position from reverse af
122
123 // if all spaces or empty return an empty string
124 if (string::npos==pstart || string::npos==pend)
125 return string();
126
127 return str.substr(pstart, pend-pstart+1);
128 }
129
130 bool Check(const string &key, char type, const string &value="") const
131 {
132 const Keys::const_iterator it = keys.find(key);
133 if (it==keys.end())
134 {
135 ostringstream str;
136 str << "Key '" << key << "' not found.";
137#ifdef __EXCEPTIONS
138 throw runtime_error(str.str());
139#else
140 gLog << ___err___ << "ERROR - " << str.str() << endl;
141 return false;
142#endif
143 }
144
145 if (it->second.type!=type)
146 {
147 ostringstream str;
148 str << "Wrong type for key '" << key << "': expected " << type << ", found " << it->second.type << ".";
149#ifdef __EXCEPTIONS
150 throw runtime_error(str.str());
151#else
152 gLog << ___err___ << "ERROR - " << str.str() << endl;
153 return false;
154#endif
155 }
156
157 if (!value.empty() && it->second.value!=value)
158 {
159 ostringstream str;
160 str << "Wrong value for key '" << key << "': expected " << value << ", found " << it->second.value << ".";
161#ifdef __EXCEPTIONS
162 throw runtime_error(str.str());
163#else
164 gLog << ___err___ << "ERROR - " << str.str() << endl;
165 return false;
166#endif
167 }
168
169 return true;
170 }
171
172 Keys ParseBlock(const vector<string> &vec) const
173 {
174 map<string,Entry> rc;
175
176 for (unsigned int i=0; i<vec.size(); i++)
177 {
178 const string key = Trim(vec[i].substr(0,8));
179 // Keywords without a value, like COMMENT / HISTORY
180 if (vec[i].substr(8,2)!="= ")
181 continue;
182
183 char type = 0;
184
185 string com;
186 string val = Trim(vec[i].substr(10));
187
188 if (val[0]=='\'')
189 {
190 // First skip all '' in the string
191 size_t p = 1;
192 while (1)
193 {
194 const size_t pp = val.find_first_of('\'', p);
195 if (pp==string::npos)
196 break;
197
198 p = val[pp+1]=='\'' ? pp+2 : pp+1;
199 }
200
201 // Now find the comment
202 const size_t ppp = val.find_first_of('/', p);
203
204 // Set value, comment and type
205 // comments could be just spaces. take care of this.
206 if (ppp!=string::npos && val.size() != ppp+1)
207 com = Trim(val.substr(ppp+1));
208
209 val = Trim(val.substr(1, p-2));
210 type = 'T';
211 }
212 else
213 {
214 const size_t p = val.find_first_of('/');
215
216 if (val.size() != p+1)
217 com = Trim(val.substr(p+2));
218
219 val = Trim(val.substr(0, p));
220
221 if (val.empty() || val.find_first_of('T')!=string::npos || val.find_first_of('F')!=string::npos)
222 type = 'B';
223 else
224 type = val.find_last_of('.')==string::npos ? 'I' : 'F';
225 }
226
227 const Entry e = { type, val, com, vec[i] };
228
229 rc[key] = e;
230 }
231
232 return rc;
233 }
234
235 Table() : offset(0) { }
236 Table(const vector<string> &vec, off_t off) : offset(off),
237 keys(ParseBlock(vec))
238 {
239 is_compressed = HasKey("ZTABLE") && Check("ZTABLE", 'B', "T");
240
241 if (!Check("XTENSION", 'T', "BINTABLE") ||
242 !Check("NAXIS", 'I', "2") ||
243 !Check("BITPIX", 'I', "8") ||
244 !Check("GCOUNT", 'I', "1") ||
245 !Check("EXTNAME", 'T') ||
246 !Check("NAXIS1", 'I') ||
247 !Check("NAXIS2", 'I') ||
248 !Check("TFIELDS", 'I'))
249 return;
250
251 if (is_compressed)
252 {
253 if (!Check("ZNAXIS1", 'I') ||
254 !Check("ZNAXIS2", 'I') ||
255 !Check("ZPCOUNT", 'I', "0"))
256 return;
257 }
258 else
259 {
260 if (!Check("PCOUNT", 'I', "0"))
261 return;
262 }
263
264 total_bytes = Get<size_t>("NAXIS1")*Get<size_t>("NAXIS2");
265 bytes_per_row = is_compressed ? Get<size_t>("ZNAXIS1") : Get<size_t>("NAXIS1");
266 num_rows = is_compressed ? Get<size_t>("ZNAXIS2") : Get<size_t>("NAXIS2");
267 num_cols = Get<size_t>("TFIELDS");
268 datasum = is_compressed ? Get<int64_t>("ZDATASUM", -1) : Get<int64_t>("DATASUM", -1);
269
270 size_t bytes = 0;
271
272 const string tFormName = is_compressed ? "ZFORM" : "TFORM";
273 for (long long unsigned int i=1; i<=num_cols; i++)
274 {
275 const string num(to_string(i));
276
277 if (!Check("TTYPE"+num, 'T') ||
278 !Check(tFormName+num, 'T'))
279 return;
280
281 const string id = Get<string>("TTYPE"+num);
282 const string fmt = Get<string>(tFormName+num);
283 const string unit = Get<string>("TUNIT"+num, "");
284 const string comp = Get<string>("ZCTYP"+num, "");
285
286 Compression_t compress = kCompUnknown;
287 if (comp == "FACT")
288 compress = kCompFACT;
289
290 istringstream sin(fmt);
291 int n = 0;
292 sin >> n;
293 if (!sin)
294 n = 1;
295
296 const char type = fmt[fmt.length()-1];
297
298 size_t size = 0;
299 switch (type)
300 {
301 // We could use negative values to mark floats
302 // otheriwse we could just cast them to int64_t?
303 case 'L': // logical
304 case 'A': // char
305 case 'B': size = 1; break; // byte
306 case 'I': size = 2; break; // short
307 case 'J': size = 4; break; // int
308 case 'K': size = 8; break; // long long
309 case 'E': size = 4; break; // float
310 case 'D': size = 8; break; // double
311 // case 'X': size = n; break; // bits (n=number of bytes needed to contain all bits)
312 // case 'C': size = 8; break; // complex float
313 // case 'M': size = 16; break; // complex double
314 // case 'P': size = 8; break; // array descriptor (32bit)
315 // case 'Q': size = 16; break; // array descriptor (64bit)
316 default:
317 {
318 ostringstream str;
319 str << "FITS format TFORM='" << fmt << "' not yet supported.";
320#ifdef __EXCEPTIONS
321 throw runtime_error(str.str());
322#else
323 gLog << ___err___ << "ERROR - " << str.str() << endl;
324 return;
325#endif
326 }
327 }
328
329 const Table::Column col = { bytes, n, size, n*size, type, unit, compress};
330
331 cols[id] = col;
332 sorted_cols.push_back(col);
333 bytes += n*size;
334 }
335
336 if (bytes!=bytes_per_row)
337 {
338#ifdef __EXCEPTIONS
339 throw runtime_error("Column size mismatch");
340#else
341 gLog << ___err___ << "ERROR - Column size mismatch" << endl;
342 return;
343#endif
344 }
345
346 name = Get<string>("EXTNAME");
347 }
348
349 void PrintKeys(bool display_all=false) const
350 {
351 for (Keys::const_iterator it=keys.begin(); it!=keys.end(); it++)
352 {
353 if (!display_all &&
354 (it->first.substr(0, 6)=="TTYPE" ||
355 it->first.substr(0, 6)=="TFORM" ||
356 it->first.substr(0, 6)=="TUNIT" ||
357 it->first=="TFIELDS" ||
358 it->first=="XTENSION" ||
359 it->first=="NAXIS" ||
360 it->first=="BITPIX" ||
361 it->first=="PCOUNT" ||
362 it->first=="GCOUNT")
363 )
364 continue;
365
366 gLog << ___all___ << setw(2) << it->second.type << '|' << it->first << '=' << it->second.value << '/' << it->second.comment << '|' << endl;
367 }}
368
369 void PrintColumns() const
370 {
371 typedef map<pair<size_t, string>, Column> Sorted;
372
373 Sorted sorted;
374
375 for (Columns::const_iterator it=cols.begin(); it!=cols.end(); it++)
376 sorted[make_pair(it->second.offset, it->first)] = it->second;
377
378 for (Sorted::const_iterator it=sorted.begin(); it!=sorted.end(); it++)
379 {
380 gLog << ___all___ << setw(6) << it->second.offset << "| ";
381 gLog << it->second.num << 'x';
382 switch (it->second.type)
383 {
384 case 'A': gLog << "char(8)"; break;
385 case 'L': gLog << "bool(8)"; break;
386 case 'B': gLog << "byte(8)"; break;
387 case 'I': gLog << "short(16)"; break;
388 case 'J': gLog << "int(32)"; break;
389 case 'K': gLog << "int(64)"; break;
390 case 'E': gLog << "float(32)"; break;
391 case 'D': gLog << "double(64)"; break;
392 }
393 gLog << ": " << it->first.second << " [" << it->second.unit << "]" << endl;
394 }
395 }
396
397 operator bool() const { return !name.empty(); }
398
399 bool HasKey(const string &key) const
400 {
401 return keys.find(key)!=keys.end();
402 }
403
404 bool HasColumn(const string& col) const
405 {
406 return cols.find(col)!=cols.end();
407 }
408
409 const Columns &GetColumns() const
410 {
411 return cols;
412 }
413
414 const Keys &GetKeys() const
415 {
416 return keys;
417 }
418
419 // Values of keys are always signed
420 template<typename T>
421 T Get(const string &key) const
422 {
423 const map<string,Entry>::const_iterator it = keys.find(key);
424 if (it==keys.end())
425 {
426 ostringstream str;
427 str << "Key '" << key << "' not found." << endl;
428#ifdef __EXCEPTIONS
429 throw runtime_error(str.str());
430#else
431 gLog << ___err___ << "ERROR - " << str.str() << endl;
432 return T();
433#endif
434 }
435 return it->second.Get<T>();
436 }
437
438 // Values of keys are always signed
439 template<typename T>
440 T Get(const string &key, const T &deflt) const
441 {
442 const map<string,Entry>::const_iterator it = keys.find(key);
443 return it==keys.end() ? deflt :it->second.Get<T>();
444 }
445
446 size_t GetN(const string &key) const
447 {
448 const Columns::const_iterator it = cols.find(key);
449 return it==cols.end() ? 0 : it->second.num;
450 }
451
452
453
454 // There may be a gap between the main table and the start of the heap:
455 // this computes the offset
456 streamoff GetHeapShift() const
457 {
458 if (!HasKey("THEAP"))
459 return 0;
460
461 const size_t shift = Get<size_t>("THEAP");
462 return shift <= total_bytes ? 0 : shift - total_bytes;
463 }
464
465 // return total number of bytes 'all inclusive'
466 streamoff GetTotalBytes() const
467 {
468 //get offset of special data area from start of main table
469 const streamoff shift = GetHeapShift();
470
471 //and special data area size
472 const streamoff size = HasKey("PCOUNT") ? Get<streamoff>("PCOUNT") : 0;
473
474 // Get the total size
475 const streamoff total = total_bytes + size + shift;
476
477 // check for padding
478 if (total%2880==0)
479 return total;
480
481 // padding necessary
482 return total + (2880 - (total%2880));
483 }
484 };
485
486protected:
487 ofstream fCopy;
488
489 Table fTable;
490
491 typedef pair<void*, Table::Column> Address;
492 typedef vector<Address> Addresses;
493 //map<void*, Table::Column> fAddresses;
494 Addresses fAddresses;
495
496#if defined(__MARS__) || defined(__CINT__)
497 typedef map<string, void*> Pointers;
498#else
499 typedef unordered_map<string, void*> Pointers;
500#endif
501 Pointers fPointers;
502
503 vector<vector<char>> fGarbage;
504
505 vector<char> fBufferRow;
506 vector<char> fBufferDat;
507
508 size_t fRow;
509
510 Checksum fChkHeader;
511 Checksum fChkData;
512
513 bool ReadBlock(vector<string> &vec)
514 {
515 int endtag = 0;
516 for (int i=0; i<36; i++)
517 {
518 char c[81];
519 c[80] = 0;
520 read(c, 80);
521 if (!good())
522 break;
523
524 fChkHeader.add(c, 80);
525
526// if (c[0]==0)
527// return vector<string>();
528
529 string str(c);
530
531// if (!str.empty())
532// cout << setw(2) << i << "|" << str << "|" << (endtag?'-':'+') << endl;
533
534 if (endtag==2 || str=="END ")
535 {
536 endtag = 2; // valid END tag found
537 continue;
538 }
539
540 if (endtag==1 || str==" ")
541 {
542 endtag = 1; // end tag not found, but expected to be there
543 continue;
544 }
545
546 vec.push_back(str);
547 }
548
549 // Make sure that no empty vector is returned
550 if (endtag && vec.size()%36==0)
551 vec.emplace_back("END = '' / ");
552
553 return endtag==2;
554 }
555
556 string Compile(const string &key, int16_t i=-1) const
557 {
558 if (i<0)
559 return key;
560
561 ostringstream str;
562 str << key << i;
563 return str.str();
564 }
565
566 void Constructor(const string &fname, string fout, const string& tableName, bool force)
567 {
568 char simple[10];
569 read(simple, 10);
570 if (!good())
571 return;
572
573 if (memcmp(simple, "SIMPLE = ", 10))
574 {
575 clear(rdstate()|ios::badbit);
576#ifdef __EXCEPTIONS
577 throw runtime_error("File is not a FITS file.");
578#else
579 gLog << ___err___ << "ERROR - File is not a FITS file." << endl;
580 return;
581#endif
582 }
583
584 seekg(0);
585
586 while (good())
587 {
588 vector<string> block;
589 while (1)
590 {
591 // If we search for a table, we implicitly assume that
592 // not finding the table is not an error. The user
593 // can easily check that by eof() && !bad()
594 peek();
595 if (eof() && !bad() && !tableName.empty())
596 {
597 break;
598 }
599 // FIXME: Set limit on memory consumption
600 const int rc = ReadBlock(block);
601 if (!good())
602 {
603 clear(rdstate()|ios::badbit);
604#ifdef __EXCEPTIONS
605 throw runtime_error("FITS file corrupted.");
606#else
607 gLog << ___err___ << "ERROR - FITS file corrupted." << endl;
608 return;
609#endif
610 }
611
612 if (block.size()%36)
613 {
614 if (!rc && !force)
615 {
616 clear(rdstate()|ios::badbit);
617#ifdef __EXCEPTIONS
618 throw runtime_error("END keyword missing in FITS header.");
619#else
620 gLog << ___err___ << "ERROR - END keyword missing in FITS file... file might be corrupted." << endl;
621 return;
622#endif
623 }
624 break;
625 }
626 }
627
628 if (block.empty())
629 break;
630
631 if (block[0].substr(0, 9)=="SIMPLE =")
632 {
633 fChkHeader.reset();
634 continue;
635 }
636
637 if (block[0].substr(0, 9)=="XTENSION=")
638 {
639 fTable = Table(block, tellg());
640 fRow = (size_t)-1;
641
642 if (!fTable)
643 {
644 clear(rdstate()|ios::badbit);
645 return;
646 }
647
648 // Check for table name. Skip until eof or requested table are found.
649 // skip the current table?
650 if ((!tableName.empty() && tableName!=fTable.Get<string>("EXTNAME")) ||
651 ( tableName.empty() && "ZDrsCellOffsets"==fTable.Get<string>("EXTNAME")))
652 {
653 const streamoff skip = fTable.GetTotalBytes();
654 seekg(skip, ios_base::cur);
655
656 fChkHeader.reset();
657
658 continue;
659 }
660
661 fBufferRow.resize(fTable.bytes_per_row + 8-fTable.bytes_per_row%4);
662 fBufferDat.resize(fTable.bytes_per_row);
663
664 break;
665 }
666 }
667
668 if (fout.empty())
669 return;
670
671 if (*fout.rbegin()=='/')
672 {
673 const size_t p = fname.find_last_of('/');
674 fout.append(fname.substr(p+1));
675 }
676
677 fCopy.open(fout);
678 if (!fCopy)
679 {
680 clear(rdstate()|ios::badbit);
681#ifdef __EXCEPTIONS
682 throw runtime_error("Could not open output file.");
683#else
684 gLog << ___err___ << "ERROR - Failed to open output file." << endl;
685#endif
686 }
687
688 const streampos p = tellg();
689 seekg(0);
690
691 vector<char> buf(p);
692 read(buf.data(), p);
693
694 fCopy.write(buf.data(), p);
695 if (!fCopy)
696 clear(rdstate()|ios::badbit);
697 }
698
699public:
700 fits(const string &fname, const string& tableName="", bool force=false) : izstream(fname.c_str())
701 {
702 Constructor(fname, "", tableName, force);
703 if ((fTable.is_compressed && !force) ||
704 (fTable.name == "ZDrsCellOffsets" && !force))
705 {
706#ifdef __EXCEPTIONS
707 throw runtime_error("You are trying to read a compressed fits with the base fits class. Please use factfits instead.");
708#else
709 gLog << ___err___ << "ERROR - You are trying to read a compressed fits with the base fits class. Please use factfits instead." << endl;
710#endif
711 clear(rdstate()|ios::badbit);
712 }
713 }
714
715 fits(const string &fname, const string &fout, const string& tableName, bool force=false) : izstream(fname.c_str())
716 {
717 Constructor(fname, fout, tableName, force);
718 if ((fTable.is_compressed && !force) ||
719 (fTable.name == "ZDrsCellOffsets" && !force))
720 {
721#ifdef __EXCEPTIONS
722 throw runtime_error("You are trying to read a compressed fits with the base fits class. Please use factfits instead.");
723#else
724 gLog << ___err___ << "ERROR - You are trying to read a compressed fits with the base fits class. Please use factfits instead." << endl;
725#endif
726 clear(rdstate()|ios::badbit);
727 }
728 }
729
730 fits() : izstream()
731 {
732
733 }
734
735 ~fits()
736 {
737 copy(istreambuf_iterator<char>(*this),
738 istreambuf_iterator<char>(),
739 ostreambuf_iterator<char>(fCopy));
740 }
741
742 virtual void StageRow(size_t row, char* dest)
743 {
744 // if (row!=fRow+1) // Fast seeking is ensured by izstream
745 seekg(fTable.offset+row*fTable.bytes_per_row);
746 read(dest, fTable.bytes_per_row);
747 //fin.clear(fin.rdstate()&~ios::eofbit);
748 }
749
750 virtual void WriteRowToCopyFile(size_t row)
751 {
752 if (row==fRow+1)
753 {
754 const uint8_t offset = (row*fTable.bytes_per_row)%4;
755
756 fChkData.add(fBufferRow);
757 if (fCopy.is_open() && fCopy.good())
758 fCopy.write(fBufferRow.data()+offset, fTable.bytes_per_row);
759 if (!fCopy)
760 clear(rdstate()|ios::badbit);
761 }
762 else
763 if (fCopy.is_open())
764 clear(rdstate()|ios::badbit);
765 }
766
767 void ZeroBufferForChecksum(vector<char>& vec, const uint64_t extraZeros=0)
768 {
769 auto ib = vec.begin();
770 auto ie = vec.end();
771
772 *ib++ = 0;
773 *ib++ = 0;
774 *ib++ = 0;
775 *ib = 0;
776
777 for (uint64_t i=0;i<extraZeros+8;i++)
778 *--ie = 0;
779 }
780
781 uint8_t ReadRow(size_t row)
782 {
783 // For the checksum we need everything to be correctly aligned
784 const uint8_t offset = (row*fTable.bytes_per_row)%4;
785
786 ZeroBufferForChecksum(fBufferRow);
787
788 StageRow(row, fBufferRow.data()+offset);
789
790 WriteRowToCopyFile(row);
791
792 fRow = row;
793
794 return offset;
795 }
796
797 template<size_t N>
798 void revcpy(char *dest, const char *src, const int &num)
799 {
800 const char *pend = src + num*N;
801 for (const char *ptr = src; ptr<pend; ptr+=N, dest+=N)
802 reverse_copy(ptr, ptr+N, dest);
803 }
804
805 virtual void MoveColumnDataToUserSpace(char *dest, const char *src, const Table::Column& c)
806 {
807 // Let the compiler do some optimization by
808 // knowing that we only have 1, 2, 4 and 8
809 switch (c.size)
810 {
811 case 1: memcpy (dest, src, c.bytes); break;
812 case 2: revcpy<2>(dest, src, c.num); break;
813 case 4: revcpy<4>(dest, src, c.num); break;
814 case 8: revcpy<8>(dest, src, c.num); break;
815 }
816 }
817
818#if !defined(__MARS__) && !defined(__CINT__)
819 virtual bool GetRow(size_t row, bool check=true)
820#else
821 virtual bool GetRowNum(size_t row, bool check=true)
822#endif
823 {
824 if (check && row>=fTable.num_rows)
825 return false;
826
827 const uint8_t offset = ReadRow(row);
828 if (!good())
829 return good();
830
831 const char *ptr = fBufferRow.data() + offset;
832
833 for (Addresses::const_iterator it=fAddresses.begin(); it!=fAddresses.end(); it++)
834 {
835 const Table::Column &c = it->second;
836
837 const char *src = ptr + c.offset;
838 char *dest = reinterpret_cast<char*>(it->first);
839
840 MoveColumnDataToUserSpace(dest, src, c);
841 }
842
843 return good();
844 }
845
846 bool GetNextRow(bool check=true)
847 {
848#if !defined(__MARS__) && !defined(__CINT__)
849 return GetRow(fRow+1, check);
850#else
851 return GetRowNum(fRow+1, check);
852#endif
853 }
854
855 virtual bool SkipNextRow()
856 {
857 seekg(fTable.offset+(++fRow)*fTable.bytes_per_row);
858 return good();
859 }
860
861 static bool Compare(const Address &p1, const Address &p2)
862 {
863 return p1.first>p2.first;
864 }
865
866 template<class T, class S>
867 const T &GetAs(const string &name)
868 {
869 return *reinterpret_cast<S*>(fPointers[name]);
870 }
871
872 void *SetPtrAddress(const string &name)
873 {
874 if (fTable.cols.count(name)==0)
875 {
876 ostringstream str;
877 str << "SetPtrAddress('" << name << "') - Column not found." << endl;
878#ifdef __EXCEPTIONS
879 throw runtime_error(str.str());
880#else
881 gLog << ___err___ << "ERROR - " << str.str() << endl;
882 return NULL;
883#endif
884 }
885
886 Pointers::const_iterator it = fPointers.find(name);
887 if (it!=fPointers.end())
888 return it->second;
889
890 fGarbage.emplace_back(fTable.cols[name].bytes);
891
892 void *ptr = fGarbage.back().data();
893
894 fPointers[name] = ptr;
895 fAddresses.emplace_back(ptr, fTable.cols[name]);
896 sort(fAddresses.begin(), fAddresses.end(), Compare);
897 return ptr;
898 }
899
900 template<typename T>
901 bool SetPtrAddress(const string &name, T *ptr, size_t cnt)
902 {
903 if (fTable.cols.count(name)==0)
904 {
905 ostringstream str;
906 str << "SetPtrAddress('" << name << "') - Column not found." << endl;
907#ifdef __EXCEPTIONS
908 throw runtime_error(str.str());
909#else
910 gLog << ___err___ << "ERROR - " << str.str() << endl;
911 return false;
912#endif
913 }
914
915 if (sizeof(T)!=fTable.cols[name].size)
916 {
917 ostringstream str;
918 str << "SetPtrAddress('" << name << "') - Element size mismatch: expected "
919 << fTable.cols[name].size << " from header, got " << sizeof(T) << endl;
920#ifdef __EXCEPTIONS
921 throw runtime_error(str.str());
922#else
923 gLog << ___err___ << "ERROR - " << str.str() << endl;
924 return false;
925#endif
926 }
927
928 if (cnt!=fTable.cols[name].num)
929 {
930 ostringstream str;
931 str << "SetPtrAddress('" << name << "') - Element count mismatch: expected "
932 << fTable.cols[name].num << " from header, got " << cnt << endl;
933#ifdef __EXCEPTIONS
934 throw runtime_error(str.str());
935#else
936 gLog << ___err___ << "ERROR - " << str.str() << endl;
937 return false;
938#endif
939 }
940
941 // if (fAddresses.count(ptr)>0)
942 // gLog << warn << "SetPtrAddress('" << name << "') - Pointer " << ptr << " already assigned." << endl;
943
944 //fAddresses[ptr] = fTable.cols[name];
945 fPointers[name] = ptr;
946 fAddresses.emplace_back(ptr, fTable.cols[name]);
947 sort(fAddresses.begin(), fAddresses.end(), Compare);
948 return true;
949 }
950
951 template<class T>
952 bool SetRefAddress(const string &name, T &ptr)
953 {
954 return SetPtrAddress(name, &ptr, sizeof(ptr)/sizeof(T));
955 }
956
957 template<typename T>
958 bool SetVecAddress(const string &name, vector<T> &vec)
959 {
960 return SetPtrAddress(name, vec.data(), vec.size());
961 }
962
963 template<typename T>
964 T Get(const string &key) const
965 {
966 return fTable.Get<T>(key);
967 }
968
969 template<typename T>
970 T Get(const string &key, const string &deflt) const
971 {
972 return fTable.Get<T>(key, deflt);
973 }
974
975 bool SetPtrAddress(const string &name, void *ptr)
976 {
977 if (fTable.cols.count(name)==0)
978 {
979 ostringstream str;
980 str <<"SetPtrAddress('" << name << "') - Column not found." << endl;
981#ifdef __EXCEPTIONS
982 throw runtime_error(str.str());
983#else
984 gLog << ___err___ << "ERROR - " << str.str() << endl;
985 return false;
986#endif
987 }
988
989 // if (fAddresses.count(ptr)>0)
990 // gLog << warn << "SetPtrAddress('" << name << "') - Pointer " << ptr << " already assigned." << endl;
991
992 //fAddresses[ptr] = fTable.cols[name];
993 fPointers[name] = ptr;
994 fAddresses.emplace_back(ptr, fTable.cols[name]);
995 sort(fAddresses.begin(), fAddresses.end(), Compare);
996 return true;
997 }
998
999 bool HasKey(const string &key) const { return fTable.HasKey(key); }
1000 bool HasColumn(const string& col) const { return fTable.HasColumn(col);}
1001 const Table::Columns &GetColumns() const { return fTable.GetColumns();}
1002 const Table::SortedColumns& GetSortedColumns() const { return fTable.sorted_cols;}
1003 const Table::Keys &GetKeys() const { return fTable.GetKeys();}
1004
1005 int64_t GetInt(const string &key) const { return fTable.Get<int64_t>(key); }
1006 uint64_t GetUInt(const string &key) const { return fTable.Get<uint64_t>(key); }
1007 double GetFloat(const string &key) const { return fTable.Get<double>(key); }
1008 string GetStr(const string &key) const { return fTable.Get<string>(key); }
1009
1010 size_t GetN(const string &key) const
1011 {
1012 return fTable.GetN(key);
1013 }
1014
1015// size_t GetNumRows() const { return fTable.num_rows; }
1016 size_t GetRow() const { return fRow==(size_t)-1 ? 0 : fRow; }
1017
1018 operator bool() const { return fTable && fTable.offset!=0; }
1019
1020 void PrintKeys() const { fTable.PrintKeys(); }
1021 void PrintColumns() const { fTable.PrintColumns(); }
1022
1023 bool IsHeaderOk() const { return fTable.datasum<0?false:(fChkHeader+Checksum(fTable.datasum)).valid(); }
1024 virtual bool IsFileOk() const { return (fChkHeader+fChkData).valid(); }
1025
1026 bool IsCompressedFITS() const { return fTable.is_compressed;}
1027
1028 virtual size_t GetNumRows() const
1029 {
1030 return fTable.Get<size_t>("NAXIS2");
1031 }
1032
1033 virtual size_t GetBytesPerRow() const
1034 {
1035 return fTable.Get<size_t>("NAXIS1");
1036 }
1037};
1038
1039#ifndef __MARS__
1040};
1041#endif
1042#endif
Note: See TracBrowser for help on using the repository browser.