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, UCHAR, // SCHAR,
48  SHORT, INT, LONG, LONGLONG,
49  USHORT, UINT, ULONG, ULONGLONG,
50  FLOAT, DOUBLE, LONG_DOUBLE,
51  CFLOAT, CDOUBLE, CLONG_DOUBLE,
52  STRING,
53  VEC_CHAR,
54  VEC_SHORT,
55  VEC_INT,
56  VEC_LONG,
57  VEC_LONGLONG,
58  VEC_UCHAR,
59  VEC_USHORT,
60  VEC_UINT,
61  VEC_ULONG,
62  VEC_ULONGLONG,
63  VEC_FLOAT,
64  VEC_DOUBLE,
65  VEC_LONG_DOUBLE,
66  VEC_CFLOAT,
67  VEC_CDOUBLE,
68  VEC_CLONG_DOUBLE,
69  VEC_STRING,
70  ARR_DBL_7,
71 
72  BOOL,
73 
74  DATATYPE = HIGHEST_DATATYPE,
75 
76  UNDEFINED
77 }; // Datatype
78 
84 extern std::vector< Datatype > openPMD_Datatypes;
85 
95 template<
96  typename T,
97  typename U
98 >
99 struct decay_equiv :
100  std::is_same<
101  typename std::remove_pointer<
102  typename std::remove_cv<
103  typename std::decay<
104  typename std::remove_all_extents< T >::type
105  >::type
106  >::type
107  >::type,
108  typename std::remove_pointer<
109  typename std::remove_cv<
110  typename std::decay<
111  typename std::remove_all_extents< U >::type
112  >::type
113  >::type
114  >::type
115  >::type
116 { };
117 
118 template<
119  typename T,
120  typename U
121 >
122 constexpr bool decay_equiv_v = decay_equiv< T, U >::value;
123 
124 template< typename T >
125 inline
126 constexpr
127 Datatype
128 determineDatatype()
129 {
130  using DT = Datatype;
131  if( decay_equiv< T, char >::value ){ return DT::CHAR; }
132  else if( decay_equiv< T, unsigned char >::value ){ return DT::UCHAR; }
133  else if( decay_equiv< T, short >::value ){ return DT::SHORT; }
134  else if( decay_equiv< T, int >::value ){ return DT::INT; }
135  else if( decay_equiv< T, long >::value ){ return DT::LONG; }
136  else if( decay_equiv< T, long long >::value ){ return DT::LONGLONG; }
137  else if( decay_equiv< T, unsigned short >::value ){ return DT::USHORT; }
138  else if( decay_equiv< T, unsigned int >::value ){ return DT::UINT; }
139  else if( decay_equiv< T, unsigned long >::value ){ return DT::ULONG; }
140  else if( decay_equiv< T, unsigned long long >::value ){ return DT::ULONGLONG; }
141  else if( decay_equiv< T, float >::value ){ return DT::FLOAT; }
142  else if( decay_equiv< T, double >::value ){ return DT::DOUBLE; }
143  else if( decay_equiv< T, long double >::value ){ return DT::LONG_DOUBLE; }
144  else if( decay_equiv< T, std::complex< float > >::value ){ return DT::CFLOAT; }
145  else if( decay_equiv< T, std::complex< double > >::value ){ return DT::CDOUBLE; }
146  else if( decay_equiv< T, std::complex< long double > >::value ){ return DT::CLONG_DOUBLE; }
147  else if( decay_equiv< T, std::string >::value ){ return DT::STRING; }
148  else if( decay_equiv< T, std::vector< char > >::value ){ return DT::VEC_CHAR; }
149  else if( decay_equiv< T, std::vector< short > >::value ){ return DT::VEC_SHORT; }
150  else if( decay_equiv< T, std::vector< int > >::value ){ return DT::VEC_INT; }
151  else if( decay_equiv< T, std::vector< long > >::value ){ return DT::VEC_LONG; }
152  else if( decay_equiv< T, std::vector< long long > >::value ){ return DT::VEC_LONGLONG; }
153  else if( decay_equiv< T, std::vector< unsigned char > >::value ){ return DT::VEC_UCHAR; }
154  else if( decay_equiv< T, std::vector< unsigned short > >::value ){ return DT::VEC_USHORT; }
155  else if( decay_equiv< T, std::vector< unsigned int > >::value ){ return DT::VEC_UINT; }
156  else if( decay_equiv< T, std::vector< unsigned long > >::value ){ return DT::VEC_ULONG; }
157  else if( decay_equiv< T, std::vector< unsigned long long > >::value ){ return DT::VEC_ULONGLONG; }
158  else if( decay_equiv< T, std::vector< float > >::value ){ return DT::VEC_FLOAT; }
159  else if( decay_equiv< T, std::vector< double > >::value ){ return DT::VEC_DOUBLE; }
160  else if( decay_equiv< T, std::vector< long double > >::value ){ return DT::VEC_LONG_DOUBLE; }
161  else if( decay_equiv< T, std::vector< std::complex< float > > >::value ){ return DT::VEC_CFLOAT; }
162  else if( decay_equiv< T, std::vector< std::complex< double > > >::value ){ return DT::VEC_CDOUBLE; }
163  else if( decay_equiv< T, std::vector< std::complex< long double > > >::value ){ return DT::VEC_CLONG_DOUBLE; }
164  else if( decay_equiv< T, std::vector< std::string > >::value ){ return DT::VEC_STRING; }
165  else if( decay_equiv< T, std::array< double, 7 > >::value ){ return DT::ARR_DBL_7; }
166  else if( decay_equiv< T, bool >::value ){ return DT::BOOL; }
167  else return Datatype::UNDEFINED;
168 }
169 
170 template< typename T >
171 inline
172 constexpr
173 Datatype
174 determineDatatype(std::shared_ptr< T >)
175 {
176  using DT = Datatype;
177  if( decay_equiv< T, char >::value ){ return DT::CHAR; }
178  else if( decay_equiv< T, unsigned char >::value ){ return DT::UCHAR; }
179  else if( decay_equiv< T, short >::value ){ return DT::SHORT; }
180  else if( decay_equiv< T, int >::value ){ return DT::INT; }
181  else if( decay_equiv< T, long >::value ){ return DT::LONG; }
182  else if( decay_equiv< T, long long >::value ){ return DT::LONGLONG; }
183  else if( decay_equiv< T, unsigned short >::value ){ return DT::USHORT; }
184  else if( decay_equiv< T, unsigned int >::value ){ return DT::UINT; }
185  else if( decay_equiv< T, unsigned long >::value ){ return DT::ULONG; }
186  else if( decay_equiv< T, unsigned long long >::value ){ return DT::ULONGLONG; }
187  else if( decay_equiv< T, float >::value ){ return DT::FLOAT; }
188  else if( decay_equiv< T, double >::value ){ return DT::DOUBLE; }
189  else if( decay_equiv< T, long double >::value ){ return DT::LONG_DOUBLE; }
190  else if( decay_equiv< T, std::complex< float > >::value ){ return DT::CFLOAT; }
191  else if( decay_equiv< T, std::complex< double > >::value ){ return DT::CDOUBLE; }
192  else if( decay_equiv< T, std::complex< long double > >::value ){ return DT::CLONG_DOUBLE; }
193  else if( decay_equiv< T, std::string >::value ){ return DT::STRING; }
194  else if( decay_equiv< T, std::vector< char > >::value ){ return DT::VEC_CHAR; }
195  else if( decay_equiv< T, std::vector< short > >::value ){ return DT::VEC_SHORT; }
196  else if( decay_equiv< T, std::vector< int > >::value ){ return DT::VEC_INT; }
197  else if( decay_equiv< T, std::vector< long > >::value ){ return DT::VEC_LONG; }
198  else if( decay_equiv< T, std::vector< long long > >::value ){ return DT::VEC_LONGLONG; }
199  else if( decay_equiv< T, std::vector< unsigned char > >::value ){ return DT::VEC_UCHAR; }
200  else if( decay_equiv< T, std::vector< unsigned short > >::value ){ return DT::VEC_USHORT; }
201  else if( decay_equiv< T, std::vector< unsigned int > >::value ){ return DT::VEC_UINT; }
202  else if( decay_equiv< T, std::vector< unsigned long > >::value ){ return DT::VEC_ULONG; }
203  else if( decay_equiv< T, std::vector< unsigned long long > >::value ){ return DT::VEC_ULONGLONG; }
204  else if( decay_equiv< T, std::vector< float > >::value ){ return DT::VEC_FLOAT; }
205  else if( decay_equiv< T, std::vector< double > >::value ){ return DT::VEC_DOUBLE; }
206  else if( decay_equiv< T, std::vector< long double > >::value ){ return DT::VEC_LONG_DOUBLE; }
207  else if( decay_equiv< T, std::vector< std::complex< float > > >::value ){ return DT::VEC_CFLOAT; }
208  else if( decay_equiv< T, std::vector< std::complex< double > > >::value ){ return DT::VEC_CDOUBLE; }
209  else if( decay_equiv< T, std::vector< std::complex< long double > > >::value ){ return DT::VEC_CLONG_DOUBLE; }
210  else if( decay_equiv< T, std::vector< std::string > >::value ){ return DT::VEC_STRING; }
211  else if( decay_equiv< T, std::array< double, 7 > >::value ){ return DT::ARR_DBL_7; }
212  else if( decay_equiv< T, bool >::value ){ return DT::BOOL; }
213  else return DT::UNDEFINED;
214 }
215 
221 inline size_t
223 {
224  using DT = Datatype;
225  switch( d )
226  {
227  case DT::CHAR:
228  case DT::VEC_CHAR:
229  case DT::STRING:
230  case DT::VEC_STRING:
231  return sizeof(char);
232  case DT::UCHAR:
233  case DT::VEC_UCHAR:
234  return sizeof(unsigned char);
235  // case DT::SCHAR:
236  // case DT::VEC_SCHAR:
237  // return sizeof(signed char);
238  case DT::SHORT:
239  case DT::VEC_SHORT:
240  return sizeof(short);
241  case DT::INT:
242  case DT::VEC_INT:
243  return sizeof(int);
244  case DT::LONG:
245  case DT::VEC_LONG:
246  return sizeof(long);
247  case DT::LONGLONG:
248  case DT::VEC_LONGLONG:
249  return sizeof(long long);
250  case DT::USHORT:
251  case DT::VEC_USHORT:
252  return sizeof(unsigned short);
253  case DT::UINT:
254  case DT::VEC_UINT:
255  return sizeof(unsigned int);
256  case DT::ULONG:
257  case DT::VEC_ULONG:
258  return sizeof(unsigned long);
259  case DT::ULONGLONG:
260  case DT::VEC_ULONGLONG:
261  return sizeof(unsigned long long);
262  case DT::FLOAT:
263  case DT::VEC_FLOAT:
264  return sizeof(float);
265  case DT::DOUBLE:
266  case DT::VEC_DOUBLE:
267  case DT::ARR_DBL_7:
268  return sizeof(double);
269  case DT::LONG_DOUBLE:
270  case DT::VEC_LONG_DOUBLE:
271  return sizeof(long double);
272  case DT::CFLOAT:
273  case DT::VEC_CFLOAT:
274  return sizeof(float) * 2;
275  case DT::CDOUBLE:
276  case DT::VEC_CDOUBLE:
277  return sizeof(double) * 2;
278  case DT::CLONG_DOUBLE:
279  case DT::VEC_CLONG_DOUBLE:
280  return sizeof(long double) * 2;
281  case DT::BOOL:
282  return sizeof(bool);
283  case DT::DATATYPE:
284  case DT::UNDEFINED:
285  default:
286  throw std::runtime_error("toBytes: Invalid datatype!");
287  }
288 }
289 
295 inline size_t
297 {
298  return toBytes( d ) * CHAR_BIT;
299 }
300 
306 inline bool
308 {
309  using DT = Datatype;
310 
311  switch( d )
312  {
313  case DT::VEC_CHAR:
314  case DT::VEC_SHORT:
315  case DT::VEC_INT:
316  case DT::VEC_LONG:
317  case DT::VEC_LONGLONG:
318  case DT::VEC_UCHAR:
319  case DT::VEC_USHORT:
320  case DT::VEC_UINT:
321  case DT::VEC_ULONG:
322  case DT::VEC_ULONGLONG:
323  case DT::VEC_FLOAT:
324  case DT::VEC_DOUBLE:
325  case DT::VEC_LONG_DOUBLE:
326  case DT::VEC_CFLOAT:
327  case DT::VEC_CDOUBLE:
328  case DT::VEC_CLONG_DOUBLE:
329  case DT::VEC_STRING:
330  return true;
331  default:
332  return false;
333  }
334 }
335 
343 inline bool
345 {
346  using DT = Datatype;
347 
348  switch( d )
349  {
350  case DT::FLOAT:
351  case DT::VEC_FLOAT:
352  case DT::DOUBLE:
353  case DT::VEC_DOUBLE:
354  case DT::LONG_DOUBLE:
355  case DT::VEC_LONG_DOUBLE:
356  // note: complex floats are not std::is_floating_point
357  return true;
358  default:
359  return false;
360  }
361 }
362 
370 inline bool
372 {
373  using DT = Datatype;
374 
375  switch( d )
376  {
377  case DT::CFLOAT:
378  case DT::VEC_CFLOAT:
379  case DT::CDOUBLE:
380  case DT::VEC_CDOUBLE:
381  case DT::CLONG_DOUBLE:
382  case DT::VEC_CLONG_DOUBLE:
383  return true;
384  default:
385  return false;
386  }
387 }
388 
396 template< typename T >
397 inline bool
399 {
400  Datatype dtype = determineDatatype< T >();
401 
402  return isFloatingPoint( dtype );
403 }
404 
412 template< typename T >
413 inline bool
415 {
416  Datatype dtype = determineDatatype< T >();
417 
418  return isComplexFloatingPoint(dtype);
419 }
420 
429 inline std::tuple< bool, bool >
431 {
432  using DT = Datatype;
433 
434  switch( d )
435  {
436  case DT::SHORT:
437  case DT::VEC_SHORT:
438  case DT::INT:
439  case DT::VEC_INT:
440  case DT::LONG:
441  case DT::VEC_LONG:
442  case DT::LONGLONG:
443  case DT::VEC_LONGLONG:
444  return std::make_tuple( true, true );
445  case DT::USHORT:
446  case DT::VEC_USHORT:
447  case DT::UINT:
448  case DT::VEC_UINT:
449  case DT::ULONG:
450  case DT::VEC_ULONG:
451  case DT::ULONGLONG:
452  case DT::VEC_ULONGLONG:
453  return std::make_tuple( true, false );
454  default:
455  return std::make_tuple( false, false );
456  }
457 }
458 
467 template< typename T >
468 inline std::tuple< bool, bool >
470 {
471  Datatype dtype = determineDatatype< T >();
472 
473  return isInteger( dtype );
474 }
475 
482 template< typename T_FP >
483 inline bool
485 {
486  // template
487  bool tt_is_fp = isFloatingPoint< T_FP >();
488 
489  // Datatype
490  bool dt_is_fp = isFloatingPoint( d );
491 
492  if(
493  tt_is_fp &&
494  dt_is_fp &&
495  toBits( d ) == toBits( determineDatatype< T_FP >() )
496  )
497  return true;
498  else
499  return false;
500 }
501 
508 template< typename T_CFP >
509 inline bool
511 {
512  // template
513  bool tt_is_cfp = isComplexFloatingPoint< T_CFP >();
514 
515  // Datatype
516  bool dt_is_cfp = isComplexFloatingPoint( d );
517 
518  if(
519  tt_is_cfp &&
520  dt_is_cfp &&
521  toBits( d ) == toBits( determineDatatype< T_CFP >() )
522  )
523  return true;
524  else
525  return false;
526 }
527 
534 template< typename T_Int >
535 inline bool
537 {
538  // template
539  bool tt_is_int, tt_is_sig;
540  std::tie(tt_is_int, tt_is_sig) = isInteger< T_Int >();
541 
542  // Datatype
543  bool dt_is_int, dt_is_sig;
544  std::tie(dt_is_int, dt_is_sig) = isInteger( d );
545 
546  if(
547  tt_is_int &&
548  dt_is_int &&
549  tt_is_sig == dt_is_sig &&
550  toBits( d ) == toBits( determineDatatype< T_Int >() )
551  )
552  return true;
553  else
554  return false;
555 }
556 
563 inline bool
565 {
566  // exact same type
567  if( static_cast<int>(d) == static_cast<int>(e) )
568  return true;
569 
570  bool d_is_vec = isVector( d );
571  bool e_is_vec = isVector( e );
572 
573  // same int
574  bool d_is_int, d_is_sig;
575  std::tie(d_is_int, d_is_sig) = isInteger( d );
576  bool e_is_int, e_is_sig;
577  std::tie(e_is_int, e_is_sig) = isInteger( e );
578  if(
579  d_is_int &&
580  e_is_int &&
581  d_is_vec == e_is_vec &&
582  d_is_sig == e_is_sig &&
583  toBits( d ) == toBits( e )
584  )
585  return true;
586 
587  // same float
588  bool d_is_fp = isFloatingPoint( d );
589  bool e_is_fp = isFloatingPoint( e );
590 
591  if(
592  d_is_fp &&
593  e_is_fp &&
594  d_is_vec == e_is_vec &&
595  toBits( d ) == toBits( e )
596  )
597  return true;
598 
599  // same complex floating point
600  bool d_is_cfp = isComplexFloatingPoint(d);
601  bool e_is_cfp = isComplexFloatingPoint(e);
602 
603  if(
604  d_is_cfp &&
605  e_is_cfp &&
606  d_is_vec == e_is_vec &&
607  toBits( d ) == toBits( e )
608  )
609  return true;
610 
611  return false;
612 }
613 
614 namespace detail {
615  template<typename T>
617  Datatype m_dt = determineDatatype<T>();
618  };
619 
620  template<typename T>
621  struct BasicDatatypeHelper<std::vector<T>> {
622  Datatype m_dt = BasicDatatypeHelper<T>{}.m_dt;
623  };
624 
625  template<typename T, std::size_t n>
626  struct BasicDatatypeHelper<std::array<T, n>> {
627  Datatype m_dt = BasicDatatypeHelper<T>{}.m_dt;
628  };
629 
630  struct BasicDatatype {
631  template <typename T>
632  Datatype operator()();
633 
634  template <int n>
635  Datatype operator()();
636  };
637 }
638 
645 
646 Datatype toVectorType(Datatype dt);
647 
648 std::string datatypeToString( Datatype dt );
649 
650 Datatype stringToDatatype( std::string s );
651 
652 void
653 warnWrongDtype(std::string const& key,
654  Datatype store,
655  Datatype request);
656 
657 std::ostream&
658 operator<<(std::ostream&, openPMD::Datatype const&);
659 
660 } // namespace openPMD
661 
662 #if !defined(_MSC_VER)
663 
675 inline bool
676 operator==( openPMD::Datatype d, openPMD::Datatype e )
677 {
678  return openPMD::isSame(d, e);
679 }
680 
681 inline bool
682 operator!=( openPMD::Datatype d, openPMD::Datatype e )
683 {
684  return !(d == e);
685 }
688 #endif
openPMD::isVector
bool isVector(Datatype d)
Compare if a Datatype is a vector type.
Definition: Datatype.hpp:307
openPMD::isSameInteger
bool isSameInteger(Datatype d)
Compare if a Datatype is equivalent to an integer type.
Definition: Datatype.hpp:536
openPMD::Datatype
Datatype
Concrete datatype of an object available at runtime.
Definition: Datatype.hpp:45
openPMD::isSame
bool isSame(openPMD::Datatype const d, openPMD::Datatype const e)
Comparison for two Datatypes.
Definition: Datatype.hpp:564
openPMD::openPMD_Datatypes
std::vector< Datatype > openPMD_Datatypes
All openPMD datatypes defined in Datatype, listed in order in a vector.
Definition: Datatype.cpp:346
openPMD::isSameComplexFloatingPoint
bool isSameComplexFloatingPoint(Datatype d)
Compare if a Datatype is equivalent to a complex floating point type.
Definition: Datatype.hpp:510
openPMD::toBytes
size_t toBytes(Datatype d)
Return number of bytes representing a Datatype.
Definition: Datatype.hpp:222
openPMD::toBits
size_t toBits(Datatype d)
Return number of bits representing a Datatype.
Definition: Datatype.hpp:296
openPMD::decay_equiv
Fundamental equivalence check for two given types T and U.
Definition: Datatype.hpp:99
openPMD::UnitDimension::T
@ T
time
openPMD::basicDatatype
Datatype basicDatatype(Datatype dt)
basicDatatype Strip openPMD Datatype of std::vector, std::array et.
Definition: Datatype.cpp:388
openPMD
Public definitions of openPMD-api.
Definition: Date.cpp:29
openPMD::isComplexFloatingPoint
bool isComplexFloatingPoint(Datatype d)
Compare if a Datatype is a complex floating point type.
Definition: Datatype.hpp:371
openPMD::detail::BasicDatatype
Definition: Datatype.hpp:630
openPMD::detail::BasicDatatypeHelper
Definition: Datatype.hpp:616
openPMD::isSameFloatingPoint
bool isSameFloatingPoint(Datatype d)
Compare if a Datatype is equivalent to a floating point type.
Definition: Datatype.hpp:484
openPMD::isInteger
std::tuple< bool, bool > isInteger(Datatype d)
Compare if a Datatype is an integer type.
Definition: Datatype.hpp:430
openPMD::isFloatingPoint
bool isFloatingPoint(Datatype d)
Compare if a Datatype is a floating point type.
Definition: Datatype.hpp:344