openPMD-api
 
Loading...
Searching...
No Matches
Datatype.hpp
1/* Copyright 2017-2025 Fabian Koller, Franz Poeschel, Axel Huebl, Luca Fedeli
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// comment to prevent clang-format from moving this #include up
27// datatype macros may be included and un-included in other headers
28#include "openPMD/DatatypeMacros.hpp"
29
30#include <array>
31#include <climits>
32#include <complex>
33#include <cstdint>
34#include <iosfwd>
35#include <map>
36#include <memory>
37#include <stdexcept>
38#include <string>
39#include <tuple>
40#include <type_traits>
41#include <utility> // std::declval
42#include <variant>
43#include <vector>
44
45namespace openPMD
46{
47
50enum class Datatype : int
51{
52 CHAR,
53 UCHAR,
54 SCHAR,
55 SHORT,
56 INT,
57 LONG,
58 LONGLONG,
59 USHORT,
60 UINT,
61 ULONG,
62 ULONGLONG,
63 FLOAT,
64 DOUBLE,
65 LONG_DOUBLE,
66 CFLOAT,
67 CDOUBLE,
68 CLONG_DOUBLE,
69 STRING,
70 VEC_CHAR,
71 VEC_SHORT,
72 VEC_INT,
73 VEC_LONG,
74 VEC_LONGLONG,
75 VEC_UCHAR,
76 VEC_USHORT,
77 VEC_UINT,
78 VEC_ULONG,
79 VEC_ULONGLONG,
80 VEC_FLOAT,
81 VEC_DOUBLE,
82 VEC_LONG_DOUBLE,
83 VEC_CFLOAT,
84 VEC_CDOUBLE,
85 VEC_CLONG_DOUBLE,
86 VEC_SCHAR,
87 VEC_STRING,
88 ARR_DBL_7,
89
90 BOOL,
91
92 UNDEFINED
93}; // Datatype
94
100std::vector<Datatype> openPMD_Datatypes();
101
111template <typename T, typename U>
113 : std::is_same<
114 typename std::remove_pointer<typename std::remove_cv<
115 typename std::decay<typename std::remove_all_extents<T>::type>::
116 type>::type>::type,
117 typename std::remove_pointer<typename std::remove_cv<
118 typename std::decay<typename std::remove_all_extents<U>::type>::
119 type>::type>::type>::type
120{};
121
122template <typename T, typename U>
123constexpr bool decay_equiv_v = decay_equiv<T, U>::value;
124
125template <typename T>
126inline constexpr Datatype determineDatatype()
127{
128 using DT = Datatype;
130 {
131 return DT::CHAR;
132 }
133 else if (decay_equiv<T, unsigned char>::value)
134 {
135 return DT::UCHAR;
136 }
138 {
139 return DT::SCHAR;
140 }
142 {
143 return DT::SHORT;
144 }
146 {
147 return DT::INT;
148 }
150 {
151 return DT::LONG;
152 }
154 {
155 return DT::LONGLONG;
156 }
158 {
159 return DT::USHORT;
160 }
162 {
163 return DT::UINT;
164 }
166 {
167 return DT::ULONG;
168 }
170 {
171 return DT::ULONGLONG;
172 }
174 {
175 return DT::FLOAT;
176 }
178 {
179 return DT::DOUBLE;
180 }
182 {
183 return DT::LONG_DOUBLE;
184 }
185 else if (decay_equiv<T, std::complex<float>>::value)
186 {
187 return DT::CFLOAT;
188 }
189 else if (decay_equiv<T, std::complex<double>>::value)
190 {
191 return DT::CDOUBLE;
192 }
193 else if (decay_equiv<T, std::complex<long double>>::value)
194 {
195 return DT::CLONG_DOUBLE;
196 }
198 {
199 return DT::STRING;
200 }
201 else if (decay_equiv<T, std::vector<char>>::value)
202 {
203 return DT::VEC_CHAR;
204 }
205 else if (decay_equiv<T, std::vector<short>>::value)
206 {
207 return DT::VEC_SHORT;
208 }
209 else if (decay_equiv<T, std::vector<int>>::value)
210 {
211 return DT::VEC_INT;
212 }
213 else if (decay_equiv<T, std::vector<long>>::value)
214 {
215 return DT::VEC_LONG;
216 }
217 else if (decay_equiv<T, std::vector<long long>>::value)
218 {
219 return DT::VEC_LONGLONG;
220 }
221 else if (decay_equiv<T, std::vector<unsigned char>>::value)
222 {
223 return DT::VEC_UCHAR;
224 }
225 else if (decay_equiv<T, std::vector<signed char>>::value)
226 {
227 return DT::VEC_SCHAR;
228 }
229 else if (decay_equiv<T, std::vector<unsigned short>>::value)
230 {
231 return DT::VEC_USHORT;
232 }
233 else if (decay_equiv<T, std::vector<unsigned int>>::value)
234 {
235 return DT::VEC_UINT;
236 }
237 else if (decay_equiv<T, std::vector<unsigned long>>::value)
238 {
239 return DT::VEC_ULONG;
240 }
241 else if (decay_equiv<T, std::vector<unsigned long long>>::value)
242 {
243 return DT::VEC_ULONGLONG;
244 }
245 else if (decay_equiv<T, std::vector<float>>::value)
246 {
247 return DT::VEC_FLOAT;
248 }
249 else if (decay_equiv<T, std::vector<double>>::value)
250 {
251 return DT::VEC_DOUBLE;
252 }
253 else if (decay_equiv<T, std::vector<long double>>::value)
254 {
255 return DT::VEC_LONG_DOUBLE;
256 }
257 else if (decay_equiv<T, std::vector<std::complex<float>>>::value)
258 {
259 return DT::VEC_CFLOAT;
260 }
261 else if (decay_equiv<T, std::vector<std::complex<double>>>::value)
262 {
263 return DT::VEC_CDOUBLE;
264 }
265 else if (decay_equiv<T, std::vector<std::complex<long double>>>::value)
266 {
267 return DT::VEC_CLONG_DOUBLE;
268 }
269 else if (decay_equiv<T, std::vector<std::string>>::value)
270 {
271 return DT::VEC_STRING;
272 }
273 else if (decay_equiv<T, std::array<double, 7>>::value)
274 {
275 return DT::ARR_DBL_7;
276 }
278 {
279 return DT::BOOL;
280 }
281 else
282 return Datatype::UNDEFINED;
283}
284
293template <typename T>
294inline constexpr Datatype determineDatatype(T &&val)
295{
296 (void)val; // don't need this, it only has a name for Doxygen
297 using T_stripped = std::remove_cv_t<std::remove_reference_t<T>>;
298 if constexpr (auxiliary::IsPointer_v<T_stripped>)
299 {
300 return determineDatatype<auxiliary::IsPointer_t<T_stripped>>();
301 }
302 else if constexpr (auxiliary::IsContiguousContainer_v<T_stripped>)
303 {
304 static_assert(auxiliary::dependent_false_v<T_stripped>, R"(
305Error: Passed a contiguous container type to determineDatatype<>().
306These types are not directly supported due to colliding semantics.
307Assuming a vector object `std::vector<float> vec;`,
308use one of the following alternatives:
309
3101) If what you want is a direct openPMD::Datatype equivalent
311 of the container type, use:
312 `determineDatatype<decltype(vec)>()`
313 OR
314 `determineDatatype<std::vector<float>>()`.
315 The result will be `Datatype::VECTOR_FLOAT`.
3162) If what you want is the openPMD::Datatype equivalent of the *contained type*,
317 use the raw pointer overload by:
318 `determineDatatype(vec.data())`
319 The result will be `Datatype::FLOAT`.
320 This is the variant that you likely wish to use if intending to write data
321 from the vector via `storeChunk()`, e.g. `storeChunk(vec, {0}, {10})`.
322 )");
323 }
324 else
325 {
326 static_assert(auxiliary::dependent_false_v<T_stripped>, R"(
327Error: Unknown datatype passed to determineDatatype<>().
328For a direct translation from C++ type to the openPMD::Datatype enum, use:
329`auto determineDatatype<T>() -> Datatype`.
330
331For detecting the contained datatpye of a pointer type (shared or raw pointer),
332use this following template (i.e. `auto determineDatatype<T>(T &&) -> Datatype`)
333which accepts pointer-type parameters (raw, shared or unique).
334 )");
335 }
336 // Unreachable, but C++ does not know it
337 return Datatype::UNDEFINED;
338}
339
345inline size_t toBytes(Datatype d)
346{
347 using DT = Datatype;
348 switch (d)
349 {
350 case DT::CHAR:
351 case DT::VEC_CHAR:
352 case DT::STRING:
353 case DT::VEC_STRING:
354 return sizeof(char);
355 case DT::UCHAR:
356 case DT::VEC_UCHAR:
357 return sizeof(unsigned char);
358 case DT::SCHAR:
359 case DT::VEC_SCHAR:
360 return sizeof(signed char);
361 case DT::SHORT:
362 case DT::VEC_SHORT:
363 return sizeof(short);
364 case DT::INT:
365 case DT::VEC_INT:
366 return sizeof(int);
367 case DT::LONG:
368 case DT::VEC_LONG:
369 return sizeof(long);
370 case DT::LONGLONG:
371 case DT::VEC_LONGLONG:
372 return sizeof(long long);
373 case DT::USHORT:
374 case DT::VEC_USHORT:
375 return sizeof(unsigned short);
376 case DT::UINT:
377 case DT::VEC_UINT:
378 return sizeof(unsigned int);
379 case DT::ULONG:
380 case DT::VEC_ULONG:
381 return sizeof(unsigned long);
382 case DT::ULONGLONG:
383 case DT::VEC_ULONGLONG:
384 return sizeof(unsigned long long);
385 case DT::FLOAT:
386 case DT::VEC_FLOAT:
387 return sizeof(float);
388 case DT::DOUBLE:
389 case DT::VEC_DOUBLE:
390 case DT::ARR_DBL_7:
391 return sizeof(double);
392 case DT::LONG_DOUBLE:
393 case DT::VEC_LONG_DOUBLE:
394 return sizeof(long double);
395 case DT::CFLOAT:
396 case DT::VEC_CFLOAT:
397 return sizeof(float) * 2;
398 case DT::CDOUBLE:
399 case DT::VEC_CDOUBLE:
400 return sizeof(double) * 2;
401 case DT::CLONG_DOUBLE:
402 case DT::VEC_CLONG_DOUBLE:
403 return sizeof(long double) * 2;
404 case DT::BOOL:
405 return sizeof(bool);
406 case DT::UNDEFINED:
407 default:
408 throw std::runtime_error("toBytes: Invalid datatype!");
409 }
410}
411
417inline size_t toBits(Datatype d)
418{
419 return toBytes(d) * CHAR_BIT;
420}
421
427constexpr inline bool isVector(Datatype d)
428{
429 using DT = Datatype;
430
431 switch (d)
432 {
433 case DT::VEC_CHAR:
434 case DT::VEC_SHORT:
435 case DT::VEC_INT:
436 case DT::VEC_LONG:
437 case DT::VEC_LONGLONG:
438 case DT::VEC_UCHAR:
439 case DT::VEC_USHORT:
440 case DT::VEC_UINT:
441 case DT::VEC_ULONG:
442 case DT::VEC_ULONGLONG:
443 case DT::VEC_FLOAT:
444 case DT::VEC_DOUBLE:
445 case DT::VEC_LONG_DOUBLE:
446 case DT::VEC_CFLOAT:
447 case DT::VEC_CDOUBLE:
448 case DT::VEC_CLONG_DOUBLE:
449 case DT::VEC_STRING:
450 return true;
451 default:
452 return false;
453 }
454}
455
464{
465 using DT = Datatype;
466
467 switch (d)
468 {
469 case DT::FLOAT:
470 case DT::VEC_FLOAT:
471 case DT::DOUBLE:
472 case DT::VEC_DOUBLE:
473 case DT::LONG_DOUBLE:
474 case DT::VEC_LONG_DOUBLE:
475 // note: complex floats are not std::is_floating_point
476 return true;
477 default:
478 return false;
479 }
480}
481
489constexpr inline bool isComplexFloatingPoint(Datatype d)
490{
491 using DT = Datatype;
492
493 switch (d)
494 {
495 case DT::CFLOAT:
496 case DT::VEC_CFLOAT:
497 case DT::CDOUBLE:
498 case DT::VEC_CDOUBLE:
499 case DT::CLONG_DOUBLE:
500 case DT::VEC_CLONG_DOUBLE:
501 return true;
502 default:
503 return false;
504 }
505}
506
514template <typename T>
515inline bool isFloatingPoint()
516{
517 Datatype dtype = determineDatatype<T>();
518
519 return isFloatingPoint(dtype);
520}
521
529template <typename T>
530constexpr inline bool isComplexFloatingPoint()
531{
532 Datatype dtype = determineDatatype<T>();
533
534 return isComplexFloatingPoint(dtype);
535}
536
545inline std::tuple<bool, bool> isInteger(Datatype d)
546{
547 using DT = Datatype;
548
549 switch (d)
550 {
551 case DT::SHORT:
552 case DT::VEC_SHORT:
553 case DT::INT:
554 case DT::VEC_INT:
555 case DT::LONG:
556 case DT::VEC_LONG:
557 case DT::LONGLONG:
558 case DT::VEC_LONGLONG:
559 return std::make_tuple(true, true);
560 case DT::USHORT:
561 case DT::VEC_USHORT:
562 case DT::UINT:
563 case DT::VEC_UINT:
564 case DT::ULONG:
565 case DT::VEC_ULONG:
566 case DT::ULONGLONG:
567 case DT::VEC_ULONGLONG:
568 return std::make_tuple(true, false);
569 default:
570 return std::make_tuple(false, false);
571 }
572}
573
582template <typename T>
583inline std::tuple<bool, bool> isInteger()
584{
585 Datatype dtype = determineDatatype<T>();
586
587 return isInteger(dtype);
588}
589
596template <typename T_FP>
598{
599 // template
600 bool tt_is_fp = isFloatingPoint<T_FP>();
601
602 // Datatype
603 bool dt_is_fp = isFloatingPoint(d);
604
605 if (tt_is_fp && dt_is_fp && toBits(d) == toBits(determineDatatype<T_FP>()))
606 return true;
607 else
608 return false;
609}
610
618template <typename T_CFP>
620{
621 // template
622 bool tt_is_cfp = isComplexFloatingPoint<T_CFP>();
623
624 // Datatype
625 bool dt_is_cfp = isComplexFloatingPoint(d);
626
627 if (tt_is_cfp && dt_is_cfp &&
628 toBits(d) == toBits(determineDatatype<T_CFP>()))
629 return true;
630 else
631 return false;
632}
633
641template <typename T_Int>
643{
644 // template
645 bool tt_is_int, tt_is_sig;
646 std::tie(tt_is_int, tt_is_sig) = isInteger<T_Int>();
647
648 // Datatype
649 bool dt_is_int, dt_is_sig;
650 std::tie(dt_is_int, dt_is_sig) = isInteger(d);
651
652 if (tt_is_int && dt_is_int && tt_is_sig == dt_is_sig &&
653 toBits(d) == toBits(determineDatatype<T_Int>()))
654 return true;
655 else
656 return false;
657}
658
666constexpr bool isChar(Datatype d)
667{
668 switch (d)
669 {
670 case Datatype::CHAR:
671 case Datatype::SCHAR:
672 case Datatype::UCHAR:
673 return true;
674 default:
675 return false;
676 }
677}
678
691template <typename T_Char>
692constexpr bool isSameChar(Datatype d);
693
700inline bool isSame(openPMD::Datatype const d, openPMD::Datatype const e)
701{
702 // exact same type
703 if (static_cast<int>(d) == static_cast<int>(e))
704 return true;
705
706 bool d_is_vec = isVector(d);
707 bool e_is_vec = isVector(e);
708
709 // same int
710 bool d_is_int, d_is_sig;
711 std::tie(d_is_int, d_is_sig) = isInteger(d);
712 bool e_is_int, e_is_sig;
713 std::tie(e_is_int, e_is_sig) = isInteger(e);
714 if (d_is_int && e_is_int && d_is_vec == e_is_vec && d_is_sig == e_is_sig &&
715 toBits(d) == toBits(e))
716 return true;
717
718 // same float
719 bool d_is_fp = isFloatingPoint(d);
720 bool e_is_fp = isFloatingPoint(e);
721
722 if (d_is_fp && e_is_fp && d_is_vec == e_is_vec && toBits(d) == toBits(e))
723 return true;
724
725 // same complex floating point
726 bool d_is_cfp = isComplexFloatingPoint(d);
727 bool e_is_cfp = isComplexFloatingPoint(e);
728
729 if (d_is_cfp && e_is_cfp && d_is_vec == e_is_vec && toBits(d) == toBits(e))
730 return true;
731
732 return false;
733}
734
742
743Datatype toVectorType(Datatype dt);
744
745std::string datatypeToString(Datatype dt);
746
747Datatype stringToDatatype(const std::string &s);
748
749void warnWrongDtype(std::string const &key, Datatype store, Datatype request);
750
751std::ostream &operator<<(std::ostream &, openPMD::Datatype const &);
752
753template <typename T>
754constexpr auto datatypeIndex() -> size_t
755{
756 return static_cast<size_t>(static_cast<int>(determineDatatype<T>()));
757}
758
773template <typename Action, typename... Args>
774constexpr auto switchType(Datatype dt, Args &&...args)
775 -> decltype(Action::template call<char>(std::forward<Args>(args)...));
776
792template <typename Action, typename... Args>
793constexpr auto switchNonVectorType(Datatype dt, Args &&...args)
794 -> decltype(Action::template call<char>(std::forward<Args>(args)...));
795
811template <typename Action, typename... Args>
812constexpr auto switchDatasetType(Datatype dt, Args &&...args)
813 -> decltype(Action::template call<char>(std::forward<Args>(args)...));
814
815} // namespace openPMD
816
817#if !defined(_MSC_VER)
830inline bool operator==(openPMD::Datatype d, openPMD::Datatype e)
831{
832 return openPMD::isSame(d, e);
833}
834
835inline bool operator!=(openPMD::Datatype d, openPMD::Datatype e)
836{
837 return !(d == e);
838}
841#endif
842
843#include "openPMD/Datatype.tpp"
844#include "openPMD/UndefDatatypeMacros.hpp"
Public definitions of openPMD-api.
Definition Date.cpp:29
std::tuple< bool, bool > isInteger()
Compare if a type is an integer type.
Definition Datatype.hpp:583
constexpr bool isSameChar(Datatype d)
Determines if d and T_Char are char types of same representation.
bool isSameFloatingPoint(Datatype d)
Compare if a Datatype is equivalent to a floating point type.
Definition Datatype.hpp:597
bool isSameComplexFloatingPoint(Datatype d)
Compare if a Datatype is equivalent to a complex floating point type.
Definition Datatype.hpp:619
size_t toBits(Datatype d)
Return number of bits representing a Datatype.
Definition Datatype.hpp:417
@ T
time
Definition UnitDimension.hpp:41
bool isFloatingPoint()
Compare if a type is a floating point type.
Definition Datatype.hpp:515
constexpr bool isChar(Datatype d)
Determines if d represents a char type.
Definition Datatype.hpp:666
std::vector< Datatype > openPMD_Datatypes()
All openPMD datatypes defined in Datatype, listed in order in a vector.
Definition Datatype.cpp:227
constexpr bool isComplexFloatingPoint()
Compare if a type is a complex floating point type.
Definition Datatype.hpp:530
bool isSame(openPMD::Datatype const d, openPMD::Datatype const e)
Comparison for two Datatypes.
Definition Datatype.hpp:700
size_t toBytes(Datatype d)
Return number of bytes representing a Datatype.
Definition Datatype.hpp:345
constexpr bool isVector(Datatype d)
Compare if a Datatype is a vector type.
Definition Datatype.hpp:427
bool isSameInteger(Datatype d)
Compare if a Datatype is equivalent to an integer type.
Definition Datatype.hpp:642
Datatype
Concrete datatype of an object available at runtime.
Definition Datatype.hpp:51
constexpr auto switchType(Datatype dt, Args &&...args) -> decltype(Action::template call< char >(std::forward< Args >(args)...))
Generalizes switching over an openPMD datatype.
constexpr auto switchNonVectorType(Datatype dt, Args &&...args) -> decltype(Action::template call< char >(std::forward< Args >(args)...))
Generalizes switching over an openPMD datatype.
Datatype basicDatatype(Datatype dt)
basicDatatype Strip openPMD Datatype of std::vector, std::array et.
Definition Datatype.cpp:289
constexpr auto switchDatasetType(Datatype dt, Args &&...args) -> decltype(Action::template call< char >(std::forward< Args >(args)...))
Generalizes switching over an openPMD datatype.
Fundamental equivalence check for two given types T and U.
Definition Datatype.hpp:120