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