mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
fitsHeaderCard.hpp
Go to the documentation of this file.
1/** \file fitsHeaderCard.hpp
2 * \brief A class to work with a FITS header card
3 * \ingroup fits_processing_files
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 */
7
8//***********************************************************************//
9// Copyright 2015-2025 Jared R. Males (jaredmales@gmail.com)
10//
11// This file is part of mxlib.
12//
13// mxlib is free software: you can redistribute it and/or modify
14// it under the terms of the GNU General Public License as published by
15// the Free Software Foundation, either version 3 of the License, or
16// (at your option) any later version.
17//
18// mxlib is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21// GNU General Public License for more details.
22//
23// You should have received a copy of the GNU General Public License
24// along with mxlib. If not, see <http://www.gnu.org/licenses/>.
25//***********************************************************************//
26
27#ifndef ioutils_fits_fitsHeaderCard_hpp
28#define ioutils_fits_fitsHeaderCard_hpp
29
30#include <format>
31
32#include "../../mxlib.hpp"
33
34#include "../../meta/tagT.hpp"
35#include "fitsUtils.hpp"
36
37namespace mx
38{
39namespace fits
40{
41
42/// \cond
43// strip leading and trailing whitespace and then opening and closing ''. leaves spaces between ''.
44inline void stripApostWS( std::string &str )
45{
46 if( str.size() == 0 )
47 {
48 return;
49 }
50
51 if( str[0] != '\'' && str[0] != ' ' && str.back() != ' ' ) // get out fast if we can
52 {
53 return;
54 }
55
56 // strip white space at front
57 size_t ns = str.find_first_not_of( " \t\r\n" );
58 if( ns != std::string::npos && ns != 0 )
59 {
60 str.erase( 0, ns );
61 }
62 else if( ns == std::string::npos ) // the rare all spaces
63 {
64 str = "";
65 return;
66 }
67
68 // strip white space at back
69 ns = str.find_last_not_of( " \t\r\n" );
70 if( ns != std::string::npos && ns != str.size() - 1 )
71 {
72 str.erase( ns + 1 );
73 }
74
75 if( str[0] == '\'' && str.back() == '\'' )
76 {
77 if( str.size() == 1 || str.size() == 2 )
78 {
79 str = "";
80 return;
81 }
82 str.erase( str.size() - 1, 1 );
83 str.erase( 0, 1 );
84 }
85}
86/// \endcond
87
88/// Class to manage the three components of a FITS header card
89/** Since FITS does not provide the type in keyword=value pairs in a FITS header, it is up to the user
90 * to determine the type. Furthermore, since we want to read values from files, type conversions must
91 * be done at runtime. The result is that we must be able to accept a string, which is converted
92 * to a given type on demand as determined at runtime.
93 *
94 * Conversion from string to native type, or vice versa, only occurs when needed. So if you set the value to,
95 * say, a double, the value is not converted to string format unless specifically requested. If the write function is
96 * called when in this state, the cfitsio routine is called directly. This conversion only on demand is most important
97 * for values read from a file, then written to another file. In this case, no conversion to its double (etc)
98 * representation occurs.
99 *
100 * Note that because of the checks to determine the type and appropriate return values, accessing the value in a card
101 * is possibly slower than accessing a variable due to various if statements and error checking.
102 * This means that you should typically do
103 * so once and use a local variable for repeated use.
104 *
105 * \ingroup fits_processing
106 */
107template <class verboseT = verbose::d>
109{
110
111 protected:
112 /// The keyword
113 std::string m_keyword;
114
115 /// The FITS type of the value, and indicates which member of m_values to access.
117
118 /// The native type is held in a union.
119 union values
120 {
121 bool Bool; ///< the bool value
122 char Char; ///< the char value
123 unsigned char UChar; ///< the unsigned char value
124 short Short; ///< the short value
125 unsigned short UShort; ///< the unsigned short value
126 int Int; ///< the int value
127 unsigned int UInt; ///< the unsigned int value
128 long Long; ///< the long value
129 unsigned long ULong; ///< the unsigned long value
130 long long LongLong; ///< the long long value
131 unsigned long long ULongLong; ///< the unsigned long long value
132 float Float; ///< the float value
133 std::complex<float> complexFloat; ///< the std::complex<float> value
134 double Double; ///< the double value
135 std::complex<double> complexDouble; ///< the std::complex<double> value
136 long double LongDouble; ///< the long double value
137 std::complex<long double> complexLongDouble; ///< the std::complex<long double> value
138
139 // clang-format off
140 #ifdef HAS_QUAD
141 __float128 Quad; ///< the float128 value
142 std::complex<__float128> complexQuad; ///< the std::complex<__float128> value
143 #endif
144 // clang-format on
145
146 /// c'tor. have to specify due to inclusion of std::complex types.
148 {
149 return;
150 }
151
152 bool &member( meta::tagT<bool> )
153 {
154 return Bool;
155 }
156
157 char &member( meta::tagT<char> )
158 {
159 return Char;
160 }
161
162 unsigned char &member( meta::tagT<unsigned char> )
163 {
164 return UChar;
165 }
166
167 short &member( meta::tagT<short> )
168 {
169 return Short;
170 }
171
172 unsigned short &member( meta::tagT<unsigned short> )
173 {
174 return UShort;
175 }
176
177 int &member( meta::tagT<int> )
178 {
179 return Int;
180 }
181
182 unsigned int &member( meta::tagT<unsigned int> )
183 {
184 return UInt;
185 }
186
187 long &member( meta::tagT<long> )
188 {
189 return Long;
190 }
191
192 unsigned long &member( meta::tagT<unsigned long> )
193 {
194 return ULong;
195 }
196
197 long long &member( meta::tagT<long long> )
198 {
199 return LongLong;
200 }
201
202 unsigned long long &member( meta::tagT<unsigned long long> )
203 {
204 return ULongLong;
205 }
206
207 float &member( meta::tagT<float> )
208 {
209 return Float;
210 }
211
212 std::complex<float> &member( meta::tagT<std::complex<float>> )
213 {
214 return complexFloat;
215 }
216
217 double &member( meta::tagT<double> )
218 {
219 return Double;
220 }
221
222 std::complex<double> &member( meta::tagT<std::complex<double>> )
223 {
224 return complexDouble;
225 }
226
227 long double &member( meta::tagT<long double> )
228 {
229 return LongDouble;
230 }
231
232 std::complex<long double> &member( meta::tagT<std::complex<long double>> )
233 {
234 return complexLongDouble;
235 }
236
237 // clang-format off
238 #ifdef HAS_QUAD
239 __float128 &member( meta::tagT<__float128> )
240 {
241 return Quad;
242 }
243
244 std::complex<__float128> &member( meta::tagT<std::complex<__float128>> )
245 {
246 return complexQuad;
247 }
248 #endif
249 // clang-format on
250
251 template <typename typeT>
252 typeT &member()
253 {
254 return member( meta::tagT<typeT>() );
255 }
256
257 } m_value;
258
259 /// The value in string form
260 std::stringstream m_valueStr;
261
262 bool m_valueGood{ false }; ///< Flag indicating if the value is valid
263 bool m_valueStrGood{ false }; ///< Flag indicating if the value string is valid
264
265 /// The comment
266 std::string m_comment;
267
268 public:
269 /// \name Constructors
270 /**
271 */
272 //@{
273
274 /// Basic c'tor
276
277 /// Construct from the three components for a value of string type
278 /**
279 */
280 fitsHeaderCard( const std::string &k, ///< [in] the keyword
281 const std::string &v, ///< [in] the value string
282 const std::string &c = "" ///< [in] the comment
283 );
284
285 /// Construct from the three components for a value of string type
286 /** Have to provide overload for char * to avoid template version
287 */
288 fitsHeaderCard( const std::string &k, ///< [in] the keyword
289 char *v, ///< [in] the value string
290 const std::string &c = "" ///< [in] the comment
291 );
292
293 /// Construct from the three components for a value of string type
294 /** Have to provide overload for const char * to avoid template version
295 */
296 fitsHeaderCard( const std::string &k, ///< [in] the keyword
297 const char *v, ///< [in] the value string
298 const std::string &c = "" ///< [in] the comment
299 );
300
301 /// Construct from the three components, when already in a string format
302 /** Use this when the value is not a string
303 */
304 fitsHeaderCard( const std::string &k, ///< [in] the keyword
305 const std::string &v, ///< [in] the value string
306 const int &type, ///< [in] the type of the value
307 const std::string &c = "" ///< [in] the comment
308 );
309
310 /// Construct from the three components, when it's really a comment card
311 /** This overload is provided to facilitate handling of comments when re-writing the file.
312 *
313 */
314 fitsHeaderCard( const std::string &k, ///< [in] the keyword
315 fitsCommentType v, ///< [in] an object of type fitsCommentType
316 const std::string &c ///< [in] the comment
317 );
318
319 /// Construct from the three components, when it's really a history card
320 /** This overload is provided to facilitate handling of history when re-writing the file.
321 *
322 */
323 fitsHeaderCard( const std::string &k, ///< [in] the keyword
324 fitsHistoryType v, ///< [in] an object of type fitsHistoryType
325 const std::string &c ///< [in] the comment
326 );
327
328 /// Construct from just keyword, when value's type is unknown
329 /**
330 */
331 explicit fitsHeaderCard( const std::string &k /**< [in] the keyword*/ );
332
333 /// Construct from just keyword, when value's type known
334 /**
335 */
336 fitsHeaderCard( const std::string &k, ///< [in] the keyword
337 const int type ///< [in] the type
338 );
339
340 /// Construct from the three components for a char.
341 /**
342 */
343 template <typename typeT>
344 fitsHeaderCard( const std::string &k, ///< [in] they keyword
345 const typeT v, ///< [in] the value
346 const std::string &c = "" ///< [in] the comment
347 );
348
349 /// Copy constructor
350 fitsHeaderCard( const fitsHeaderCard &card );
351
352 //@}
353
354 /// Assignment
356
357 protected:
358 ///\name Converters
359 /** @{
360 */
361
362 /// Convert from the type to a string.
363 /** This populates m_valueStr and sets m_valueStrGood so that this conversion
364 * only occurs once.
365 */
367
368 /// Convert from string to the type
369 /** This populates the appropriate union field and sets m_valueGood so that
370 * this conversion only occurs once.
371 */
372 template <typename typeT>
374
375 /// Get the value from its type converted to a different type.
376 template <typename typeT>
377 error_t convertedValue( typeT &cval /**< [out] the converted value */ );
378
379 /// Convert the value from its type to a different type.
380 error_t convertValue( int newtype /**< [in] the new type */ );
381
382 ///@}
383
384 public:
385 ///\name Accessors
386 /** @{
387 */
388
389 /// Get the keyword
390 /**
391 * \returns a const reference to m_keyword
392 */
393 const std::string &keyword() const;
394
395 /// Set the keyword
396 /**
397 * \returns error_t::noerror on success
398 */
399 error_t keyword( const std::string &kw /**< [in] the new keyword */ );
400
401 /// Get the type
402 /**
403 * \returns the value of m_type
404 */
405 int type() const;
406
407 /// Set the type
408 /** If this is a change in type and the native type is set in m_value (indicated by m_valueGood == true)
409 * then it is converted to the new type. Otherwise, no conversion occurs.
410 *
411 * \returns error_t::noerror on success
412 */
413 error_t type( const int &t /**< [in] the new type */ );
414
415 protected:
416 /** \name tag dispatching for getting value
417 * @{
418 */
419
420 /// Get value for anything not a string
421 template <typename typeT>
423
424 /// Get value tag dispatcher for std::string
425 /**
426 */
428
429 /// Get value tag dispatcher for char
430 /** Calls valueNonString
431 */
432 char value( meta::tagT<char>, mx::error_t &errc );
433
434 /// Get value tag dispatcher for unsigned char
435 /** Calls valueNonString
436 */
437 unsigned char value( meta::tagT<unsigned char>, mx::error_t &errc );
438
439 /// Get value tag dispatcher for short
440 /** Calls valueNonString
441 */
442 short value( meta::tagT<short>, mx::error_t &errc );
443
444 /// Get value tag dispatcher for unsigned short
445 /** Calls valueNonString
446 */
447 unsigned short value( meta::tagT<unsigned short>, mx::error_t &errc );
448
449 /// Get value tag dispatcher for int
450 /** Calls valueNonString
451 */
452 int value( meta::tagT<int>, mx::error_t &errc );
453
454 /// Get value tag dispatcher for unsigned int
455 /** Calls valueNonString
456 */
457 unsigned int value( meta::tagT<unsigned int>, mx::error_t &errc );
458
459 /// Get value tag dispatcher for long
460 /** Calls valueNonString
461 */
462 long value( meta::tagT<long>, mx::error_t &errc );
463
464 /// Get value tag dispatcher for unsigned long
465 /** Calls valueNonString
466 */
467 unsigned long value( meta::tagT<unsigned long>, mx::error_t &errc );
468
469 /// Get value tag dispatcher for long long
470 /** Calls valueNonString
471 */
472 long long value( meta::tagT<long long>, mx::error_t &errc );
473
474 /// Get value tag dispatcher for unsigned long long
475 /** Calls valueNonString
476 */
477 unsigned long long value( meta::tagT<unsigned long long>, mx::error_t &errc );
478
479 /// Get value tag dispatcher for float
480 /** Calls valueNonString
481 */
482 float value( meta::tagT<float>, mx::error_t &errc );
483
484 /// Get value tag dispatcher for double
485 /** Calls valueNonString
486 */
487 double value( meta::tagT<double>, mx::error_t &errc );
488
489 ///@}
490
491 public:
492 /// Get the value
493 /** Returns the value as typeT. Conversions occur
494 * automatically if necessary.
495 *
496 * \returns the value converted to typeT as necessary
497 *
498 * \b Errors
499 * - mx::error_t::noerror on success
500 * - other errors possible due to conversions
501 *
502 */
503 template <typename typeT>
504 typeT value( mx::error_t *errc = nullptr /**< [in] [optional] error code */ );
505
506 /// Get the value as a string
507 /** This calls value<string>().
508 *
509 * \returns the value converted to string as necessary
510 *
511 */
512 std::string String( error_t *errc = nullptr /**< [in] [optional] error code */ );
513
514 /// Get the value as a char
515 /** This calls value<char>().
516 *
517 * \returns the value converted to char as necessary
518 *
519 */
520 char Char( error_t *errc = nullptr /**< [in] [optional] error code */ );
521
522 /// Get the value as an unsigned char
523 /** This calls value<unsigned char>().
524 *
525 * \returns the value converted to unsigned char as necessary
526 *
527 */
528 unsigned char UChar( error_t *errc = nullptr /**< [in] [optional] error code */ );
529
530 /// Get the value as a short
531 /** This calls value<short>().
532 *
533 * \returns the value converted to short as necessary
534 *
535 */
536 short Short( error_t *errc = nullptr /**< [in] [optional] error code */ );
537
538 /// Get the value as an unsigned short
539 /** This calls value<unsigned short>().
540 *
541 * \returns the value converted to unsigned short as necessary
542 *
543 */
544 unsigned short UShort( error_t *errc = nullptr /**< [in] [optional] error code */ );
545
546 /// Get the value as a int
547 /** This calls value<int>().
548 *
549 * \returns the value converted to int as necessary
550 *
551 */
552 int Int( error_t *errc = nullptr /**< [in] [optional] error code */ );
553
554 /// Get the value as an unsigned int
555 /** This calls value<unsigned int>().
556 *
557 * \returns the value converted to unsigned int as necessary
558 *
559 */
560 unsigned int UInt( error_t *errc = nullptr /**< [in] [optional] error code */ );
561
562 /// Get the value as a long
563 /** This calls value<long>().
564 *
565 * \returns the value converted to long as necessary
566 *
567 */
568 long Long( error_t *errc = nullptr /**< [in] [optional] error code */ );
569
570 /// Get the value as an unsigned long
571 /** This calls value<unsigned long>().
572 *
573 * \returns the value converted to unsigned long as necessary
574 *
575 */
576 unsigned long ULong( error_t *errc = nullptr /**< [in] [optional] error code */ );
577
578 /// Get the value as a long long
579 /** This calls value<long long>().
580 *
581 * \returns the value converted to long long as necessary
582 *
583 */
584 long long LongLong( error_t *errc = nullptr /**< [in] [optional] error code */ );
585
586 /// Get the value as an unsigned long long
587 /** This calls value<unsigned long long>().
588 *
589 * \returns the value converted to unsigned long long as necessaryvalue(
590 *
591 */
592 unsigned long long ULongLong( error_t *errc = nullptr /**< [in] [optional] error code */ );
593
594 /// Get the value as a float
595 /** This calls value<float>().
596 *
597 * \returns the value converted to float as necessary
598 *
599 */
600 float Float( error_t *errc = nullptr /**< [in] [optional] error code */ );
601
602 /// Get the value as a std::complex<float>
603 /** This calls value<std::complex<float>>().
604 *
605 * \returns the value converted to std::complex<float> as necessary
606 *
607 */
608 std::complex<float> complexFloat( error_t *errc = nullptr /**< [in] [optional] error code */ );
609
610 /// Get the value as a double
611 /** This calls value<double>().
612 *
613 * \returns the value converted to double as necessary
614 *
615 */
616 double Double( error_t *errc = nullptr /**< [in] [optional] error code */ );
617
618 /// Get the value as a std::complex<double>
619 /** This calls value<std::complex<double>>().
620 *
621 * \returns the value converted to std::complex<double> as necessary
622 *
623 */
624 std::complex<double> complexDouble( error_t *errc = nullptr /**< [in] [optional] error code */ );
625
626 /// Set the value to a char * string
627 error_t value( const char *v /**< [in] a character string*/ );
628
629 /// Set the value to a std::string
630 /**
631 */
632 error_t value( const std::string &v /**< [in] a std::string*/ );
633
634 /// Set the value for a non-string type
635 template <typename typeT>
636 mx::error_t value( const typeT &v /**< [in] the value to set */ );
637
638 /// Get the current value string
639 /**
640 * \returns m_valueStr;
641 */
642 std::string valueStr();
643
644 /// Get the current value good flag
645 /**
646 * \returns m_valueGood;
647 */
648 bool valueGood();
649
650 /// Get the current value string good flag
651 /**
652 * \returns m_valueStrGood;
653 */
655
656 /// Get the comment
657 /** \returns the value of m_comment
658 */
659 const std::string &comment();
660
661 /// Set the comment
662 /**
663 * \returns error_t::noerror on success
664 */
665 error_t comment( const std::string &c /**< [in] the new comment */ );
666
667 //@}
668
669 error_t appendContinue( const fitsHeaderCard &card );
670
671 ///\name Output
672 /**
673 */
674 //@{
675
676 /// Writes this card to a FITS file using \ref mx::fits::fits_write_key "fits_write_key".
677 /**
678 */
679 mx::error_t write( fitsfile *fptr );
680
681 //@}
682
683}; // fitsHeaderCard
684
685template <class verboseT>
689
690template <class verboseT>
691fitsHeaderCard<verboseT>::fitsHeaderCard( const std::string &k, const std::string &v, const std::string &c )
692{
693 m_keyword = k;
694
695 std::string str = v;
696 stripApostWS( str );
697 m_valueStr.str( str );
698 m_valueGood = false;
699 m_valueStrGood = true;
701 m_comment = c;
702}
703
704template <class verboseT>
705fitsHeaderCard<verboseT>::fitsHeaderCard( const std::string &k, char *v, const std::string &c )
706{
707 m_keyword = k;
708 std::string str = v;
709 stripApostWS( str );
710 m_valueStr.str( str );
711 m_valueGood = false;
712 m_valueStrGood = true;
714 m_comment = c;
715}
716
717template <class verboseT>
718fitsHeaderCard<verboseT>::fitsHeaderCard( const std::string &k, const char *v, const std::string &c )
719{
720 m_keyword = k;
721 std::string str = v;
722 stripApostWS( str );
723 m_valueStr.str( str );
724 m_valueGood = false;
725 m_valueStrGood = true;
727 m_comment = c;
728}
729
730template <class verboseT>
732 const std::string &v,
733 const int &type,
734 const std::string &c )
735{
736 m_keyword = k;
737 std::string str = v;
738 stripApostWS( str );
739 m_valueStr.str( str );
740 m_valueGood = false;
741 m_valueStrGood = true;
742 m_type = type;
743 m_comment = c;
744}
745
746template <class verboseT>
747fitsHeaderCard<verboseT>::fitsHeaderCard( const std::string &k, fitsCommentType v, const std::string &c )
748{
749 m_keyword = k;
750 m_valueGood = false;
751 m_valueStrGood = false;
753 m_comment = c;
754}
755
756template <class verboseT>
757fitsHeaderCard<verboseT>::fitsHeaderCard( const std::string &k, fitsHistoryType v, const std::string &c )
758{
759 m_keyword = k;
760 m_valueGood = false;
761 m_valueStrGood = false;
763 m_comment = c;
764}
765
766template <class verboseT>
768{
769 m_keyword = k;
770}
771
772template <class verboseT>
773fitsHeaderCard<verboseT>::fitsHeaderCard( const std::string &k, const int type )
774{
775 m_keyword = k;
776 m_type = type;
777}
778
779template <class verboseT>
780template <typename typeT>
781fitsHeaderCard<verboseT>::fitsHeaderCard( const std::string &k, const typeT v, const std::string &c )
782{
783 m_keyword = k;
784 value( v );
785 m_comment = c;
786}
787
788template <class verboseT>
790{
791 m_keyword = card.m_keyword;
792 m_type = card.m_type;
793 memcpy( &m_value, &card.m_value, sizeof( values ) );
794 m_valueStr.str( card.m_valueStr.str() );
797 m_comment = card.m_comment;
798}
799
800template <class verboseT>
802{
803 if( this == &card )
804 {
805 return *this;
806 }
807
808 m_keyword = card.m_keyword;
809 m_type = card.m_type;
810 memcpy( &m_value, &card.m_value, sizeof( values ) );
811 m_valueStr.str( card.m_valueStr.str() );
814 m_comment = card.m_comment;
815
816 return *this;
817}
818
819template <class verboseT>
821{
822 if( !m_valueGood )
823 {
825 }
826
828 {
829 m_valueStrGood = true; // It should be hard to get here, but just in case.
831 }
832
833 m_valueStr.str( "" );
834 m_valueStr.precision( 10 );
835
836 switch( m_type )
837 {
838 case fitsType<char>():
839 m_valueStr << static_cast<int>( m_value.Char );
840 break;
842 m_valueStr << static_cast<int>( m_value.UChar );
843 break;
844 case fitsType<short>():
845 m_valueStr << m_value.Short;
846 break;
848 m_valueStr << m_value.UShort;
849 break;
850 case fitsType<int>():
851 m_valueStr << m_value.Int;
852 break;
854 m_valueStr << m_value.UInt;
855 break;
856 case fitsType<long>():
857 m_valueStr << m_value.Long;
858 break;
860 m_valueStr << m_value.ULong;
861 break;
862 case fitsType<long long>():
863 m_valueStr << m_value.LongLong;
864 break;
866 m_valueStr << m_value.ULongLong;
867 break;
868 case fitsType<float>():
869 m_valueStr << m_value.Float;
870 break;
872 m_valueStr << m_value.complexFloat;
873 break;
874 case fitsType<double>():
875 m_valueStr << m_value.Double;
876 break;
878 m_valueStr << m_value.complexDouble;
879 break;
886 default:
888 "Unknown FITS type for " + m_keyword );
889 }
890
891 m_valueStrGood = true;
893}
894
895template <class verboseT>
896template <typename typeT>
898{
900
901 error_t errc;
902
903 m_value.template member<typeT>() = ioutils::stoT<typeT>( m_valueStr.str(), &errc );
904
905 if( errc != mx::error_t::noerror )
906 {
907 m_valueGood = false;
908 return errc;
909 }
910
911 m_valueGood = true;
912
913 return error_t::noerror;
914}
915
916template <class verboseT>
917template <typename typeT>
919{
920 switch( m_type )
921 {
923 {
924 cval = m_value.UChar;
925 return error_t::noerror;
926 }
927 case fitsType<char>():
928 {
929 cval = m_value.Char;
930 return error_t::noerror;
931 }
932 case fitsType<short>():
933 {
934 cval = m_value.Short;
935 return error_t::noerror;
936 }
938 {
939 cval = m_value.UShort;
940 return error_t::noerror;
941 }
942 case fitsType<int>():
943 {
944 cval = m_value.Int;
945 return error_t::noerror;
946 }
948 {
949 cval = m_value.UInt;
950 return error_t::noerror;
951 }
952 case fitsType<long>():
953 {
954 cval = m_value.Long;
955 return error_t::noerror;
956 }
958 {
959 cval = m_value.ULong;
960 return error_t::noerror;
961 }
962 case fitsType<long long>():
963 {
964 cval = m_value.LongLong;
965 return error_t::noerror;
966 }
968 {
969 cval = m_value.ULongLong;
970 return error_t::noerror;
971 }
972 case fitsType<float>():
973 {
974 cval = m_value.Float;
975 return error_t::noerror;
976 }
978 {
980 "can't convert complex type for " + m_keyword );
981 }
982 case fitsType<double>():
983 {
984 cval = m_value.Double;
985 return error_t::noerror;
986 }
988 {
990 "can't convert complex type for " + m_keyword );
991 }
993 {
995 "cannot convert comment to numeric type for " + m_keyword );
996 }
998 {
1000 "cannot convert history to numeric type for " + m_keyword );
1001 }
1003 {
1005 "cannot convert continue to numeric type for " + m_keyword );
1006 }
1007 case TSTRING:
1008 {
1010 "cannot convert string to numeric type for " + m_keyword );
1011 }
1012 default:
1013 {
1015 "invalid FITS type conversion for " + m_keyword );
1016 }
1017 }
1018}
1019
1020template <class verboseT>
1022{
1023 mx::error_t errc;
1024 switch( newtype )
1025 {
1027 {
1028 errc = convertedValue<unsigned char>( m_value.UChar );
1029 break;
1030 }
1031 case fitsType<char>():
1032 {
1033 errc = convertedValue<char>( m_value.Char );
1034 break;
1035 }
1036 case fitsType<short>():
1037 {
1038 errc = convertedValue<short>( m_value.Short );
1039 break;
1040 }
1042 {
1043 errc = convertedValue<unsigned short>( m_value.UShort );
1044 break;
1045 }
1046 case fitsType<int>():
1047 {
1048 errc = convertedValue<int>( m_value.Int );
1049 break;
1050 }
1052 {
1053 errc = convertedValue<unsigned int>( m_value.UInt );
1054 break;
1055 }
1056 case fitsType<long>():
1057 {
1058 errc = convertedValue<long>( m_value.Long );
1059 break;
1060 }
1062 {
1063 errc = convertedValue<unsigned long>( m_value.ULong );
1064 break;
1065 }
1066 case fitsType<long long>():
1067 {
1068 errc = convertedValue<long long>( m_value.LongLong );
1069 break;
1070 }
1072 {
1073 errc = convertedValue<unsigned long long>( m_value.ULongLong );
1074 break;
1075 }
1076 case fitsType<float>():
1077 {
1078 errc = convertedValue<float>( m_value.Float );
1079 break;
1080 }
1082 {
1084 "can't convert complex type for " + m_keyword );
1085 }
1086 case fitsType<double>():
1087 {
1088 errc = convertedValue<double>( m_value.Double );
1089 break;
1090 }
1092 {
1094 "can't convert complex type for " + m_keyword );
1095 }
1097 {
1099 "cannot convert comment to numeric type for " + m_keyword );
1100 }
1102 {
1104 "cannot convert history to numeric type for " + m_keyword );
1105 }
1107 {
1109 "cannot convert continue to numeric type for " + m_keyword );
1110 }
1111 case TSTRING:
1112 {
1114 m_type = newtype;
1115 m_valueGood = false;
1116 return error_t::noerror;
1117 }
1118 default:
1119 {
1121 "invalid FITS type conversion for " + m_keyword );
1122 }
1123 }
1124
1125 if( !!errc )
1126 {
1127 return errc;
1128 }
1129
1130 m_type = newtype;
1131 m_valueGood = true;
1132
1133 return error_t::noerror;
1134}
1135
1136template <class verboseT>
1137const std::string &fitsHeaderCard<verboseT>::keyword() const
1138{
1139 return m_keyword;
1140}
1141
1142template <class verboseT>
1144{
1145 m_keyword = kw;
1146 return error_t::noerror;
1147}
1148
1149template <class verboseT>
1151{
1152 return m_type;
1153}
1154
1155template <class verboseT>
1157{
1158 if( t == m_type )
1159 {
1160 return error_t::noerror;
1161 }
1162
1163 if( m_valueGood )
1164 {
1165 error_t errc = convertValue( t );
1166 if( errc != error_t::noerror )
1167 {
1168 return errc;
1169 }
1170 }
1171 else
1172 {
1173 m_type = t;
1174 }
1175
1176 // Need to reconvert, always favor the actual value.
1178 {
1179 m_valueStrGood = false;
1180 }
1181
1182 return error_t::noerror;
1183}
1184
1185template <class verboseT>
1186template <typename typeT>
1188{
1189 errc = mx::error_t::noerror; // to be changed if needed
1190
1191 if( m_valueGood == false )
1192 {
1193 errc = convertFromString<typeT>();
1194 if( errc != error_t::noerror )
1195 {
1196 return typeT{};
1197 }
1198 }
1199
1200 if( m_type != fitsType<typeT>() )
1201 {
1202 typeT val{};
1203 errc = convertedValue<typeT>( val );
1204 return val;
1205 }
1206
1207 return m_value.template member<typeT>();
1208}
1209
1210template <class verboseT>
1212{
1213 errc = mx::error_t::noerror;
1214
1215 if( m_valueStrGood == false )
1216 {
1217 errc = convertToString();
1218 if( !!errc )
1219 {
1220 return "";
1221 }
1222 }
1223
1224 // Strip ' from beginning and end if present
1225 std::string str = m_valueStr.str();
1226
1227 // Reload it so it's there for next time:
1228 m_valueStr.str( str );
1229
1230 return str;
1231}
1232
1233template <class verboseT>
1238
1239template <class verboseT>
1244
1245template <class verboseT>
1250
1251template <class verboseT>
1256
1257template <class verboseT>
1262
1263template <class verboseT>
1268
1269template <class verboseT>
1274
1275template <class verboseT>
1280
1281template <class verboseT>
1286
1287template <class verboseT>
1292
1293template <class verboseT>
1298
1299template <class verboseT>
1304
1305template <class verboseT>
1306template <typename typeT>
1308{
1309 mx::error_t _errc;
1310
1311 typeT val = value( meta::tagT<typeT>(), _errc );
1312
1313 if( errc )
1314 {
1315 *errc = _errc;
1316 }
1317
1318 if( _errc != mx::error_t::noerror )
1319 {
1320 internal::mxlib_error_report<verboseT>( _errc, "getting value for " + m_keyword );
1321 }
1322
1323 return val;
1324} // LCOV_EXCL_LINE
1325
1326template <class verboseT>
1328{
1329 return value<std::string>( errc );
1330}
1331
1332template <class verboseT>
1334{
1335 return value<char>( errc );
1336}
1337
1338template <class verboseT>
1340{
1341 return value<unsigned char>( errc );
1342}
1343
1344template <class verboseT>
1346{
1347 return value<short>( errc );
1348}
1349
1350template <class verboseT>
1352{
1353 return value<unsigned short>( errc );
1354}
1355
1356template <class verboseT>
1358{
1359 return value<int>( errc );
1360}
1361
1362template <class verboseT>
1364{
1365 return value<unsigned int>( errc );
1366}
1367
1368template <class verboseT>
1370{
1371 return value<long>( errc );
1372}
1373
1374template <class verboseT>
1376{
1377 return value<unsigned long>( errc );
1378}
1379
1380template <class verboseT>
1382{
1383 return value<long long>( errc );
1384}
1385
1386template <class verboseT>
1388{
1389 return value<unsigned long long>( errc );
1390}
1391
1392template <class verboseT>
1394{
1395 return value<float>( errc );
1396}
1397
1398/*template <class verboseT>
1399std::complex<float> fitsHeaderCard<verboseT>::complexFloat()
1400{
1401 return value<std::complex<float>>();
1402}*/
1403
1404template <class verboseT>
1406{
1407 return value<double>( errc );
1408}
1409
1410/*
1411template <class verboseT>
1412std::complex<double> fitsHeaderCard<verboseT>::complexDouble()
1413{
1414 return value<std::complex<double>>();
1415}*/
1416
1417template <class verboseT>
1419{
1420 std::string str = v;
1421
1422 return value( str );
1423}
1424
1425template <class verboseT>
1427{
1428 // Strip ' from beginning and end if present
1429 std::string str = v;
1430
1431 stripApostWS( str );
1432
1433 // Reload it so it's there for next time:
1434 m_valueStr.str( str );
1435 m_valueGood = false;
1436 m_valueStrGood = true;
1438
1439 return mx::error_t::noerror;
1440}
1441
1442template <class verboseT>
1443template <typename typeT>
1445{
1447 m_value.template member<typeT>() = v;
1448 m_valueGood = true;
1449 m_valueStrGood = false;
1450
1451 return mx::error_t::noerror;
1452}
1453
1454template <class verboseT>
1456{
1457 if( !m_valueStrGood )
1458 {
1460 }
1461
1462 std::string s = m_valueStr.str();
1463 return s;
1464}
1465
1466template <class verboseT>
1468{
1469 return m_valueGood;
1470}
1471
1472template <class verboseT>
1477
1478template <class verboseT>
1480{
1481 return m_comment;
1482}
1483
1484template <class verboseT>
1486{
1487 m_comment = c;
1488 return error_t::noerror;
1489}
1490
1491template <class verboseT>
1492error_t fitsHeaderCard<verboseT>::appendContinue( const fitsHeaderCard<verboseT> &card )
1493{
1494 // Check if m_type is string
1495 if( m_type != fitsType<char *>() && m_type != fitsType<std::string>() )
1496 {
1497 return internal::mxlib_error_report<verboseT>( error_t::invalidarg, "attempt to continue a non-string card" );
1498 }
1499
1500 // Check if m_valueStrGood is true
1501 if( !m_valueStrGood )
1502 {
1504 "attempt to continue a card with no value" );
1505 }
1506
1507 std::string newstr = card.m_comment;
1508
1509 // Check if this is the last one
1510 size_t slash = newstr.find_last_of( '\'' );
1511 if( slash != std::string::npos )
1512 {
1513 slash = newstr.find_first_of( '/', slash );
1514
1515 if( slash != std::string::npos )
1516 {
1517 // extract comment
1518 size_t comm = newstr.find_first_not_of( ' ', slash + 1 );
1519 if( comm != std::string::npos )
1520 {
1521 m_comment = newstr.substr( comm );
1522 }
1523
1524 // and then erase it
1525 newstr.erase( slash );
1526 }
1527 }
1528 stripApostWS( newstr );
1529
1530 // have to remove & if needed
1531 std::string vstr = m_valueStr.str();
1532 if( !vstr.empty() && vstr.back() == '&' )
1533 {
1534 vstr.erase( vstr.size() - 1 );
1535 }
1536
1537 m_valueStr.str( vstr + newstr );
1538
1539 return error_t::noerror;
1540}
1541
1542template <class verboseT>
1544{
1546 {
1547 return fits_write_key<char *>( fptr,
1548 (char *)m_keyword.c_str(),
1549 (void *)m_valueStr.str().c_str(),
1550 (char *)m_comment.c_str() );
1551 }
1552
1553 // If the string is good, meaning already converted.
1554 if( m_valueStrGood == true )
1555 {
1556 // This populates the card directly.
1558 (char *)m_keyword.c_str(),
1559 (void *)m_valueStr.str().c_str(),
1560 (char *)m_comment.c_str() );
1561 }
1562
1563 // Ok, now we write the type directly using fitsio routines because it hasn't been converted.
1564 switch( m_type )
1565 {
1566 case fitsType<bool>():
1567 {
1568 return fits_write_key<bool>( fptr, (char *)m_keyword.c_str(), &m_value.Bool, (char *)m_comment.c_str() );
1569 }
1570 case fitsType<char>():
1571 {
1572 return fits_write_key<char>( fptr, (char *)m_keyword.c_str(), &m_value.Char, (char *)m_comment.c_str() );
1573 }
1575 {
1576 return fits_write_key<unsigned char>( fptr,
1577 (char *)m_keyword.c_str(),
1578 &m_value.UChar,
1579 (char *)m_comment.c_str() );
1580 }
1581 case fitsType<short>():
1582 {
1583 return fits_write_key<short>( fptr, (char *)m_keyword.c_str(), &m_value.Short, (char *)m_comment.c_str() );
1584 }
1586 {
1587 return fits_write_key<unsigned short>( fptr,
1588 (char *)m_keyword.c_str(),
1589 &m_value.UShort,
1590 (char *)m_comment.c_str() );
1591 }
1592 case fitsType<int>():
1593 {
1594 return fits_write_key<int>( fptr, (char *)m_keyword.c_str(), &m_value.Int, (char *)m_comment.c_str() );
1595 }
1597 {
1598 return fits_write_key<unsigned int>( fptr,
1599 (char *)m_keyword.c_str(),
1600 &m_value.UInt,
1601 (char *)m_comment.c_str() );
1602 }
1603 case fitsType<long>():
1604 {
1605 return fits_write_key<long>( fptr, (char *)m_keyword.c_str(), &m_value.Long, (char *)m_comment.c_str() );
1606 }
1608 {
1609 return fits_write_key<unsigned long>( fptr,
1610 (char *)m_keyword.c_str(),
1611 &m_value.ULong,
1612 (char *)m_comment.c_str() );
1613 }
1614 case fitsType<long long>():
1615 {
1616 return fits_write_key<long long>( fptr,
1617 (char *)m_keyword.c_str(),
1618 &m_value.LongLong,
1619 (char *)m_comment.c_str() );
1620 }
1622 {
1624 (char *)m_keyword.c_str(),
1625 &m_value.ULongLong,
1626 (char *)m_comment.c_str() );
1627 }
1628 case fitsType<float>():
1629 {
1630 return fits_write_key<float>( fptr, (char *)m_keyword.c_str(), &m_value.Float, (char *)m_comment.c_str() );
1631 }
1632 case fitsType<double>():
1633 {
1634 return fits_write_key<double>( fptr,
1635 (char *)m_keyword.c_str(),
1636 &m_value.Double,
1637 (char *)m_comment.c_str() );
1638 }
1640 {
1641 return fits_write_comment( fptr, (char *)m_comment.c_str() );
1642 }
1644 {
1645 return fits_write_history( fptr, (char *)m_comment.c_str() );
1646 }
1647 default:
1648 {
1649 return internal::mxlib_error_report<verboseT>( error_t::invalidarg, "invalid FITS type for " + m_keyword );
1650 }
1651 }
1652}
1653
1654extern template class fitsHeaderCard<verbose::d>;
1655
1656} // namespace fits
1657} // namespace mx
1658
1659#endif // ioutils_fits_fitsHeaderCard_hpp
Class to manage the three components of a FITS header card.
std::complex< float > complexFloat(error_t *errc=nullptr)
Get the value as a std::complex<float>.
error_t convertFromString()
Convert from string to the type.
mx::error_t write(fitsfile *fptr)
Writes this card to a FITS file using fits_write_key.
std::string value(meta::tagT< std::string >, mx::error_t &errc)
Get value tag dispatcher for std::string.
unsigned short UShort(error_t *errc=nullptr)
Get the value as an unsigned short.
unsigned char UChar(error_t *errc=nullptr)
Get the value as an unsigned char.
bool m_valueGood
Flag indicating if the value is valid.
float Float(error_t *errc=nullptr)
Get the value as a float.
double Double(error_t *errc=nullptr)
Get the value as a double.
long long LongLong(error_t *errc=nullptr)
Get the value as a long long.
char Char(error_t *errc=nullptr)
Get the value as a char.
long Long(error_t *errc=nullptr)
Get the value as a long.
bool valueStrGood()
Get the current value string good flag.
std::string m_comment
The comment.
bool m_valueStrGood
Flag indicating if the value string is valid.
unsigned int UInt(error_t *errc=nullptr)
Get the value as an unsigned int.
const std::string & keyword() const
Get the keyword.
mx::error_t convertToString()
Convert from the type to a string.
std::string m_keyword
The keyword.
error_t convertValue(int newtype)
Convert the value from its type to a different type.
error_t convertedValue(typeT &cval)
Get the value from its type converted to a different type.
short Short(error_t *errc=nullptr)
Get the value as a short.
bool valueGood()
Get the current value good flag.
unsigned long long ULongLong(error_t *errc=nullptr)
Get the value as an unsigned long long.
std::string valueStr()
Get the current value string.
unsigned long ULong(error_t *errc=nullptr)
Get the value as an unsigned long.
const std::string & comment()
Get the comment.
std::string String(error_t *errc=nullptr)
Get the value as a string.
typeT valueNonString(mx::error_t &errc)
Get value for anything not a string.
int m_type
The FITS type of the value, and indicates which member of m_values to access.
int Int(error_t *errc=nullptr)
Get the value as a int.
std::complex< double > complexDouble(error_t *errc=nullptr)
Get the value as a std::complex<double>.
std::stringstream m_valueStr
The value in string form.
fitsHeaderCard & operator=(const fitsHeaderCard &card)
Assignment.
Declares and defines utilities to work with FITS files.
error_t
The mxlib error codes.
Definition error_t.hpp:26
@ notimpl
A component or technique is not implemented.
Definition error_t.hpp:31
@ noerror
No error has occurred.
Definition error_t.hpp:27
@ paramnotset
A parameter was not set.
Definition error_t.hpp:32
@ invalidconfig
A config setting was invalid.
Definition error_t.hpp:30
@ invalidarg
An argument was invalid.
Definition error_t.hpp:29
error_t mxlib_error_report(const error_t &code, const std::string &expl, const std::source_location &loc=std::source_location::current())
Print a report to stderr given an mxlib error_t code and explanation and return the code.
Definition error.hpp:331
constexpr int fitsType()
Return the cfitsio constant for a given data type.
mx::error_t fits_write_key< bool >(fitsfile *fptr, char *keyword, void *value, char *comment)
Specialization to handle the case bool.
mx::error_t fits_write_key(fitsfile *fptr, char *keyword, void *value, char *comment)
Write a header card to a file.
typeT stoT(const std::string &str, error_t *errc=nullptr)
Convert a string to a numerical value.
Declarations of some libarary wide utilities.
The mxlib c++ namespace.
Definition mxlib.hpp:37
Empty type for tag dispatching.
Definition tagT.hpp:44
Declares and defines an empty struct for tag dispatching.
The native type is held in a union.
std::complex< float > complexFloat
the std::complex<float> value
unsigned char UChar
the unsigned char value
values()
c'tor. have to specify due to inclusion of std::complex types.
unsigned long long ULongLong
the unsigned long long value
unsigned long ULong
the unsigned long value
unsigned int UInt
the unsigned int value
std::complex< long double > complexLongDouble
the std::complex<long double> value
long double LongDouble
the long double value
unsigned short UShort
the unsigned short value
long long LongLong
the long long value
std::complex< double > complexDouble
the std::complex<double> value