| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // SPDX-FileCopyrightText: 2022-2023 Dennis Gläser <dennis.glaeser@iws.uni-stuttgart.de> | ||
| 2 | // SPDX-License-Identifier: MIT | ||
| 3 | /*! | ||
| 4 | * \file | ||
| 5 | * \ingroup Common | ||
| 6 | * \brief Types to represent different precisions. | ||
| 7 | */ | ||
| 8 | #ifndef GRIDFORMAT_COMMON_PRECISION_HPP_ | ||
| 9 | #define GRIDFORMAT_COMMON_PRECISION_HPP_ | ||
| 10 | |||
| 11 | #include <cstdint> | ||
| 12 | #include <variant> | ||
| 13 | #include <utility> | ||
| 14 | #include <type_traits> | ||
| 15 | #include <concepts> | ||
| 16 | #include <ostream> | ||
| 17 | |||
| 18 | #include <gridformat/common/type_traits.hpp> | ||
| 19 | #include <gridformat/common/concepts.hpp> | ||
| 20 | |||
| 21 | namespace GridFormat { | ||
| 22 | |||
| 23 | /*! | ||
| 24 | * \ingroup Common | ||
| 25 | * \brief Represents a precision known at compile-time | ||
| 26 | */ | ||
| 27 | template<Concepts::Scalar _T> | ||
| 28 | struct Precision { using T = _T; }; | ||
| 29 | |||
| 30 | using Float32 = Precision<float>; | ||
| 31 | using Float64 = Precision<double>; | ||
| 32 | inline constexpr Float32 float32; | ||
| 33 | inline constexpr Float64 float64; | ||
| 34 | |||
| 35 | using Int8 = Precision<std::int_least8_t>; | ||
| 36 | using Int16 = Precision<std::int_least16_t>; | ||
| 37 | using Int32 = Precision<std::int_least32_t>; | ||
| 38 | using Int64 = Precision<std::int_least64_t>; | ||
| 39 | inline constexpr Int8 int8; | ||
| 40 | inline constexpr Int16 int16; | ||
| 41 | inline constexpr Int32 int32; | ||
| 42 | inline constexpr Int64 int64; | ||
| 43 | |||
| 44 | using UInt8 = Precision<std::uint_least8_t>; | ||
| 45 | using UInt16 = Precision<std::uint_least16_t>; | ||
| 46 | using UInt32 = Precision<std::uint_least32_t>; | ||
| 47 | using UInt64 = Precision<std::uint_least64_t>; | ||
| 48 | inline constexpr UInt8 uint8; | ||
| 49 | inline constexpr UInt16 uint16; | ||
| 50 | inline constexpr UInt32 uint32; | ||
| 51 | inline constexpr UInt64 uint64; | ||
| 52 | |||
| 53 | using Boolean = Precision<bool>; | ||
| 54 | inline constexpr Boolean boolean; | ||
| 55 | |||
| 56 | /*! | ||
| 57 | * \ingroup Common | ||
| 58 | * \brief Represents a dynamic precision. | ||
| 59 | * \note This can only represent the precisions predefined in this header. | ||
| 60 | */ | ||
| 61 | class DynamicPrecision { | ||
| 62 | public: | ||
| 63 | 162134 | DynamicPrecision() = default; | |
| 64 | |||
| 65 | template<typename T> | ||
| 66 | 1036354 | DynamicPrecision(Precision<T> prec) | |
| 67 | 1036354 | : _precision{std::move(prec)} | |
| 68 | 1036354 | {} | |
| 69 | |||
| 70 | 140510 | bool is_integral() const { | |
| 71 | 421530 | return std::visit([] <typename T> (const Precision<T>&) { | |
| 72 | 281020 | return std::is_integral_v<T>; | |
| 73 |
1/2✓ Branch 1 taken 140510 times.
✗ Branch 2 not taken.
|
281020 | }, _precision); |
| 74 | } | ||
| 75 | |||
| 76 | 19032 | bool is_signed() const { | |
| 77 | 57096 | return std::visit([] <typename T> (const Precision<T>&) { | |
| 78 | 38064 | return std::is_signed_v<T>; | |
| 79 |
1/2✓ Branch 1 taken 19032 times.
✗ Branch 2 not taken.
|
38064 | }, _precision); |
| 80 | } | ||
| 81 | |||
| 82 | 330351 | std::size_t size_in_bytes() const { | |
| 83 | 991053 | return std::visit([] <typename T> (const Precision<T>&) { | |
| 84 | 660702 | return sizeof(T); | |
| 85 |
1/2✓ Branch 1 taken 330351 times.
✗ Branch 2 not taken.
|
660702 | }, _precision); |
| 86 | } | ||
| 87 | |||
| 88 | template<typename T> | ||
| 89 | 21758 | bool is() const { | |
| 90 | 65274 | return std::visit([] <typename _T> (const Precision<_T>&) { | |
| 91 | 21758 | return std::is_same_v<_T, T>; | |
| 92 |
1/2✓ Branch 1 taken 21758 times.
✗ Branch 2 not taken.
|
43516 | }, _precision); |
| 93 | } | ||
| 94 | |||
| 95 | template<typename Visitor> | ||
| 96 | 225871 | decltype(auto) visit(Visitor&& visitor) const { | |
| 97 | 225871 | return std::visit(std::forward<Visitor>(visitor), _precision); | |
| 98 | } | ||
| 99 | |||
| 100 | 1127 | bool operator==(const DynamicPrecision& other) const { | |
| 101 | 1127 | return _precision.index() == other._precision.index(); | |
| 102 | } | ||
| 103 | |||
| 104 | 11 | friend std::ostream& operator<<(std::ostream& s, const DynamicPrecision& prec) { | |
| 105 |
1/2✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
|
33 | prec.visit([&] <typename T> (Precision<T>) { |
| 106 | if constexpr (std::is_same_v<T, char>) | ||
| 107 | ✗ | s << "char"; | |
| 108 | else if constexpr (std::signed_integral<T>) | ||
| 109 | 8 | s << "int" << sizeof(T)*8; | |
| 110 | else if constexpr (std::unsigned_integral<T>) | ||
| 111 | 10 | s << "uint" << sizeof(T)*8; | |
| 112 | else | ||
| 113 | 4 | s << "float" << sizeof(T)*8; | |
| 114 | 22 | }); | |
| 115 | 11 | return s; | |
| 116 | } | ||
| 117 | |||
| 118 | private: | ||
| 119 | UniqueVariant< | ||
| 120 | Precision<float>, | ||
| 121 | Precision<double>, | ||
| 122 | Precision<std::int8_t>, | ||
| 123 | Precision<std::int16_t>, | ||
| 124 | Precision<std::int32_t>, | ||
| 125 | Precision<std::int64_t>, | ||
| 126 | Precision<std::uint8_t>, | ||
| 127 | Precision<std::uint16_t>, | ||
| 128 | Precision<std::uint32_t>, | ||
| 129 | Precision<std::uint64_t>, | ||
| 130 | Precision<std::size_t>, | ||
| 131 | Precision<char>, | ||
| 132 | Precision<bool> | ||
| 133 | > _precision; | ||
| 134 | }; | ||
| 135 | |||
| 136 | } // namespace GridFormat | ||
| 137 | |||
| 138 | #endif // GRIDFORMAT_COMMON_PRECISION_HPP_ | ||
| 139 |