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 "openPMD/auxiliary/TypeTraits.hpp"
24 #include "openPMD/auxiliary/UniquePtr.hpp"
25 
26 #include <array>
27 #include <climits>
28 #include <complex>
29 #include <cstdint>
30 #include <iosfwd>
31 #include <map>
32 #include <memory>
33 #include <stdexcept>
34 #include <string>
35 #include <tuple>
36 #include <type_traits>
37 #include <utility> // std::declval
38 #include <vector>
39 
40 namespace openPMD
41 {
42 
45 enum class Datatype : int
46 {
47  CHAR,
48  UCHAR,
49  SCHAR,
50  SHORT,
51  INT,
52  LONG,
53  LONGLONG,
54  USHORT,
55  UINT,
56  ULONG,
57  ULONGLONG,
58  FLOAT,
59  DOUBLE,
60  LONG_DOUBLE,
61  CFLOAT,
62  CDOUBLE,
63  CLONG_DOUBLE,
64  STRING,
65  VEC_CHAR,
66  VEC_SHORT,
67  VEC_INT,
68  VEC_LONG,
69  VEC_LONGLONG,
70  VEC_UCHAR,
71  VEC_USHORT,
72  VEC_UINT,
73  VEC_ULONG,
74  VEC_ULONGLONG,
75  VEC_FLOAT,
76  VEC_DOUBLE,
77  VEC_LONG_DOUBLE,
78  VEC_CFLOAT,
79  VEC_CDOUBLE,
80  VEC_CLONG_DOUBLE,
81  VEC_SCHAR,
82  VEC_STRING,
83  ARR_DBL_7,
84 
85  BOOL,
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::SCHAR;
135  }
137  {
138  return DT::SHORT;
139  }
141  {
142  return DT::INT;
143  }
145  {
146  return DT::LONG;
147  }
149  {
150  return DT::LONGLONG;
151  }
153  {
154  return DT::USHORT;
155  }
157  {
158  return DT::UINT;
159  }
161  {
162  return DT::ULONG;
163  }
165  {
166  return DT::ULONGLONG;
167  }
169  {
170  return DT::FLOAT;
171  }
173  {
174  return DT::DOUBLE;
175  }
177  {
178  return DT::LONG_DOUBLE;
179  }
180  else if (decay_equiv<T, std::complex<float>>::value)
181  {
182  return DT::CFLOAT;
183  }
184  else if (decay_equiv<T, std::complex<double>>::value)
185  {
186  return DT::CDOUBLE;
187  }
188  else if (decay_equiv<T, std::complex<long double>>::value)
189  {
190  return DT::CLONG_DOUBLE;
191  }
193  {
194  return DT::STRING;
195  }
196  else if (decay_equiv<T, std::vector<char>>::value)
197  {
198  return DT::VEC_CHAR;
199  }
200  else if (decay_equiv<T, std::vector<short>>::value)
201  {
202  return DT::VEC_SHORT;
203  }
204  else if (decay_equiv<T, std::vector<int>>::value)
205  {
206  return DT::VEC_INT;
207  }
208  else if (decay_equiv<T, std::vector<long>>::value)
209  {
210  return DT::VEC_LONG;
211  }
212  else if (decay_equiv<T, std::vector<long long>>::value)
213  {
214  return DT::VEC_LONGLONG;
215  }
216  else if (decay_equiv<T, std::vector<unsigned char>>::value)
217  {
218  return DT::VEC_UCHAR;
219  }
220  else if (decay_equiv<T, std::vector<signed char>>::value)
221  {
222  return DT::VEC_SCHAR;
223  }
224  else if (decay_equiv<T, std::vector<unsigned short>>::value)
225  {
226  return DT::VEC_USHORT;
227  }
228  else if (decay_equiv<T, std::vector<unsigned int>>::value)
229  {
230  return DT::VEC_UINT;
231  }
232  else if (decay_equiv<T, std::vector<unsigned long>>::value)
233  {
234  return DT::VEC_ULONG;
235  }
236  else if (decay_equiv<T, std::vector<unsigned long long>>::value)
237  {
238  return DT::VEC_ULONGLONG;
239  }
240  else if (decay_equiv<T, std::vector<float>>::value)
241  {
242  return DT::VEC_FLOAT;
243  }
244  else if (decay_equiv<T, std::vector<double>>::value)
245  {
246  return DT::VEC_DOUBLE;
247  }
248  else if (decay_equiv<T, std::vector<long double>>::value)
249  {
250  return DT::VEC_LONG_DOUBLE;
251  }
252  else if (decay_equiv<T, std::vector<std::complex<float>>>::value)
253  {
254  return DT::VEC_CFLOAT;
255  }
256  else if (decay_equiv<T, std::vector<std::complex<double>>>::value)
257  {
258  return DT::VEC_CDOUBLE;
259  }
260  else if (decay_equiv<T, std::vector<std::complex<long double>>>::value)
261  {
262  return DT::VEC_CLONG_DOUBLE;
263  }
264  else if (decay_equiv<T, std::vector<std::string>>::value)
265  {
266  return DT::VEC_STRING;
267  }
268  else if (decay_equiv<T, std::array<double, 7>>::value)
269  {
270  return DT::ARR_DBL_7;
271  }
273  {
274  return DT::BOOL;
275  }
276  else
277  return Datatype::UNDEFINED;
278 }
279 
288 template <typename T>
289 inline constexpr Datatype determineDatatype(T &&val)
290 {
291  (void)val; // don't need this, it only has a name for Doxygen
292  using T_stripped = std::remove_cv_t<std::remove_reference_t<T>>;
293  if constexpr (auxiliary::IsPointer_v<T_stripped>)
294  {
295  return determineDatatype<auxiliary::IsPointer_t<T_stripped>>();
296  }
297  else if constexpr (auxiliary::IsContiguousContainer_v<T_stripped>)
298  {
299  static_assert(auxiliary::dependent_false_v<T_stripped>, R"(
300 Error: Passed a contiguous container type to determineDatatype<>().
301 These types are not directly supported due to colliding semantics.
302 Assuming a vector object `std::vector<float> vec;`,
303 use one of the following alternatives:
304 
305 1) If what you want is a direct openPMD::Datatype equivalent
306  of the container type, use:
307  `determineDatatype<decltype(vec)>()`
308  OR
309  `determineDatatype<std::vector<float>>()`.
310  The result will be `Datatype::VECTOR_FLOAT`.
311 2) If what you want is the openPMD::Datatype equivalent of the *contained type*,
312  use the raw pointer overload by:
313  `determineDatatype(vec.data())`
314  The result will be `Datatype::FLOAT`.
315  This is the variant that you likely wish to use if intending to write data
316  from the vector via `storeChunk()`, e.g. `storeChunk(vec, {0}, {10})`.
317  )");
318  }
319  else
320  {
321  static_assert(auxiliary::dependent_false_v<T_stripped>, R"(
322 Error: Unknown datatype passed to determineDatatype<>().
323 For a direct translation from C++ type to the openPMD::Datatype enum, use:
324 `auto determineDatatype<T>() -> Datatype`.
325 
326 For detecting the contained datatpye of a pointer type (shared or raw pointer),
327 use this following template (i.e. `auto determineDatatype<T>(T &&) -> Datatype`)
328 which accepts pointer-type parameters (raw, shared or unique).
329  )");
330  }
331  // Unreachable, but C++ does not know it
332  return Datatype::UNDEFINED;
333 }
334 
340 inline size_t toBytes(Datatype d)
341 {
342  using DT = Datatype;
343  switch (d)
344  {
345  case DT::CHAR:
346  case DT::VEC_CHAR:
347  case DT::STRING:
348  case DT::VEC_STRING:
349  return sizeof(char);
350  case DT::UCHAR:
351  case DT::VEC_UCHAR:
352  return sizeof(unsigned char);
353  case DT::SCHAR:
354  case DT::VEC_SCHAR:
355  return sizeof(signed char);
356  case DT::SHORT:
357  case DT::VEC_SHORT:
358  return sizeof(short);
359  case DT::INT:
360  case DT::VEC_INT:
361  return sizeof(int);
362  case DT::LONG:
363  case DT::VEC_LONG:
364  return sizeof(long);
365  case DT::LONGLONG:
366  case DT::VEC_LONGLONG:
367  return sizeof(long long);
368  case DT::USHORT:
369  case DT::VEC_USHORT:
370  return sizeof(unsigned short);
371  case DT::UINT:
372  case DT::VEC_UINT:
373  return sizeof(unsigned int);
374  case DT::ULONG:
375  case DT::VEC_ULONG:
376  return sizeof(unsigned long);
377  case DT::ULONGLONG:
378  case DT::VEC_ULONGLONG:
379  return sizeof(unsigned long long);
380  case DT::FLOAT:
381  case DT::VEC_FLOAT:
382  return sizeof(float);
383  case DT::DOUBLE:
384  case DT::VEC_DOUBLE:
385  case DT::ARR_DBL_7:
386  return sizeof(double);
387  case DT::LONG_DOUBLE:
388  case DT::VEC_LONG_DOUBLE:
389  return sizeof(long double);
390  case DT::CFLOAT:
391  case DT::VEC_CFLOAT:
392  return sizeof(float) * 2;
393  case DT::CDOUBLE:
394  case DT::VEC_CDOUBLE:
395  return sizeof(double) * 2;
396  case DT::CLONG_DOUBLE:
397  case DT::VEC_CLONG_DOUBLE:
398  return sizeof(long double) * 2;
399  case DT::BOOL:
400  return sizeof(bool);
401  case DT::UNDEFINED:
402  default:
403  throw std::runtime_error("toBytes: Invalid datatype!");
404  }
405 }
406 
412 inline size_t toBits(Datatype d)
413 {
414  return toBytes(d) * CHAR_BIT;
415 }
416 
422 inline bool isVector(Datatype d)
423 {
424  using DT = Datatype;
425 
426  switch (d)
427  {
428  case DT::VEC_CHAR:
429  case DT::VEC_SHORT:
430  case DT::VEC_INT:
431  case DT::VEC_LONG:
432  case DT::VEC_LONGLONG:
433  case DT::VEC_UCHAR:
434  case DT::VEC_USHORT:
435  case DT::VEC_UINT:
436  case DT::VEC_ULONG:
437  case DT::VEC_ULONGLONG:
438  case DT::VEC_FLOAT:
439  case DT::VEC_DOUBLE:
440  case DT::VEC_LONG_DOUBLE:
441  case DT::VEC_CFLOAT:
442  case DT::VEC_CDOUBLE:
443  case DT::VEC_CLONG_DOUBLE:
444  case DT::VEC_STRING:
445  return true;
446  default:
447  return false;
448  }
449 }
450 
458 inline bool isFloatingPoint(Datatype d)
459 {
460  using DT = Datatype;
461 
462  switch (d)
463  {
464  case DT::FLOAT:
465  case DT::VEC_FLOAT:
466  case DT::DOUBLE:
467  case DT::VEC_DOUBLE:
468  case DT::LONG_DOUBLE:
469  case DT::VEC_LONG_DOUBLE:
470  // note: complex floats are not std::is_floating_point
471  return true;
472  default:
473  return false;
474  }
475 }
476 
485 {
486  using DT = Datatype;
487 
488  switch (d)
489  {
490  case DT::CFLOAT:
491  case DT::VEC_CFLOAT:
492  case DT::CDOUBLE:
493  case DT::VEC_CDOUBLE:
494  case DT::CLONG_DOUBLE:
495  case DT::VEC_CLONG_DOUBLE:
496  return true;
497  default:
498  return false;
499  }
500 }
501 
509 template <typename T>
510 inline bool isFloatingPoint()
511 {
512  Datatype dtype = determineDatatype<T>();
513 
514  return isFloatingPoint(dtype);
515 }
516 
524 template <typename T>
526 {
527  Datatype dtype = determineDatatype<T>();
528 
529  return isComplexFloatingPoint(dtype);
530 }
531 
540 inline std::tuple<bool, bool> isInteger(Datatype d)
541 {
542  using DT = Datatype;
543 
544  switch (d)
545  {
546  case DT::SHORT:
547  case DT::VEC_SHORT:
548  case DT::INT:
549  case DT::VEC_INT:
550  case DT::LONG:
551  case DT::VEC_LONG:
552  case DT::LONGLONG:
553  case DT::VEC_LONGLONG:
554  return std::make_tuple(true, true);
555  case DT::USHORT:
556  case DT::VEC_USHORT:
557  case DT::UINT:
558  case DT::VEC_UINT:
559  case DT::ULONG:
560  case DT::VEC_ULONG:
561  case DT::ULONGLONG:
562  case DT::VEC_ULONGLONG:
563  return std::make_tuple(true, false);
564  default:
565  return std::make_tuple(false, false);
566  }
567 }
568 
577 template <typename T>
578 inline std::tuple<bool, bool> isInteger()
579 {
580  Datatype dtype = determineDatatype<T>();
581 
582  return isInteger(dtype);
583 }
584 
591 template <typename T_FP>
593 {
594  // template
595  bool tt_is_fp = isFloatingPoint<T_FP>();
596 
597  // Datatype
598  bool dt_is_fp = isFloatingPoint(d);
599 
600  if (tt_is_fp && dt_is_fp && toBits(d) == toBits(determineDatatype<T_FP>()))
601  return true;
602  else
603  return false;
604 }
605 
613 template <typename T_CFP>
615 {
616  // template
617  bool tt_is_cfp = isComplexFloatingPoint<T_CFP>();
618 
619  // Datatype
620  bool dt_is_cfp = isComplexFloatingPoint(d);
621 
622  if (tt_is_cfp && dt_is_cfp &&
623  toBits(d) == toBits(determineDatatype<T_CFP>()))
624  return true;
625  else
626  return false;
627 }
628 
636 template <typename T_Int>
637 inline bool isSameInteger(Datatype d)
638 {
639  // template
640  bool tt_is_int, tt_is_sig;
641  std::tie(tt_is_int, tt_is_sig) = isInteger<T_Int>();
642 
643  // Datatype
644  bool dt_is_int, dt_is_sig;
645  std::tie(dt_is_int, dt_is_sig) = isInteger(d);
646 
647  if (tt_is_int && dt_is_int && tt_is_sig == dt_is_sig &&
648  toBits(d) == toBits(determineDatatype<T_Int>()))
649  return true;
650  else
651  return false;
652 }
653 
660 inline bool isSame(openPMD::Datatype const d, openPMD::Datatype const e)
661 {
662  // exact same type
663  if (static_cast<int>(d) == static_cast<int>(e))
664  return true;
665 
666  bool d_is_vec = isVector(d);
667  bool e_is_vec = isVector(e);
668 
669  // same int
670  bool d_is_int, d_is_sig;
671  std::tie(d_is_int, d_is_sig) = isInteger(d);
672  bool e_is_int, e_is_sig;
673  std::tie(e_is_int, e_is_sig) = isInteger(e);
674  if (d_is_int && e_is_int && d_is_vec == e_is_vec && d_is_sig == e_is_sig &&
675  toBits(d) == toBits(e))
676  return true;
677 
678  // same float
679  bool d_is_fp = isFloatingPoint(d);
680  bool e_is_fp = isFloatingPoint(e);
681 
682  if (d_is_fp && e_is_fp && d_is_vec == e_is_vec && toBits(d) == toBits(e))
683  return true;
684 
685  // same complex floating point
686  bool d_is_cfp = isComplexFloatingPoint(d);
687  bool e_is_cfp = isComplexFloatingPoint(e);
688 
689  if (d_is_cfp && e_is_cfp && d_is_vec == e_is_vec && toBits(d) == toBits(e))
690  return true;
691 
692  return false;
693 }
694 
702 
703 Datatype toVectorType(Datatype dt);
704 
705 std::string datatypeToString(Datatype dt);
706 
707 Datatype stringToDatatype(std::string s);
708 
709 void warnWrongDtype(std::string const &key, Datatype store, Datatype request);
710 
711 std::ostream &operator<<(std::ostream &, openPMD::Datatype const &);
712 
713 } // namespace openPMD
714 
715 #if !defined(_MSC_VER)
716 
728 inline bool operator==(openPMD::Datatype d, openPMD::Datatype e)
729 {
730  return openPMD::isSame(d, e);
731 }
732 
733 inline bool operator!=(openPMD::Datatype d, openPMD::Datatype e)
734 {
735  return !(d == e);
736 }
739 #endif
bool isVector(Datatype d)
Compare if a Datatype is a vector type.
Definition: Datatype.hpp:422
std::vector< Datatype > openPMD_Datatypes
All openPMD datatypes defined in Datatype, listed in order in a vector.
Definition: Datatype.cpp:227
bool isSameFloatingPoint(Datatype d)
Compare if a Datatype is equivalent to a floating point type.
Definition: Datatype.hpp:592
bool isSameComplexFloatingPoint(Datatype d)
Compare if a Datatype is equivalent to a complex floating point type.
Definition: Datatype.hpp:614
bool isSameInteger(Datatype d)
Compare if a Datatype is equivalent to an integer type.
Definition: Datatype.hpp:637
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:484
Datatype
Concrete datatype of an object available at runtime.
Definition: Datatype.hpp:45
size_t toBits(Datatype d)
Return number of bits representing a Datatype.
Definition: Datatype.hpp:412
Public definitions of openPMD-api.
Datatype basicDatatype(Datatype dt)
basicDatatype Strip openPMD Datatype of std::vector, std::array et.
Definition: Datatype.cpp:286
size_t toBytes(Datatype d)
Return number of bytes representing a Datatype.
Definition: Datatype.hpp:340
bool isFloatingPoint(Datatype d)
Compare if a Datatype is a floating point type.
Definition: Datatype.hpp:458
std::tuple< bool, bool > isInteger(Datatype d)
Compare if a Datatype is an integer type.
Definition: Datatype.hpp:540
bool isSame(openPMD::Datatype const d, openPMD::Datatype const e)
Comparison for two Datatypes.
Definition: Datatype.hpp:660