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

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