1 /* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */
2
3 #ifndef MPT_BASE_FLOATINGPOINT_HPP
4 #define MPT_BASE_FLOATINGPOINT_HPP
5
6
7
8 #include "mpt/base/detect.hpp"
9 #include "mpt/base/namespace.hpp"
10
11 #include <limits>
12 #include <type_traits>
13
14
15
16 namespace mpt {
17 inline namespace MPT_INLINE_NS {
18
19
20 // fp half
21 // n/a
22
23 // fp single
24 using single = float;
25 namespace float_literals {
operator ""_fs(long double lit)26 constexpr single operator"" _fs(long double lit) noexcept {
27 return static_cast<single>(lit);
28 }
29 } // namespace float_literals
30
31 // fp double
32 namespace float_literals {
operator ""_fd(long double lit)33 constexpr double operator"" _fd(long double lit) noexcept {
34 return static_cast<double>(lit);
35 }
36 } // namespace float_literals
37
38 // fp extended
39 namespace float_literals {
operator ""_fe(long double lit)40 constexpr long double operator"" _fe(long double lit) noexcept {
41 return static_cast<long double>(lit);
42 }
43 } // namespace float_literals
44
45 // fp quad
46 // n/a
47
48 using float32 = std::conditional<sizeof(float) == 4, float, std::conditional<sizeof(double) == 4, double, std::conditional<sizeof(long double) == 4, long double, float>::type>::type>::type;
49 namespace float_literals {
operator ""_f32(long double lit)50 constexpr float32 operator"" _f32(long double lit) noexcept {
51 return static_cast<float32>(lit);
52 }
53 } // namespace float_literals
54
55 using float64 = std::conditional<sizeof(float) == 8, float, std::conditional<sizeof(double) == 8, double, std::conditional<sizeof(long double) == 8, long double, double>::type>::type>::type;
56 namespace float_literals {
operator ""_f64(long double lit)57 constexpr float64 operator"" _f64(long double lit) noexcept {
58 return static_cast<float64>(lit);
59 }
60 } // namespace float_literals
61
62 template <typename T>
63 struct float_traits {
64 static constexpr bool is_float = !std::numeric_limits<T>::is_integer;
65 static constexpr bool is_hard = is_float && !MPT_COMPILER_QUIRK_FLOAT_EMULATED;
66 static constexpr bool is_soft = is_float && MPT_COMPILER_QUIRK_FLOAT_EMULATED;
67 static constexpr bool is_float32 = is_float && (sizeof(T) == 4);
68 static constexpr bool is_float64 = is_float && (sizeof(T) == 8);
69 static constexpr bool is_native_endian = is_float && !MPT_COMPILER_QUIRK_FLOAT_NOTNATIVEENDIAN;
70 static constexpr bool is_ieee754_binary = is_float && std::numeric_limits<T>::is_iec559 && !MPT_COMPILER_QUIRK_FLOAT_NOTIEEE754;
71 static constexpr bool is_ieee754_binary32 = is_float && is_ieee754_binary && is_float32;
72 static constexpr bool is_ieee754_binary64 = is_float && is_ieee754_binary && is_float64;
73 static constexpr bool is_ieee754_binary32ne = is_float && is_ieee754_binary && is_float32 && is_native_endian;
74 static constexpr bool is_ieee754_binary64ne = is_float && is_ieee754_binary && is_float64 && is_native_endian;
75 static constexpr bool is_preferred = is_float && ((is_float32 && MPT_COMPILER_QUIRK_FLOAT_PREFER32) || (is_float64 && MPT_COMPILER_QUIRK_FLOAT_PREFER64));
76 };
77
78 // prefer smaller floats, but try to use IEEE754 floats
79 using nativefloat =
80 std::conditional<mpt::float_traits<float32>::is_preferred, float32, std::conditional<mpt::float_traits<float64>::is_preferred, float64, std::conditional<std::numeric_limits<float>::is_iec559, float, std::conditional<std::numeric_limits<double>::is_iec559, double, std::conditional<std::numeric_limits<long double>::is_iec559, long double, float>::type>::type>::type>::type>::type;
81 namespace float_literals {
operator ""_nf(long double lit)82 constexpr nativefloat operator"" _nf(long double lit) noexcept {
83 return static_cast<nativefloat>(lit);
84 }
85 } // namespace float_literals
86
87
88 } // namespace MPT_INLINE_NS
89 } // namespace mpt
90
91
92
93 #endif // MPT_BASE_FLOATINGPOINT_HPP
94