openPMD-api
Datatype.hpp
1 /* Copyright 2017-2021 Fabian Koller, Franz Poeschel, Axel Huebl
2  *
3  * This file is part of openPMD-api.
4  *
5  * openPMD-api is free software: you can redistribute it and/or modify
6  * it under the terms of of either the GNU General Public License or
7  * the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * openPMD-api is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License and the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * and the GNU Lesser General Public License along with openPMD-api.
19  * If not, see <http://www.gnu.org/licenses/>.
20  */
21 #pragma once
22 
23 #include <array>
24 #include <climits>
25 #include <complex>
26 #include <cstdint>
27 #include <iosfwd>
28 #include <map>
29 #include <memory>
30 #include <stdexcept>
31 #include <string>
32 #include <tuple>
33 #include <type_traits>
34 #include <utility> // std::declval
35 #include <vector>
36 
37 namespace openPMD
38 {
39 
40 constexpr int LOWEST_DATATYPE = 0;
41 constexpr int HIGHEST_DATATYPE = 1000;
42 
45 enum class Datatype : int
46 {
47  CHAR = LOWEST_DATATYPE,
48  UCHAR, // SCHAR,
49  SHORT,
50  INT,
51  LONG,
52  LONGLONG,
53  USHORT,
54  UINT,
55  ULONG,
56  ULONGLONG,
57  FLOAT,
58  DOUBLE,
59  LONG_DOUBLE,
60  CFLOAT,
61  CDOUBLE,
62  CLONG_DOUBLE,
63  STRING,
64  VEC_CHAR,
65  VEC_SHORT,
66  VEC_INT,
67  VEC_LONG,
68  VEC_LONGLONG,
69  VEC_UCHAR,
70  VEC_USHORT,
71  VEC_UINT,
72  VEC_ULONG,
73  VEC_ULONGLONG,
74  VEC_FLOAT,
75  VEC_DOUBLE,
76  VEC_LONG_DOUBLE,
77  VEC_CFLOAT,
78  VEC_CDOUBLE,
79  VEC_CLONG_DOUBLE,
80  VEC_STRING,
81  ARR_DBL_7,
82 
83  BOOL,
84 
85  DATATYPE = HIGHEST_DATATYPE,
86 
87  UNDEFINED
88 }; // Datatype
89 
95 extern std::vector<Datatype> openPMD_Datatypes;
96 
106 template <typename T, typename U>
108  : std::is_same<
109  typename std::remove_pointer<typename std::remove_cv<
110  typename std::decay<typename std::remove_all_extents<T>::type>::
111  type>::type>::type,
112  typename std::remove_pointer<typename std::remove_cv<
113  typename std::decay<typename std::remove_all_extents<U>::type>::
114  type>::type>::type>::type
115 {};
116 
117 template <typename T, typename U>
118 constexpr bool decay_equiv_v = decay_equiv<T, U>::value;
119 
120 template <typename T>
121 inline constexpr Datatype determineDatatype()
122 {
123  using DT = Datatype;
125  {
126  return DT::CHAR;
127  }
129  {
130  return DT::UCHAR;
131  }
133  {
134  return DT::SHORT;
135  }
137  {
138  return DT::INT;
139  }
141  {
142  return DT::LONG;
143  }
145  {
146  return DT::LONGLONG;
147  }
149  {
150  return DT::USHORT;
151  }
153  {
154  return DT::UINT;
155  }
157  {
158  return DT::ULONG;
159  }
161  {
162  return DT::ULONGLONG;
163  }
165  {
166  return DT::FLOAT;
167  }
169  {
170  return DT::DOUBLE;
171  }
173  {
174  return DT::LONG_DOUBLE;
175  }
176  else if (decay_equiv<T, std::complex<float>>::value)
177  {
178  return DT::CFLOAT;
179  }
180  else if (decay_equiv<T, std::complex<double>>::value)
181  {
182  return DT::CDOUBLE;
183  }
184  else if (decay_equiv<T, std::complex<long double>>::value)
185  {
186  return DT::CLONG_DOUBLE;
187  }
189  {
190  return DT::STRING;
191  }
192  else if (decay_equiv<T, std::vector<char>>::value)
193  {
194  return DT::VEC_CHAR;
195  }
196  else if (decay_equiv<T, std::vector<short>>::value)
197  {
198  return DT::VEC_SHORT;
199  }
200  else if (decay_equiv<T, std::vector<int>>::value)
201  {
202  return DT::VEC_INT;
203  }
204  else if (decay_equiv<T, std::vector<long>>::value)
205  {
206  return DT::VEC_LONG;
207  }
208  else if (decay_equiv<T, std::vector<long long>>::value)
209  {
210  return DT::VEC_LONGLONG;
211  }
212  else if (decay_equiv<T, std::vector<unsigned char>>::value)
213  {
214  return DT::VEC_UCHAR;
215  }
216  else if (decay_equiv<T, std::vector<unsigned short>>::value)
217  {
218  return DT::VEC_USHORT;
219  }
220  else if (decay_equiv<T, std::vector<unsigned int>>::value)
221  {
222  return DT::VEC_UINT;
223  }
224  else if (decay_equiv<T, std::vector<unsigned long>>::value)
225  {
226  return DT::VEC_ULONG;
227  }
228  else if (decay_equiv<T, std::vector<unsigned long long>>::value)
229  {
230  return DT::VEC_ULONGLONG;
231  }
232  else if (decay_equiv<T, std::vector<float>>::value)
233  {
234  return DT::VEC_FLOAT;
235  }
236  else if (decay_equiv<T, std::vector<double>>::value)
237  {
238  return DT::VEC_DOUBLE;
239  }
240  else if (decay_equiv<T, std::vector<long double>>::value)
241  {
242  return DT::VEC_LONG_DOUBLE;
243  }
244  else if (decay_equiv<T, std::vector<std::complex<float>>>::value)
245  {
246  return DT::VEC_CFLOAT;
247  }
248  else if (decay_equiv<T, std::vector<std::complex<double>>>::value)
249  {
250  return DT::VEC_CDOUBLE;
251  }
252  else if (decay_equiv<T, std::vector<std::complex<long double>>>::value)
253  {
254  return DT::VEC_CLONG_DOUBLE;
255  }
256  else if (decay_equiv<T, std::vector<std::string>>::value)
257  {
258  return DT::VEC_STRING;
259  }
260  else if (decay_equiv<T, std::array<double, 7>>::value)
261  {
262  return DT::ARR_DBL_7;
263  }
265  {
266  return DT::BOOL;
267  }
268  else
269  return Datatype::UNDEFINED;
270 }
271 
272 template <typename T>
273 inline constexpr Datatype determineDatatype(std::shared_ptr<T>)
274 {
275  using DT = Datatype;
277  {
278  return DT::CHAR;
279  }
281  {
282  return DT::UCHAR;
283  }
285  {
286  return DT::SHORT;
287  }
289  {
290  return DT::INT;
291  }
293  {
294  return DT::LONG;
295  }
297  {
298  return DT::LONGLONG;
299  }
301  {
302  return DT::USHORT;
303  }
305  {
306  return DT::UINT;
307  }
309  {
310  return DT::ULONG;
311  }
313  {
314  return DT::ULONGLONG;
315  }
317  {
318  return DT::FLOAT;
319  }
321  {
322  return DT::DOUBLE;
323  }
325  {
326  return DT::LONG_DOUBLE;
327  }
328  else if (decay_equiv<T, std::complex<float>>::value)
329  {
330  return DT::CFLOAT;
331  }
332  else if (decay_equiv<T, std::complex<double>>::value)
333  {
334  return DT::CDOUBLE;
335  }
336  else if (decay_equiv<T, std::complex<long double>>::value)
337  {
338  return DT::CLONG_DOUBLE;
339  }
341  {
342  return DT::STRING;
343  }
344  else if (decay_equiv<T, std::vector<char>>::value)
345  {
346  return DT::VEC_CHAR;
347  }
348  else if (decay_equiv<T, std::vector<short>>::value)
349  {
350  return DT::VEC_SHORT;
351  }
352  else if (decay_equiv<T, std::vector<int>>::value)
353  {
354  return DT::VEC_INT;
355  }
356  else if (decay_equiv<T, std::vector<long>>::value)
357  {
358  return DT::VEC_LONG;
359  }
360  else if (decay_equiv<T, std::vector<long long>>::value)
361  {
362  return DT::VEC_LONGLONG;
363  }
364  else if (decay_equiv<T, std::vector<unsigned char>>::value)
365  {
366  return DT::VEC_UCHAR;
367  }
368  else if (decay_equiv<T, std::vector<unsigned short>>::value)
369  {
370  return DT::VEC_USHORT;
371  }
372  else if (decay_equiv<T, std::vector<unsigned int>>::value)
373  {
374  return DT::VEC_UINT;
375  }
376  else if (decay_equiv<T, std::vector<unsigned long>>::value)
377  {
378  return DT::VEC_ULONG;
379  }
380  else if (decay_equiv<T, std::vector<unsigned long long>>::value)
381  {
382  return DT::VEC_ULONGLONG;
383  }
384  else if (decay_equiv<T, std::vector<float>>::value)
385  {
386  return DT::VEC_FLOAT;
387  }
388  else if (decay_equiv<T, std::vector<double>>::value)
389  {
390  return DT::VEC_DOUBLE;
391  }
392  else if (decay_equiv<T, std::vector<long double>>::value)
393  {
394  return DT::VEC_LONG_DOUBLE;
395  }
396  else if (decay_equiv<T, std::vector<std::complex<float>>>::value)
397  {
398  return DT::VEC_CFLOAT;
399  }
400  else if (decay_equiv<T, std::vector<std::complex<double>>>::value)
401  {
402  return DT::VEC_CDOUBLE;
403  }
404  else if (decay_equiv<T, std::vector<std::complex<long double>>>::value)
405  {
406  return DT::VEC_CLONG_DOUBLE;
407  }
408  else if (decay_equiv<T, std::vector<std::string>>::value)
409  {
410  return DT::VEC_STRING;
411  }
412  else if (decay_equiv<T, std::array<double, 7>>::value)
413  {
414  return DT::ARR_DBL_7;
415  }
417  {
418  return DT::BOOL;
419  }
420  else
421  return DT::UNDEFINED;
422 }
423 
429 inline size_t toBytes(Datatype d)
430 {
431  using DT = Datatype;
432  switch (d)
433  {
434  case DT::CHAR:
435  case DT::VEC_CHAR:
436  case DT::STRING:
437  case DT::VEC_STRING:
438  return sizeof(char);
439  case DT::UCHAR:
440  case DT::VEC_UCHAR:
441  return sizeof(unsigned char);
442  // case DT::SCHAR:
443  // case DT::VEC_SCHAR:
444  // return sizeof(signed char);
445  case DT::SHORT:
446  case DT::VEC_SHORT:
447  return sizeof(short);
448  case DT::INT:
449  case DT::VEC_INT:
450  return sizeof(int);
451  case DT::LONG:
452  case DT::VEC_LONG:
453  return sizeof(long);
454  case DT::LONGLONG:
455  case DT::VEC_LONGLONG:
456  return sizeof(long long);
457  case DT::USHORT:
458  case DT::VEC_USHORT:
459  return sizeof(unsigned short);
460  case DT::UINT:
461  case DT::VEC_UINT:
462  return sizeof(unsigned int);
463  case DT::ULONG:
464  case DT::VEC_ULONG:
465  return sizeof(unsigned long);
466  case DT::ULONGLONG:
467  case DT::VEC_ULONGLONG:
468  return sizeof(unsigned long long);
469  case DT::FLOAT:
470  case DT::VEC_FLOAT:
471  return sizeof(float);
472  case DT::DOUBLE:
473  case DT::VEC_DOUBLE:
474  case DT::ARR_DBL_7:
475  return sizeof(double);
476  case DT::LONG_DOUBLE:
477  case DT::VEC_LONG_DOUBLE:
478  return sizeof(long double);
479  case DT::CFLOAT:
480  case DT::VEC_CFLOAT:
481  return sizeof(float) * 2;
482  case DT::CDOUBLE:
483  case DT::VEC_CDOUBLE:
484  return sizeof(double) * 2;
485  case DT::CLONG_DOUBLE:
486  case DT::VEC_CLONG_DOUBLE:
487  return sizeof(long double) * 2;
488  case DT::BOOL:
489  return sizeof(bool);
490  case DT::DATATYPE:
491  case DT::UNDEFINED:
492  default:
493  throw std::runtime_error("toBytes: Invalid datatype!");
494  }
495 }
496 
502 inline size_t toBits(Datatype d)
503 {
504  return toBytes(d) * CHAR_BIT;
505 }
506 
512 inline bool isVector(Datatype d)
513 {
514  using DT = Datatype;
515 
516  switch (d)
517  {
518  case DT::VEC_CHAR:
519  case DT::VEC_SHORT:
520  case DT::VEC_INT:
521  case DT::VEC_LONG:
522  case DT::VEC_LONGLONG:
523  case DT::VEC_UCHAR:
524  case DT::VEC_USHORT:
525  case DT::VEC_UINT:
526  case DT::VEC_ULONG:
527  case DT::VEC_ULONGLONG:
528  case DT::VEC_FLOAT:
529  case DT::VEC_DOUBLE:
530  case DT::VEC_LONG_DOUBLE:
531  case DT::VEC_CFLOAT:
532  case DT::VEC_CDOUBLE:
533  case DT::VEC_CLONG_DOUBLE:
534  case DT::VEC_STRING:
535  return true;
536  default:
537  return false;
538  }
539 }
540 
548 inline bool isFloatingPoint(Datatype d)
549 {
550  using DT = Datatype;
551 
552  switch (d)
553  {
554  case DT::FLOAT:
555  case DT::VEC_FLOAT:
556  case DT::DOUBLE:
557  case DT::VEC_DOUBLE:
558  case DT::LONG_DOUBLE:
559  case DT::VEC_LONG_DOUBLE:
560  // note: complex floats are not std::is_floating_point
561  return true;
562  default:
563  return false;
564  }
565 }
566 
575 {
576  using DT = Datatype;
577 
578  switch (d)
579  {
580  case DT::CFLOAT:
581  case DT::VEC_CFLOAT:
582  case DT::CDOUBLE:
583  case DT::VEC_CDOUBLE:
584  case DT::CLONG_DOUBLE:
585  case DT::VEC_CLONG_DOUBLE:
586  return true;
587  default:
588  return false;
589  }
590 }
591 
599 template <typename T>
600 inline bool isFloatingPoint()
601 {
602  Datatype dtype = determineDatatype<T>();
603 
604  return isFloatingPoint(dtype);
605 }
606 
614 template <typename T>
616 {
617  Datatype dtype = determineDatatype<T>();
618 
619  return isComplexFloatingPoint(dtype);
620 }
621 
630 inline std::tuple<bool, bool> isInteger(Datatype d)
631 {
632  using DT = Datatype;
633 
634  switch (d)
635  {
636  case DT::SHORT:
637  case DT::VEC_SHORT:
638  case DT::INT:
639  case DT::VEC_INT:
640  case DT::LONG:
641  case DT::VEC_LONG:
642  case DT::LONGLONG:
643  case DT::VEC_LONGLONG:
644  return std::make_tuple(true, true);
645  case DT::USHORT:
646  case DT::VEC_USHORT:
647  case DT::UINT:
648  case DT::VEC_UINT:
649  case DT::ULONG:
650  case DT::VEC_ULONG:
651  case DT::ULONGLONG:
652  case DT::VEC_ULONGLONG:
653  return std::make_tuple(true, false);
654  default:
655  return std::make_tuple(false, false);
656  }
657 }
658 
667 template <typename T>
668 inline std::tuple<bool, bool> isInteger()
669 {
670  Datatype dtype = determineDatatype<T>();
671 
672  return isInteger(dtype);
673 }
674 
681 template <typename T_FP>
683 {
684  // template
685  bool tt_is_fp = isFloatingPoint<T_FP>();
686 
687  // Datatype
688  bool dt_is_fp = isFloatingPoint(d);
689 
690  if (tt_is_fp && dt_is_fp && toBits(d) == toBits(determineDatatype<T_FP>()))
691  return true;
692  else
693  return false;
694 }
695 
703 template <typename T_CFP>
705 {
706  // template
707  bool tt_is_cfp = isComplexFloatingPoint<T_CFP>();
708 
709  // Datatype
710  bool dt_is_cfp = isComplexFloatingPoint(d);
711 
712  if (tt_is_cfp && dt_is_cfp &&
713  toBits(d) == toBits(determineDatatype<T_CFP>()))
714  return true;
715  else
716  return false;
717 }
718 
726 template <typename T_Int>
727 inline bool isSameInteger(Datatype d)
728 {
729  // template
730  bool tt_is_int, tt_is_sig;
731  std::tie(tt_is_int, tt_is_sig) = isInteger<T_Int>();
732 
733  // Datatype
734  bool dt_is_int, dt_is_sig;
735  std::tie(dt_is_int, dt_is_sig) = isInteger(d);
736 
737  if (tt_is_int && dt_is_int && tt_is_sig == dt_is_sig &&
738  toBits(d) == toBits(determineDatatype<T_Int>()))
739  return true;
740  else
741  return false;
742 }
743 
750 inline bool isSame(openPMD::Datatype const d, openPMD::Datatype const e)
751 {
752  // exact same type
753  if (static_cast<int>(d) == static_cast<int>(e))
754  return true;
755 
756  bool d_is_vec = isVector(d);
757  bool e_is_vec = isVector(e);
758 
759  // same int
760  bool d_is_int, d_is_sig;
761  std::tie(d_is_int, d_is_sig) = isInteger(d);
762  bool e_is_int, e_is_sig;
763  std::tie(e_is_int, e_is_sig) = isInteger(e);
764  if (d_is_int && e_is_int && d_is_vec == e_is_vec && d_is_sig == e_is_sig &&
765  toBits(d) == toBits(e))
766  return true;
767 
768  // same float
769  bool d_is_fp = isFloatingPoint(d);
770  bool e_is_fp = isFloatingPoint(e);
771 
772  if (d_is_fp && e_is_fp && d_is_vec == e_is_vec && toBits(d) == toBits(e))
773  return true;
774 
775  // same complex floating point
776  bool d_is_cfp = isComplexFloatingPoint(d);
777  bool e_is_cfp = isComplexFloatingPoint(e);
778 
779  if (d_is_cfp && e_is_cfp && d_is_vec == e_is_vec && toBits(d) == toBits(e))
780  return true;
781 
782  return false;
783 }
784 
785 namespace detail
786 {
787  template <typename T>
789  {
790  Datatype m_dt = determineDatatype<T>();
791  };
792 
793  template <typename T>
794  struct BasicDatatypeHelper<std::vector<T>>
795  {
796  Datatype m_dt = BasicDatatypeHelper<T>{}.m_dt;
797  };
798 
799  template <typename T, std::size_t n>
800  struct BasicDatatypeHelper<std::array<T, n>>
801  {
802  Datatype m_dt = BasicDatatypeHelper<T>{}.m_dt;
803  };
804 
806  {
807  template <typename T>
808  Datatype operator()();
809 
810  template <int n>
811  Datatype operator()();
812  };
813 } // namespace detail
814 
822 
823 Datatype toVectorType(Datatype dt);
824 
825 std::string datatypeToString(Datatype dt);
826 
827 Datatype stringToDatatype(std::string s);
828 
829 void warnWrongDtype(std::string const &key, Datatype store, Datatype request);
830 
831 std::ostream &operator<<(std::ostream &, openPMD::Datatype const &);
832 
833 } // namespace openPMD
834 
835 #if !defined(_MSC_VER)
836 
848 inline bool operator==(openPMD::Datatype d, openPMD::Datatype e)
849 {
850  return openPMD::isSame(d, e);
851 }
852 
853 inline bool operator!=(openPMD::Datatype d, openPMD::Datatype e)
854 {
855  return !(d == e);
856 }
859 #endif
bool isVector(Datatype d)
Compare if a Datatype is a vector type.
Definition: Datatype.hpp:512
std::vector< Datatype > openPMD_Datatypes
All openPMD datatypes defined in Datatype, listed in order in a vector.
Definition: Datatype.cpp:222
bool isSameFloatingPoint(Datatype d)
Compare if a Datatype is equivalent to a floating point type.
Definition: Datatype.hpp:682
bool isSameComplexFloatingPoint(Datatype d)
Compare if a Datatype is equivalent to a complex floating point type.
Definition: Datatype.hpp:704
bool isSameInteger(Datatype d)
Compare if a Datatype is equivalent to an integer type.
Definition: Datatype.hpp:727
STL namespace.
Fundamental equivalence check for two given types T and U.
Definition: Datatype.hpp:107
bool isComplexFloatingPoint(Datatype d)
Compare if a Datatype is a complex floating point type.
Definition: Datatype.hpp:574
Datatype
Concrete datatype of an object available at runtime.
Definition: Datatype.hpp:45
Definition: Container.cpp:50
size_t toBits(Datatype d)
Return number of bits representing a Datatype.
Definition: Datatype.hpp:502
Definition: Datatype.hpp:788
Public definitions of openPMD-api.
Definition: Date.cpp:28
Datatype basicDatatype(Datatype dt)
basicDatatype Strip openPMD Datatype of std::vector, std::array et.
Definition: Datatype.cpp:237
size_t toBytes(Datatype d)
Return number of bytes representing a Datatype.
Definition: Datatype.hpp:429
Definition: Datatype.hpp:805
bool isFloatingPoint(Datatype d)
Compare if a Datatype is a floating point type.
Definition: Datatype.hpp:548
std::tuple< bool, bool > isInteger(Datatype d)
Compare if a Datatype is an integer type.
Definition: Datatype.hpp:630
bool isSame(openPMD::Datatype const d, openPMD::Datatype const e)
Comparison for two Datatypes.
Definition: Datatype.hpp:750