View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0001272 | OpenMPT | General | public | 2019-10-14 16:20 | 2019-10-20 07:07 |
| Reporter | manx | Assigned To | manx | ||
| Priority | normal | Severity | minor | Reproducibility | have not tried |
| Status | resolved | Resolution | fixed | ||
| Product Version | OpenMPT 1.29.00.* (old testing) | ||||
| Target Version | OpenMPT 1.29.01.00 / libopenmpt 0.5.0 (upgrade first) | Fixed in Version | OpenMPT 1.29.01.00 / libopenmpt 0.5.0 (upgrade first) | ||
| Summary | 0001272: use C++20 in Endianness.h | ||||
| Description | Use C++20 std::is_constant_evaluated() for packed<T> implementation and remove MPT_ENDIAN_IS_COSTEXPR macro. | ||||
| Tags | No tags attached. | ||||
| Attached Files | endian-cpp20-v1.patch (16,841 bytes)
Index: common/Endianness.h
===================================================================
--- common/Endianness.h (revision 12190)
+++ common/Endianness.h (working copy)
@@ -13,6 +13,9 @@
#include "BuildSettings.h"
#include <array>
+#if MPT_CXX_AT_LEAST(20)
+#include <bit>
+#endif // C++20
#include <limits>
#include <cmath>
@@ -27,16 +30,44 @@
+OPENMPT_NAMESPACE_BEGIN
+
+
+
+namespace mpt {
+
+
+
#if MPT_CXX_AT_LEAST(20)
-// nothing
+using std::endian;
-#elif MPT_COMPILER_GENERIC
+static_assert(mpt::endian::big != mpt::endian::little, "platform with all scalar types having size 1 is not supported");
-// rely on runtime detection instead of using non-standard macros
+static constexpr mpt::endian get_endian() noexcept
+{
+ return mpt::endian::native;
+}
-#else
+static constexpr bool endian_is_little() noexcept
+{
+ return get_endian() == mpt::endian::little;
+}
+static constexpr bool endian_is_big() noexcept
+{
+ return get_endian() == mpt::endian::big;
+}
+
+static constexpr bool endian_is_weird() noexcept
+{
+ return !endian_is_little() && !endian_is_big();
+}
+
+#else // !C++20
+
+#if !MPT_COMPILER_GENERIC
+
#if MPT_COMPILER_MSVC
#define MPT_PLATFORM_LITTLE_ENDIAN
#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG
@@ -75,101 +106,26 @@
#endif
#endif
-#endif
+#endif // !MPT_COMPILER_GENERIC
-#if defined(MPT_PLATFORM_BIG_ENDIAN) || defined(MPT_PLATFORM_LITTLE_ENDIAN)
-#define MPT_PLATFORM_ENDIAN_KNOWN 1
-#else
-#define MPT_PLATFORM_ENDIAN_KNOWN 0
-#endif
-
-
-
-#if MPT_PLATFORM_ENDIAN_KNOWN
-//#define MPT_ENDIAN_IS_CONSTEXPR 1
-// For now, we do not want to use constexpr endianness functions and types.
-// It bloats the binary size somewhat (possibly because of either the zeroing
-// constructor or because of not being able to use byteswap intrinsics) and has
-// currently no compelling benefit for us
-#define MPT_ENDIAN_IS_CONSTEXPR 0
-#else
-#define MPT_ENDIAN_IS_CONSTEXPR 0
-#endif
-
-#if MPT_ENDIAN_IS_CONSTEXPR
-#define MPT_ENDIAN_CONSTEXPR_FUN MPT_CONSTEXPR14_FUN
-#define MPT_ENDIAN_CONSTEXPR_VAR MPT_CONSTEXPR14_VAR
-#else
-#define MPT_ENDIAN_CONSTEXPR_FUN MPT_FORCEINLINE
-#define MPT_ENDIAN_CONSTEXPR_VAR const
-#endif
-
-
-
-OPENMPT_NAMESPACE_BEGIN
-
-
-
-namespace mpt {
-
-
-
-// C++20 std::endian
-#if MPT_CXX_AT_LEAST(20)
-using std::endian;
-static_assert(mpt::endian::big != mpt::endian::little, "platform with all scalar types having size 1 is not supported");
-#else // !C++20
enum class endian
{
little = 0x78563412u,
big = 0x12345678u,
weird = 1u,
-#if MPT_PLATFORM_ENDIAN_KNOWN && defined(MPT_PLATFORM_LITTLE_ENDIAN)
- native = little
-#elif MPT_PLATFORM_ENDIAN_KNOWN && defined(MPT_PLATFORM_BIG_ENDIAN)
- native = big
+#if MPT_COMPILER_GENERIC
+ native = 0u,
+#elif defined(MPT_PLATFORM_LITTLE_ENDIAN)
+ native = little,
+#elif defined(MPT_PLATFORM_BIG_ENDIAN)
+ native = big,
#else
- native = 0u
+ native = 0u,
#endif
};
-#endif // C++20
-MPT_CONSTEXPR11_FUN bool endian_known() noexcept
-{
- return ((mpt::endian::native == mpt::endian::little) || (mpt::endian::native == mpt::endian::big));
-}
+static_assert(mpt::endian::big != mpt::endian::little, "platform with all scalar types having size 1 is not supported");
-MPT_CONSTEXPR11_FUN bool endian_unknown() noexcept
-{
- return ((mpt::endian::native != mpt::endian::little) && (mpt::endian::native != mpt::endian::big));
-}
-
-
-
-#if MPT_CXX_AT_LEAST(20)
-
-static MPT_CONSTEXPR11_FUN mpt::endian get_endian() noexcept
-{
- return mpt::endian::native;
-}
-
-static MPT_CONSTEXPR11_FUN bool endian_is_little() noexcept
-{
- return get_endian() == mpt::endian::little;
-}
-
-static MPT_CONSTEXPR11_FUN bool endian_is_big() noexcept
-{
- return get_endian() == mpt::endian::big;
-}
-
-static MPT_CONSTEXPR11_FUN bool endian_is_weird() noexcept
-{
- return !endian_is_little() && !endian_is_big();
-}
-
-#else // !C++20
-
namespace detail {
static MPT_FORCEINLINE mpt::endian endian_probe() noexcept
@@ -178,9 +134,8 @@
static_assert(sizeof(endian_probe_type) == 4);
constexpr endian_probe_type endian_probe_big = 0x12345678u;
constexpr endian_probe_type endian_probe_little = 0x78563412u;
- const std::byte probe[sizeof(endian_probe_type)] = { mpt::as_byte(0x12), mpt::as_byte(0x34), mpt::as_byte(0x56), mpt::as_byte(0x78) };
- endian_probe_type test;
- std::memcpy(&test, probe, sizeof(endian_probe_type));
+ const std::array<std::byte, sizeof(endian_probe_type)> probe{ mpt::as_byte(0x12), mpt::as_byte(0x34), mpt::as_byte(0x56), mpt::as_byte(0x78) };
+ const endian_probe_type test = mpt::bit_cast<endian_probe_type>(probe);
mpt::endian result = mpt::endian::native;
switch(test)
{
@@ -197,11 +152,11 @@
return result;
}
-}
+} // namespace detail
static MPT_FORCEINLINE mpt::endian get_endian() noexcept
{
- if constexpr(mpt::endian_known())
+ if constexpr((mpt::endian::native == mpt::endian::little) || (mpt::endian::native == mpt::endian::big))
{
return mpt::endian::native;
} else
@@ -262,7 +217,32 @@
-#if !MPT_ENDIAN_IS_CONSTEXPR
+#define MPT_constexpr_bswap16(x) \
+ ( uint16(0) \
+ | ((static_cast<uint16>(x) >> 8) & 0x00FFu) \
+ | ((static_cast<uint16>(x) << 8) & 0xFF00u) \
+ ) \
+/**/
+#define MPT_constexpr_bswap32(x) \
+ ( uint32(0) \
+ | ((static_cast<uint32>(x) & 0x000000FFu) << 24) \
+ | ((static_cast<uint32>(x) & 0x0000FF00u) << 8) \
+ | ((static_cast<uint32>(x) & 0x00FF0000u) >> 8) \
+ | ((static_cast<uint32>(x) & 0xFF000000u) >> 24) \
+ ) \
+/**/
+#define MPT_constexpr_bswap64(x) \
+ ( uint64(0) \
+ | (((static_cast<uint64>(x) >> 0) & 0xffull) << 56) \
+ | (((static_cast<uint64>(x) >> 8) & 0xffull) << 48) \
+ | (((static_cast<uint64>(x) >> 16) & 0xffull) << 40) \
+ | (((static_cast<uint64>(x) >> 24) & 0xffull) << 32) \
+ | (((static_cast<uint64>(x) >> 32) & 0xffull) << 24) \
+ | (((static_cast<uint64>(x) >> 40) & 0xffull) << 16) \
+ | (((static_cast<uint64>(x) >> 48) & 0xffull) << 8) \
+ | (((static_cast<uint64>(x) >> 56) & 0xffull) << 0) \
+ ) \
+/**/
#if MPT_COMPILER_GCC
#define MPT_bswap16 __builtin_bswap16
@@ -296,44 +276,19 @@
#endif
} } // namespace mpt::detail
-#endif // !MPT_ENDIAN_IS_CONSTEXPR
-
-
// No intrinsics available
#ifndef MPT_bswap16
-#define MPT_bswap16(x) \
- ( uint16(0) \
- | ((static_cast<uint16>(x) >> 8) & 0x00FFu) \
- | ((static_cast<uint16>(x) << 8) & 0xFF00u) \
- ) \
-/**/
+#define MPT_bswap16(x) MPT_constexpr_bswap16(x)
#endif
#ifndef MPT_bswap32
-#define MPT_bswap32(x) \
- ( uint32(0) \
- | ((static_cast<uint32>(x) & 0x000000FFu) << 24) \
- | ((static_cast<uint32>(x) & 0x0000FF00u) << 8) \
- | ((static_cast<uint32>(x) & 0x00FF0000u) >> 8) \
- | ((static_cast<uint32>(x) & 0xFF000000u) >> 24) \
- ) \
-/**/
+#define MPT_bswap32(x) MPT_constexpr_bswap32(x)
#endif
#ifndef MPT_bswap64
-#define MPT_bswap64(x) \
- ( uint64(0) \
- | (((static_cast<uint64>(x) >> 0) & 0xffull) << 56) \
- | (((static_cast<uint64>(x) >> 8) & 0xffull) << 48) \
- | (((static_cast<uint64>(x) >> 16) & 0xffull) << 40) \
- | (((static_cast<uint64>(x) >> 24) & 0xffull) << 32) \
- | (((static_cast<uint64>(x) >> 32) & 0xffull) << 24) \
- | (((static_cast<uint64>(x) >> 40) & 0xffull) << 16) \
- | (((static_cast<uint64>(x) >> 48) & 0xffull) << 8) \
- | (((static_cast<uint64>(x) >> 56) & 0xffull) << 0) \
- ) \
-/**/
+#define MPT_bswap64(x) MPT_constexpr_bswap64(x)
#endif
+
template <typename T, typename Tendian, std::size_t size>
static MPT_CONSTEXPR17_FUN std::array<std::byte, size> EndianEncode(T val) noexcept
{
@@ -397,24 +352,28 @@
namespace detail
{
-static MPT_ENDIAN_CONSTEXPR_FUN uint64 SwapBytes(uint64 value) noexcept { return MPT_bswap64(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN uint32 SwapBytes(uint32 value) noexcept { return MPT_bswap32(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN uint16 SwapBytes(uint16 value) noexcept { return MPT_bswap16(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN int64 SwapBytes(int64 value) noexcept { return MPT_bswap64(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN int32 SwapBytes(int32 value) noexcept { return MPT_bswap32(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN int16 SwapBytes(int16 value) noexcept { return MPT_bswap16(value); }
+static constexpr MPT_FORCEINLINE uint64 SwapBytes(uint64 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED()) { return MPT_constexpr_bswap64(value); } else { return MPT_bswap64(value); } }
+static constexpr MPT_FORCEINLINE uint32 SwapBytes(uint32 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED()) { return MPT_constexpr_bswap32(value); } else { return MPT_bswap32(value); } }
+static constexpr MPT_FORCEINLINE uint16 SwapBytes(uint16 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED()) { return MPT_constexpr_bswap16(value); } else { return MPT_bswap16(value); } }
+static constexpr MPT_FORCEINLINE int64 SwapBytes(int64 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED()) { return MPT_constexpr_bswap64(value); } else { return MPT_bswap64(value); } }
+static constexpr MPT_FORCEINLINE int32 SwapBytes(int32 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED()) { return MPT_constexpr_bswap32(value); } else { return MPT_bswap32(value); } }
+static constexpr MPT_FORCEINLINE int16 SwapBytes(int16 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED()) { return MPT_constexpr_bswap16(value); } else { return MPT_bswap16(value); } }
// Do NOT remove these overloads, even if they seem useless.
// We do not want risking to extend 8bit integers to int and then
// endian-converting and casting back to int.
// Thus these overloads.
-static MPT_ENDIAN_CONSTEXPR_FUN uint8 SwapBytes(uint8 value) noexcept { return value; }
-static MPT_ENDIAN_CONSTEXPR_FUN int8 SwapBytes(int8 value) noexcept { return value; }
-static MPT_ENDIAN_CONSTEXPR_FUN char SwapBytes(char value) noexcept { return value; }
+static constexpr MPT_FORCEINLINE uint8 SwapBytes(uint8 value) noexcept { return value; }
+static constexpr MPT_FORCEINLINE int8 SwapBytes(int8 value) noexcept { return value; }
+static constexpr MPT_FORCEINLINE char SwapBytes(char value) noexcept { return value; }
} // namespace detail
} // namespace mpt
+#undef MPT_constexpr_bswap16
+#undef MPT_constexpr_bswap32
+#undef MPT_constexpr_bswap64
+
#undef MPT_bswap16
#undef MPT_bswap32
#undef MPT_bswap64
@@ -912,16 +871,13 @@
using base_type = T;
using endian_type = Tendian;
public:
-#if MPT_ENDIAN_IS_CONSTEXPR
- std::array<std::byte, sizeof(base_type)> data{};
-#else // !MPT_ENDIAN_IS_CONSTEXPR
std::array<std::byte, sizeof(base_type)> data;
-#endif // MPT_ENDIAN_IS_CONSTEXPR
public:
- MPT_ENDIAN_CONSTEXPR_FUN void set(base_type val) noexcept
+ MPT_CONSTEXPR14_FUN void set(base_type val) noexcept
{
static_assert(std::numeric_limits<T>::is_integer);
- #if MPT_ENDIAN_IS_CONSTEXPR
+ MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED())
+ {
if constexpr(endian_type::endian == mpt::endian::big)
{
typename std::make_unsigned<base_type>::type uval = val;
@@ -937,7 +893,8 @@
data[i] = static_cast<std::byte>((uval >> (8*i)) & 0xffu);
}
}
- #else // !MPT_ENDIAN_IS_CONSTEXPR
+ } else
+ {
if constexpr(mpt::endian::native == mpt::endian::little || mpt::endian::native == mpt::endian::big)
{
if constexpr(mpt::endian::native != endian_type::endian)
@@ -950,12 +907,13 @@
using unsigned_base_type = typename std::make_unsigned<base_type>::type;
data = EndianEncode<unsigned_base_type, Tendian, sizeof(T)>(val);
}
- #endif // MPT_ENDIAN_IS_CONSTEXPR
+ }
}
- MPT_ENDIAN_CONSTEXPR_FUN base_type get() const noexcept
+ MPT_CONSTEXPR14_FUN base_type get() const noexcept
{
static_assert(std::numeric_limits<T>::is_integer);
- #if MPT_ENDIAN_IS_CONSTEXPR
+ MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED())
+ {
if constexpr(endian_type::endian == mpt::endian::big)
{
typename std::make_unsigned<base_type>::type uval = 0;
@@ -973,7 +931,8 @@
}
return static_cast<base_type>(uval);
}
- #else // !MPT_ENDIAN_IS_CONSTEXPR
+ } else
+ {
if constexpr(mpt::endian::native == mpt::endian::little || mpt::endian::native == mpt::endian::big)
{
base_type val = base_type();
@@ -988,23 +947,23 @@
using unsigned_base_type = typename std::make_unsigned<base_type>::type;
return EndianDecode<unsigned_base_type, Tendian, sizeof(T)>(data);
}
- #endif // MPT_ENDIAN_IS_CONSTEXPR
+ }
}
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator = (const base_type & val) noexcept { set(val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN operator base_type () const noexcept { return get(); }
+ MPT_CONSTEXPR14_FUN packed & operator = (const base_type & val) noexcept { set(val); return *this; }
+ MPT_CONSTEXPR14_FUN operator base_type () const noexcept { return get(); }
public:
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator &= (base_type val) noexcept { set(get() & val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator |= (base_type val) noexcept { set(get() | val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator ^= (base_type val) noexcept { set(get() ^ val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator += (base_type val) noexcept { set(get() + val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator -= (base_type val) noexcept { set(get() - val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator *= (base_type val) noexcept { set(get() * val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator /= (base_type val) noexcept { set(get() / val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator %= (base_type val) noexcept { set(get() % val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator ++ () noexcept { set(get() + 1); return *this; } // prefix
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator -- () noexcept { set(get() - 1); return *this; } // prefix
- MPT_ENDIAN_CONSTEXPR_FUN base_type operator ++ (int) noexcept { base_type old = get(); set(old + 1); return old; } // postfix
- MPT_ENDIAN_CONSTEXPR_FUN base_type operator -- (int) noexcept { base_type old = get(); set(old - 1); return old; } // postfix
+ MPT_CONSTEXPR14_FUN packed & operator &= (base_type val) noexcept { set(get() & val); return *this; }
+ MPT_CONSTEXPR14_FUN packed & operator |= (base_type val) noexcept { set(get() | val); return *this; }
+ MPT_CONSTEXPR14_FUN packed & operator ^= (base_type val) noexcept { set(get() ^ val); return *this; }
+ MPT_CONSTEXPR14_FUN packed & operator += (base_type val) noexcept { set(get() + val); return *this; }
+ MPT_CONSTEXPR14_FUN packed & operator -= (base_type val) noexcept { set(get() - val); return *this; }
+ MPT_CONSTEXPR14_FUN packed & operator *= (base_type val) noexcept { set(get() * val); return *this; }
+ MPT_CONSTEXPR14_FUN packed & operator /= (base_type val) noexcept { set(get() / val); return *this; }
+ MPT_CONSTEXPR14_FUN packed & operator %= (base_type val) noexcept { set(get() % val); return *this; }
+ MPT_CONSTEXPR14_FUN packed & operator ++ () noexcept { set(get() + 1); return *this; } // prefix
+ MPT_CONSTEXPR14_FUN packed & operator -- () noexcept { set(get() - 1); return *this; } // prefix
+ MPT_CONSTEXPR14_FUN base_type operator ++ (int) noexcept { base_type old = get(); set(old + 1); return old; } // postfix
+ MPT_CONSTEXPR14_FUN base_type operator -- (int) noexcept { base_type old = get(); set(old - 1); return old; } // postfix
};
using int64le = packed< int64, LittleEndian_tag>;
@@ -1053,24 +1012,24 @@
template <typename T> struct make_be { using type = packed<typename std::remove_const<T>::type, BigEndian_tag>; };
template <typename T>
-MPT_ENDIAN_CONSTEXPR_FUN auto as_le(T v) noexcept -> typename mpt::make_le<typename std::remove_const<T>::type>::type
+MPT_CONSTEXPR14_FUN auto as_le(T v) noexcept -> typename mpt::make_le<typename std::remove_const<T>::type>::type
{
- typename mpt::make_le<typename std::remove_const<T>::type>::type res;
+ typename mpt::make_le<typename std::remove_const<T>::type>::type res{};
res = v;
return res;
}
template <typename T>
-MPT_ENDIAN_CONSTEXPR_FUN auto as_be(T v) noexcept -> typename mpt::make_be<typename std::remove_const<T>::type>::type
+MPT_CONSTEXPR14_FUN auto as_be(T v) noexcept -> typename mpt::make_be<typename std::remove_const<T>::type>::type
{
- typename mpt::make_be<typename std::remove_const<T>::type>::type res;
+ typename mpt::make_be<typename std::remove_const<T>::type>::type res{};
res = v;
return res;
}
template <typename Tpacked>
-MPT_ENDIAN_CONSTEXPR_FUN Tpacked as_endian(typename Tpacked::base_type v) noexcept
+MPT_CONSTEXPR14_FUN Tpacked as_endian(typename Tpacked::base_type v) noexcept
{
- Tpacked res;
+ Tpacked res{};
res = v;
return res;
}
endian-cpp20-v2.patch (17,981 bytes)
Index: common/Endianness.h
===================================================================
--- common/Endianness.h (revision 12225)
+++ common/Endianness.h (working copy)
@@ -13,6 +13,9 @@
#include "BuildSettings.h"
#include <array>
+#if MPT_CXX_AT_LEAST(20)
+#include <bit>
+#endif // C++20
#include <limits>
#include <cmath>
@@ -27,16 +30,44 @@
+OPENMPT_NAMESPACE_BEGIN
+
+
+
+namespace mpt {
+
+
+
#if MPT_CXX_AT_LEAST(20)
-// nothing
+using std::endian;
-#elif MPT_COMPILER_GENERIC
+static_assert(mpt::endian::big != mpt::endian::little, "platform with all scalar types having size 1 is not supported");
-// rely on runtime detection instead of using non-standard macros
+static constexpr mpt::endian get_endian() noexcept
+{
+ return mpt::endian::native;
+}
-#else
+static constexpr bool endian_is_little() noexcept
+{
+ return get_endian() == mpt::endian::little;
+}
+static constexpr bool endian_is_big() noexcept
+{
+ return get_endian() == mpt::endian::big;
+}
+
+static constexpr bool endian_is_weird() noexcept
+{
+ return !endian_is_little() && !endian_is_big();
+}
+
+#else // !C++20
+
+#if !MPT_COMPILER_GENERIC
+
#if MPT_COMPILER_MSVC
#define MPT_PLATFORM_LITTLE_ENDIAN
#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG
@@ -75,101 +106,26 @@
#endif
#endif
-#endif
+#endif // !MPT_COMPILER_GENERIC
-#if defined(MPT_PLATFORM_BIG_ENDIAN) || defined(MPT_PLATFORM_LITTLE_ENDIAN)
-#define MPT_PLATFORM_ENDIAN_KNOWN 1
-#else
-#define MPT_PLATFORM_ENDIAN_KNOWN 0
-#endif
-
-
-
-#if MPT_PLATFORM_ENDIAN_KNOWN
-//#define MPT_ENDIAN_IS_CONSTEXPR 1
-// For now, we do not want to use constexpr endianness functions and types.
-// It bloats the binary size somewhat (possibly because of either the zeroing
-// constructor or because of not being able to use byteswap intrinsics) and has
-// currently no compelling benefit for us
-#define MPT_ENDIAN_IS_CONSTEXPR 0
-#else
-#define MPT_ENDIAN_IS_CONSTEXPR 0
-#endif
-
-#if MPT_ENDIAN_IS_CONSTEXPR
-#define MPT_ENDIAN_CONSTEXPR_FUN MPT_CONSTEXPR14_FUN
-#define MPT_ENDIAN_CONSTEXPR_VAR MPT_CONSTEXPR14_VAR
-#else
-#define MPT_ENDIAN_CONSTEXPR_FUN MPT_FORCEINLINE
-#define MPT_ENDIAN_CONSTEXPR_VAR const
-#endif
-
-
-
-OPENMPT_NAMESPACE_BEGIN
-
-
-
-namespace mpt {
-
-
-
-// C++20 std::endian
-#if MPT_CXX_AT_LEAST(20)
-using std::endian;
-static_assert(mpt::endian::big != mpt::endian::little, "platform with all scalar types having size 1 is not supported");
-#else // !C++20
enum class endian
{
little = 0x78563412u,
big = 0x12345678u,
weird = 1u,
-#if MPT_PLATFORM_ENDIAN_KNOWN && defined(MPT_PLATFORM_LITTLE_ENDIAN)
- native = little
-#elif MPT_PLATFORM_ENDIAN_KNOWN && defined(MPT_PLATFORM_BIG_ENDIAN)
- native = big
+#if MPT_COMPILER_GENERIC
+ native = 0u,
+#elif defined(MPT_PLATFORM_LITTLE_ENDIAN)
+ native = little,
+#elif defined(MPT_PLATFORM_BIG_ENDIAN)
+ native = big,
#else
- native = 0u
+ native = 0u,
#endif
};
-#endif // C++20
-MPT_CONSTEXPR11_FUN bool endian_known() noexcept
-{
- return ((mpt::endian::native == mpt::endian::little) || (mpt::endian::native == mpt::endian::big));
-}
+static_assert(mpt::endian::big != mpt::endian::little, "platform with all scalar types having size 1 is not supported");
-MPT_CONSTEXPR11_FUN bool endian_unknown() noexcept
-{
- return ((mpt::endian::native != mpt::endian::little) && (mpt::endian::native != mpt::endian::big));
-}
-
-
-
-#if MPT_CXX_AT_LEAST(20)
-
-static MPT_CONSTEXPR11_FUN mpt::endian get_endian() noexcept
-{
- return mpt::endian::native;
-}
-
-static MPT_CONSTEXPR11_FUN bool endian_is_little() noexcept
-{
- return get_endian() == mpt::endian::little;
-}
-
-static MPT_CONSTEXPR11_FUN bool endian_is_big() noexcept
-{
- return get_endian() == mpt::endian::big;
-}
-
-static MPT_CONSTEXPR11_FUN bool endian_is_weird() noexcept
-{
- return !endian_is_little() && !endian_is_big();
-}
-
-#else // !C++20
-
namespace detail {
static MPT_FORCEINLINE mpt::endian endian_probe() noexcept
@@ -178,9 +134,8 @@
static_assert(sizeof(endian_probe_type) == 4);
constexpr endian_probe_type endian_probe_big = 0x12345678u;
constexpr endian_probe_type endian_probe_little = 0x78563412u;
- const std::byte probe[sizeof(endian_probe_type)] = { mpt::as_byte(0x12), mpt::as_byte(0x34), mpt::as_byte(0x56), mpt::as_byte(0x78) };
- endian_probe_type test;
- std::memcpy(&test, probe, sizeof(endian_probe_type));
+ const std::array<std::byte, sizeof(endian_probe_type)> probe{ mpt::as_byte(0x12), mpt::as_byte(0x34), mpt::as_byte(0x56), mpt::as_byte(0x78) };
+ const endian_probe_type test = mpt::bit_cast<endian_probe_type>(probe);
mpt::endian result = mpt::endian::native;
switch(test)
{
@@ -197,11 +152,11 @@
return result;
}
-}
+} // namespace detail
static MPT_FORCEINLINE mpt::endian get_endian() noexcept
{
- if constexpr(mpt::endian_known())
+ if constexpr((mpt::endian::native == mpt::endian::little) || (mpt::endian::native == mpt::endian::big))
{
return mpt::endian::native;
} else
@@ -262,7 +217,32 @@
-#if !MPT_ENDIAN_IS_CONSTEXPR
+#define MPT_constexpr_bswap16(x) \
+ ( uint16(0) \
+ | ((static_cast<uint16>(x) >> 8) & 0x00FFu) \
+ | ((static_cast<uint16>(x) << 8) & 0xFF00u) \
+ ) \
+/**/
+#define MPT_constexpr_bswap32(x) \
+ ( uint32(0) \
+ | ((static_cast<uint32>(x) & 0x000000FFu) << 24) \
+ | ((static_cast<uint32>(x) & 0x0000FF00u) << 8) \
+ | ((static_cast<uint32>(x) & 0x00FF0000u) >> 8) \
+ | ((static_cast<uint32>(x) & 0xFF000000u) >> 24) \
+ ) \
+/**/
+#define MPT_constexpr_bswap64(x) \
+ ( uint64(0) \
+ | (((static_cast<uint64>(x) >> 0) & 0xffull) << 56) \
+ | (((static_cast<uint64>(x) >> 8) & 0xffull) << 48) \
+ | (((static_cast<uint64>(x) >> 16) & 0xffull) << 40) \
+ | (((static_cast<uint64>(x) >> 24) & 0xffull) << 32) \
+ | (((static_cast<uint64>(x) >> 32) & 0xffull) << 24) \
+ | (((static_cast<uint64>(x) >> 40) & 0xffull) << 16) \
+ | (((static_cast<uint64>(x) >> 48) & 0xffull) << 8) \
+ | (((static_cast<uint64>(x) >> 56) & 0xffull) << 0) \
+ ) \
+/**/
#if MPT_COMPILER_GCC
#define MPT_bswap16 __builtin_bswap16
@@ -296,44 +276,19 @@
#endif
} } // namespace mpt::detail
-#endif // !MPT_ENDIAN_IS_CONSTEXPR
-
-
// No intrinsics available
#ifndef MPT_bswap16
-#define MPT_bswap16(x) \
- ( uint16(0) \
- | ((static_cast<uint16>(x) >> 8) & 0x00FFu) \
- | ((static_cast<uint16>(x) << 8) & 0xFF00u) \
- ) \
-/**/
+#define MPT_bswap16(x) MPT_constexpr_bswap16(x)
#endif
#ifndef MPT_bswap32
-#define MPT_bswap32(x) \
- ( uint32(0) \
- | ((static_cast<uint32>(x) & 0x000000FFu) << 24) \
- | ((static_cast<uint32>(x) & 0x0000FF00u) << 8) \
- | ((static_cast<uint32>(x) & 0x00FF0000u) >> 8) \
- | ((static_cast<uint32>(x) & 0xFF000000u) >> 24) \
- ) \
-/**/
+#define MPT_bswap32(x) MPT_constexpr_bswap32(x)
#endif
#ifndef MPT_bswap64
-#define MPT_bswap64(x) \
- ( uint64(0) \
- | (((static_cast<uint64>(x) >> 0) & 0xffull) << 56) \
- | (((static_cast<uint64>(x) >> 8) & 0xffull) << 48) \
- | (((static_cast<uint64>(x) >> 16) & 0xffull) << 40) \
- | (((static_cast<uint64>(x) >> 24) & 0xffull) << 32) \
- | (((static_cast<uint64>(x) >> 32) & 0xffull) << 24) \
- | (((static_cast<uint64>(x) >> 40) & 0xffull) << 16) \
- | (((static_cast<uint64>(x) >> 48) & 0xffull) << 8) \
- | (((static_cast<uint64>(x) >> 56) & 0xffull) << 0) \
- ) \
-/**/
+#define MPT_bswap64(x) MPT_constexpr_bswap64(x)
#endif
+
template <typename T, typename Tendian, std::size_t size>
static MPT_CONSTEXPR17_FUN std::array<std::byte, size> EndianEncode(T val) noexcept
{
@@ -397,24 +352,28 @@
namespace detail
{
-static MPT_ENDIAN_CONSTEXPR_FUN uint64 SwapBytes(uint64 value) noexcept { return MPT_bswap64(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN uint32 SwapBytes(uint32 value) noexcept { return MPT_bswap32(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN uint16 SwapBytes(uint16 value) noexcept { return MPT_bswap16(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN int64 SwapBytes(int64 value) noexcept { return MPT_bswap64(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN int32 SwapBytes(int32 value) noexcept { return MPT_bswap32(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN int16 SwapBytes(int16 value) noexcept { return MPT_bswap16(value); }
+static MPT_CONSTEXPR20_FUN uint64 SwapBytes(uint64 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap64(value); } else { return MPT_bswap64(value); } }
+static MPT_CONSTEXPR20_FUN uint32 SwapBytes(uint32 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap32(value); } else { return MPT_bswap32(value); } }
+static MPT_CONSTEXPR20_FUN uint16 SwapBytes(uint16 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap16(value); } else { return MPT_bswap16(value); } }
+static MPT_CONSTEXPR20_FUN int64 SwapBytes(int64 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap64(value); } else { return MPT_bswap64(value); } }
+static MPT_CONSTEXPR20_FUN int32 SwapBytes(int32 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap32(value); } else { return MPT_bswap32(value); } }
+static MPT_CONSTEXPR20_FUN int16 SwapBytes(int16 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap16(value); } else { return MPT_bswap16(value); } }
// Do NOT remove these overloads, even if they seem useless.
// We do not want risking to extend 8bit integers to int and then
// endian-converting and casting back to int.
// Thus these overloads.
-static MPT_ENDIAN_CONSTEXPR_FUN uint8 SwapBytes(uint8 value) noexcept { return value; }
-static MPT_ENDIAN_CONSTEXPR_FUN int8 SwapBytes(int8 value) noexcept { return value; }
-static MPT_ENDIAN_CONSTEXPR_FUN char SwapBytes(char value) noexcept { return value; }
+static MPT_CONSTEXPR20_FUN uint8 SwapBytes(uint8 value) noexcept { return value; }
+static MPT_CONSTEXPR20_FUN int8 SwapBytes(int8 value) noexcept { return value; }
+static MPT_CONSTEXPR20_FUN char SwapBytes(char value) noexcept { return value; }
} // namespace detail
} // namespace mpt
+#undef MPT_constexpr_bswap16
+#undef MPT_constexpr_bswap32
+#undef MPT_constexpr_bswap64
+
#undef MPT_bswap16
#undef MPT_bswap32
#undef MPT_bswap64
@@ -912,16 +871,13 @@
using base_type = T;
using endian_type = Tendian;
public:
-#if MPT_ENDIAN_IS_CONSTEXPR
- std::array<std::byte, sizeof(base_type)> data{};
-#else // !MPT_ENDIAN_IS_CONSTEXPR
std::array<std::byte, sizeof(base_type)> data;
-#endif // MPT_ENDIAN_IS_CONSTEXPR
public:
- MPT_ENDIAN_CONSTEXPR_FUN void set(base_type val) noexcept
+ MPT_CONSTEXPR20_FUN void set(base_type val) noexcept
{
static_assert(std::numeric_limits<T>::is_integer);
- #if MPT_ENDIAN_IS_CONSTEXPR
+ MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20())
+ {
if constexpr(endian_type::endian == mpt::endian::big)
{
typename std::make_unsigned<base_type>::type uval = val;
@@ -937,7 +893,8 @@
data[i] = static_cast<std::byte>((uval >> (8*i)) & 0xffu);
}
}
- #else // !MPT_ENDIAN_IS_CONSTEXPR
+ } else
+ {
if constexpr(mpt::endian::native == mpt::endian::little || mpt::endian::native == mpt::endian::big)
{
if constexpr(mpt::endian::native != endian_type::endian)
@@ -950,12 +907,13 @@
using unsigned_base_type = typename std::make_unsigned<base_type>::type;
data = EndianEncode<unsigned_base_type, Tendian, sizeof(T)>(val);
}
- #endif // MPT_ENDIAN_IS_CONSTEXPR
+ }
}
- MPT_ENDIAN_CONSTEXPR_FUN base_type get() const noexcept
+ MPT_CONSTEXPR20_FUN base_type get() const noexcept
{
static_assert(std::numeric_limits<T>::is_integer);
- #if MPT_ENDIAN_IS_CONSTEXPR
+ MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20())
+ {
if constexpr(endian_type::endian == mpt::endian::big)
{
typename std::make_unsigned<base_type>::type uval = 0;
@@ -973,7 +931,8 @@
}
return static_cast<base_type>(uval);
}
- #else // !MPT_ENDIAN_IS_CONSTEXPR
+ } else
+ {
if constexpr(mpt::endian::native == mpt::endian::little || mpt::endian::native == mpt::endian::big)
{
base_type val = base_type();
@@ -988,23 +947,23 @@
using unsigned_base_type = typename std::make_unsigned<base_type>::type;
return EndianDecode<unsigned_base_type, Tendian, sizeof(T)>(data);
}
- #endif // MPT_ENDIAN_IS_CONSTEXPR
+ }
}
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator = (const base_type & val) noexcept { set(val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN operator base_type () const noexcept { return get(); }
+ MPT_CONSTEXPR20_FUN packed & operator = (const base_type & val) noexcept { set(val); return *this; }
+ MPT_CONSTEXPR20_FUN operator base_type () const noexcept { return get(); }
public:
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator &= (base_type val) noexcept { set(get() & val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator |= (base_type val) noexcept { set(get() | val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator ^= (base_type val) noexcept { set(get() ^ val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator += (base_type val) noexcept { set(get() + val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator -= (base_type val) noexcept { set(get() - val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator *= (base_type val) noexcept { set(get() * val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator /= (base_type val) noexcept { set(get() / val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator %= (base_type val) noexcept { set(get() % val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator ++ () noexcept { set(get() + 1); return *this; } // prefix
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator -- () noexcept { set(get() - 1); return *this; } // prefix
- MPT_ENDIAN_CONSTEXPR_FUN base_type operator ++ (int) noexcept { base_type old = get(); set(old + 1); return old; } // postfix
- MPT_ENDIAN_CONSTEXPR_FUN base_type operator -- (int) noexcept { base_type old = get(); set(old - 1); return old; } // postfix
+ MPT_CONSTEXPR20_FUN packed & operator &= (base_type val) noexcept { set(get() & val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator |= (base_type val) noexcept { set(get() | val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator ^= (base_type val) noexcept { set(get() ^ val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator += (base_type val) noexcept { set(get() + val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator -= (base_type val) noexcept { set(get() - val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator *= (base_type val) noexcept { set(get() * val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator /= (base_type val) noexcept { set(get() / val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator %= (base_type val) noexcept { set(get() % val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator ++ () noexcept { set(get() + 1); return *this; } // prefix
+ MPT_CONSTEXPR20_FUN packed & operator -- () noexcept { set(get() - 1); return *this; } // prefix
+ MPT_CONSTEXPR20_FUN base_type operator ++ (int) noexcept { base_type old = get(); set(old + 1); return old; } // postfix
+ MPT_CONSTEXPR20_FUN base_type operator -- (int) noexcept { base_type old = get(); set(old - 1); return old; } // postfix
};
using int64le = packed< int64, LittleEndian_tag>;
@@ -1053,24 +1012,24 @@
template <typename T> struct make_be { using type = packed<typename std::remove_const<T>::type, BigEndian_tag>; };
template <typename T>
-MPT_ENDIAN_CONSTEXPR_FUN auto as_le(T v) noexcept -> typename mpt::make_le<typename std::remove_const<T>::type>::type
+MPT_CONSTEXPR14_FUN auto as_le(T v) noexcept -> typename mpt::make_le<typename std::remove_const<T>::type>::type
{
- typename mpt::make_le<typename std::remove_const<T>::type>::type res;
+ typename mpt::make_le<typename std::remove_const<T>::type>::type res{};
res = v;
return res;
}
template <typename T>
-MPT_ENDIAN_CONSTEXPR_FUN auto as_be(T v) noexcept -> typename mpt::make_be<typename std::remove_const<T>::type>::type
+MPT_CONSTEXPR14_FUN auto as_be(T v) noexcept -> typename mpt::make_be<typename std::remove_const<T>::type>::type
{
- typename mpt::make_be<typename std::remove_const<T>::type>::type res;
+ typename mpt::make_be<typename std::remove_const<T>::type>::type res{};
res = v;
return res;
}
template <typename Tpacked>
-MPT_ENDIAN_CONSTEXPR_FUN Tpacked as_endian(typename Tpacked::base_type v) noexcept
+MPT_CONSTEXPR14_FUN Tpacked as_endian(typename Tpacked::base_type v) noexcept
{
- Tpacked res;
+ Tpacked res{};
res = v;
return res;
}
Index: common/mptBaseMacros.h
===================================================================
--- common/mptBaseMacros.h (revision 12225)
+++ common/mptBaseMacros.h (working copy)
@@ -51,7 +51,16 @@
#define MPT_CONSTEXPR14_VAR constexpr
#define MPT_CONSTEXPR17_FUN constexpr MPT_FORCEINLINE
#define MPT_CONSTEXPR17_VAR constexpr
+#if MPT_CXX_AT_LEAST(20)
+#define MPT_CONSTEXPR20_FUN constexpr MPT_FORCEINLINE
+#define MPT_CONSTEXPR20_VAR constexpr
+#else // !C++20
+#define MPT_CONSTEXPR20_FUN MPT_FORCEINLINE
+#define MPT_CONSTEXPR20_VAR const
+#endif // C++20
+
+
namespace mpt
{
template <auto V> struct constant_value { static constexpr decltype(V) value() { return V; } };
@@ -61,10 +70,12 @@
#if MPT_CXX_AT_LEAST(20)
+#define MPT_IS_CONSTANT_EVALUATED20() std::is_constant_evaluated()
#define MPT_IS_CONSTANT_EVALUATED() std::is_constant_evaluated()
#else // !C++20
// this pessimizes the case for C++17 by always assuming constexpr context, which implies always running constexpr-friendly code
-#define MPT_IS_CONSTANT_EVALUATED() true
+#define MPT_IS_CONSTANT_EVALUATED20() true
+#define MPT_IS_CONSTANT_EVALUATED() false
#endif // C++20
endian-cpp20-v3.patch (17,934 bytes)
Index: common/Endianness.h
===================================================================
--- common/Endianness.h (revision 12225)
+++ common/Endianness.h (working copy)
@@ -13,6 +13,9 @@
#include "BuildSettings.h"
#include <array>
+#if MPT_CXX_AT_LEAST(20)
+#include <bit>
+#endif // C++20
#include <limits>
#include <cmath>
@@ -27,16 +30,44 @@
+OPENMPT_NAMESPACE_BEGIN
+
+
+
+namespace mpt {
+
+
+
#if MPT_CXX_AT_LEAST(20)
-// nothing
+using std::endian;
-#elif MPT_COMPILER_GENERIC
+static_assert(mpt::endian::big != mpt::endian::little, "platform with all scalar types having size 1 is not supported");
-// rely on runtime detection instead of using non-standard macros
+static constexpr mpt::endian get_endian() noexcept
+{
+ return mpt::endian::native;
+}
-#else
+static constexpr bool endian_is_little() noexcept
+{
+ return get_endian() == mpt::endian::little;
+}
+static constexpr bool endian_is_big() noexcept
+{
+ return get_endian() == mpt::endian::big;
+}
+
+static constexpr bool endian_is_weird() noexcept
+{
+ return !endian_is_little() && !endian_is_big();
+}
+
+#else // !C++20
+
+#if !MPT_COMPILER_GENERIC
+
#if MPT_COMPILER_MSVC
#define MPT_PLATFORM_LITTLE_ENDIAN
#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG
@@ -75,101 +106,26 @@
#endif
#endif
-#endif
+#endif // !MPT_COMPILER_GENERIC
-#if defined(MPT_PLATFORM_BIG_ENDIAN) || defined(MPT_PLATFORM_LITTLE_ENDIAN)
-#define MPT_PLATFORM_ENDIAN_KNOWN 1
-#else
-#define MPT_PLATFORM_ENDIAN_KNOWN 0
-#endif
-
-
-
-#if MPT_PLATFORM_ENDIAN_KNOWN
-//#define MPT_ENDIAN_IS_CONSTEXPR 1
-// For now, we do not want to use constexpr endianness functions and types.
-// It bloats the binary size somewhat (possibly because of either the zeroing
-// constructor or because of not being able to use byteswap intrinsics) and has
-// currently no compelling benefit for us
-#define MPT_ENDIAN_IS_CONSTEXPR 0
-#else
-#define MPT_ENDIAN_IS_CONSTEXPR 0
-#endif
-
-#if MPT_ENDIAN_IS_CONSTEXPR
-#define MPT_ENDIAN_CONSTEXPR_FUN MPT_CONSTEXPR14_FUN
-#define MPT_ENDIAN_CONSTEXPR_VAR MPT_CONSTEXPR14_VAR
-#else
-#define MPT_ENDIAN_CONSTEXPR_FUN MPT_FORCEINLINE
-#define MPT_ENDIAN_CONSTEXPR_VAR const
-#endif
-
-
-
-OPENMPT_NAMESPACE_BEGIN
-
-
-
-namespace mpt {
-
-
-
-// C++20 std::endian
-#if MPT_CXX_AT_LEAST(20)
-using std::endian;
-static_assert(mpt::endian::big != mpt::endian::little, "platform with all scalar types having size 1 is not supported");
-#else // !C++20
enum class endian
{
little = 0x78563412u,
big = 0x12345678u,
weird = 1u,
-#if MPT_PLATFORM_ENDIAN_KNOWN && defined(MPT_PLATFORM_LITTLE_ENDIAN)
- native = little
-#elif MPT_PLATFORM_ENDIAN_KNOWN && defined(MPT_PLATFORM_BIG_ENDIAN)
- native = big
+#if MPT_COMPILER_GENERIC
+ native = 0u,
+#elif defined(MPT_PLATFORM_LITTLE_ENDIAN)
+ native = little,
+#elif defined(MPT_PLATFORM_BIG_ENDIAN)
+ native = big,
#else
- native = 0u
+ native = 0u,
#endif
};
-#endif // C++20
-MPT_CONSTEXPR11_FUN bool endian_known() noexcept
-{
- return ((mpt::endian::native == mpt::endian::little) || (mpt::endian::native == mpt::endian::big));
-}
+static_assert(mpt::endian::big != mpt::endian::little, "platform with all scalar types having size 1 is not supported");
-MPT_CONSTEXPR11_FUN bool endian_unknown() noexcept
-{
- return ((mpt::endian::native != mpt::endian::little) && (mpt::endian::native != mpt::endian::big));
-}
-
-
-
-#if MPT_CXX_AT_LEAST(20)
-
-static MPT_CONSTEXPR11_FUN mpt::endian get_endian() noexcept
-{
- return mpt::endian::native;
-}
-
-static MPT_CONSTEXPR11_FUN bool endian_is_little() noexcept
-{
- return get_endian() == mpt::endian::little;
-}
-
-static MPT_CONSTEXPR11_FUN bool endian_is_big() noexcept
-{
- return get_endian() == mpt::endian::big;
-}
-
-static MPT_CONSTEXPR11_FUN bool endian_is_weird() noexcept
-{
- return !endian_is_little() && !endian_is_big();
-}
-
-#else // !C++20
-
namespace detail {
static MPT_FORCEINLINE mpt::endian endian_probe() noexcept
@@ -178,9 +134,8 @@
static_assert(sizeof(endian_probe_type) == 4);
constexpr endian_probe_type endian_probe_big = 0x12345678u;
constexpr endian_probe_type endian_probe_little = 0x78563412u;
- const std::byte probe[sizeof(endian_probe_type)] = { mpt::as_byte(0x12), mpt::as_byte(0x34), mpt::as_byte(0x56), mpt::as_byte(0x78) };
- endian_probe_type test;
- std::memcpy(&test, probe, sizeof(endian_probe_type));
+ const std::array<std::byte, sizeof(endian_probe_type)> probe{ mpt::as_byte(0x12), mpt::as_byte(0x34), mpt::as_byte(0x56), mpt::as_byte(0x78) };
+ const endian_probe_type test = mpt::bit_cast<endian_probe_type>(probe);
mpt::endian result = mpt::endian::native;
switch(test)
{
@@ -197,11 +152,11 @@
return result;
}
-}
+} // namespace detail
static MPT_FORCEINLINE mpt::endian get_endian() noexcept
{
- if constexpr(mpt::endian_known())
+ if constexpr((mpt::endian::native == mpt::endian::little) || (mpt::endian::native == mpt::endian::big))
{
return mpt::endian::native;
} else
@@ -262,7 +217,32 @@
-#if !MPT_ENDIAN_IS_CONSTEXPR
+#define MPT_constexpr_bswap16(x) \
+ ( uint16(0) \
+ | ((static_cast<uint16>(x) >> 8) & 0x00FFu) \
+ | ((static_cast<uint16>(x) << 8) & 0xFF00u) \
+ ) \
+/**/
+#define MPT_constexpr_bswap32(x) \
+ ( uint32(0) \
+ | ((static_cast<uint32>(x) & 0x000000FFu) << 24) \
+ | ((static_cast<uint32>(x) & 0x0000FF00u) << 8) \
+ | ((static_cast<uint32>(x) & 0x00FF0000u) >> 8) \
+ | ((static_cast<uint32>(x) & 0xFF000000u) >> 24) \
+ ) \
+/**/
+#define MPT_constexpr_bswap64(x) \
+ ( uint64(0) \
+ | (((static_cast<uint64>(x) >> 0) & 0xffull) << 56) \
+ | (((static_cast<uint64>(x) >> 8) & 0xffull) << 48) \
+ | (((static_cast<uint64>(x) >> 16) & 0xffull) << 40) \
+ | (((static_cast<uint64>(x) >> 24) & 0xffull) << 32) \
+ | (((static_cast<uint64>(x) >> 32) & 0xffull) << 24) \
+ | (((static_cast<uint64>(x) >> 40) & 0xffull) << 16) \
+ | (((static_cast<uint64>(x) >> 48) & 0xffull) << 8) \
+ | (((static_cast<uint64>(x) >> 56) & 0xffull) << 0) \
+ ) \
+/**/
#if MPT_COMPILER_GCC
#define MPT_bswap16 __builtin_bswap16
@@ -296,44 +276,19 @@
#endif
} } // namespace mpt::detail
-#endif // !MPT_ENDIAN_IS_CONSTEXPR
-
-
// No intrinsics available
#ifndef MPT_bswap16
-#define MPT_bswap16(x) \
- ( uint16(0) \
- | ((static_cast<uint16>(x) >> 8) & 0x00FFu) \
- | ((static_cast<uint16>(x) << 8) & 0xFF00u) \
- ) \
-/**/
+#define MPT_bswap16(x) MPT_constexpr_bswap16(x)
#endif
#ifndef MPT_bswap32
-#define MPT_bswap32(x) \
- ( uint32(0) \
- | ((static_cast<uint32>(x) & 0x000000FFu) << 24) \
- | ((static_cast<uint32>(x) & 0x0000FF00u) << 8) \
- | ((static_cast<uint32>(x) & 0x00FF0000u) >> 8) \
- | ((static_cast<uint32>(x) & 0xFF000000u) >> 24) \
- ) \
-/**/
+#define MPT_bswap32(x) MPT_constexpr_bswap32(x)
#endif
#ifndef MPT_bswap64
-#define MPT_bswap64(x) \
- ( uint64(0) \
- | (((static_cast<uint64>(x) >> 0) & 0xffull) << 56) \
- | (((static_cast<uint64>(x) >> 8) & 0xffull) << 48) \
- | (((static_cast<uint64>(x) >> 16) & 0xffull) << 40) \
- | (((static_cast<uint64>(x) >> 24) & 0xffull) << 32) \
- | (((static_cast<uint64>(x) >> 32) & 0xffull) << 24) \
- | (((static_cast<uint64>(x) >> 40) & 0xffull) << 16) \
- | (((static_cast<uint64>(x) >> 48) & 0xffull) << 8) \
- | (((static_cast<uint64>(x) >> 56) & 0xffull) << 0) \
- ) \
-/**/
+#define MPT_bswap64(x) MPT_constexpr_bswap64(x)
#endif
+
template <typename T, typename Tendian, std::size_t size>
static MPT_CONSTEXPR17_FUN std::array<std::byte, size> EndianEncode(T val) noexcept
{
@@ -397,24 +352,28 @@
namespace detail
{
-static MPT_ENDIAN_CONSTEXPR_FUN uint64 SwapBytes(uint64 value) noexcept { return MPT_bswap64(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN uint32 SwapBytes(uint32 value) noexcept { return MPT_bswap32(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN uint16 SwapBytes(uint16 value) noexcept { return MPT_bswap16(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN int64 SwapBytes(int64 value) noexcept { return MPT_bswap64(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN int32 SwapBytes(int32 value) noexcept { return MPT_bswap32(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN int16 SwapBytes(int16 value) noexcept { return MPT_bswap16(value); }
+static MPT_CONSTEXPR20_FUN uint64 SwapBytes(uint64 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap64(value); } else { return MPT_bswap64(value); } }
+static MPT_CONSTEXPR20_FUN uint32 SwapBytes(uint32 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap32(value); } else { return MPT_bswap32(value); } }
+static MPT_CONSTEXPR20_FUN uint16 SwapBytes(uint16 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap16(value); } else { return MPT_bswap16(value); } }
+static MPT_CONSTEXPR20_FUN int64 SwapBytes(int64 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap64(value); } else { return MPT_bswap64(value); } }
+static MPT_CONSTEXPR20_FUN int32 SwapBytes(int32 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap32(value); } else { return MPT_bswap32(value); } }
+static MPT_CONSTEXPR20_FUN int16 SwapBytes(int16 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap16(value); } else { return MPT_bswap16(value); } }
// Do NOT remove these overloads, even if they seem useless.
// We do not want risking to extend 8bit integers to int and then
// endian-converting and casting back to int.
// Thus these overloads.
-static MPT_ENDIAN_CONSTEXPR_FUN uint8 SwapBytes(uint8 value) noexcept { return value; }
-static MPT_ENDIAN_CONSTEXPR_FUN int8 SwapBytes(int8 value) noexcept { return value; }
-static MPT_ENDIAN_CONSTEXPR_FUN char SwapBytes(char value) noexcept { return value; }
+static MPT_CONSTEXPR20_FUN uint8 SwapBytes(uint8 value) noexcept { return value; }
+static MPT_CONSTEXPR20_FUN int8 SwapBytes(int8 value) noexcept { return value; }
+static MPT_CONSTEXPR20_FUN char SwapBytes(char value) noexcept { return value; }
} // namespace detail
} // namespace mpt
+#undef MPT_constexpr_bswap16
+#undef MPT_constexpr_bswap32
+#undef MPT_constexpr_bswap64
+
#undef MPT_bswap16
#undef MPT_bswap32
#undef MPT_bswap64
@@ -912,16 +871,13 @@
using base_type = T;
using endian_type = Tendian;
public:
-#if MPT_ENDIAN_IS_CONSTEXPR
- std::array<std::byte, sizeof(base_type)> data{};
-#else // !MPT_ENDIAN_IS_CONSTEXPR
std::array<std::byte, sizeof(base_type)> data;
-#endif // MPT_ENDIAN_IS_CONSTEXPR
public:
- MPT_ENDIAN_CONSTEXPR_FUN void set(base_type val) noexcept
+ MPT_CONSTEXPR20_FUN void set(base_type val) noexcept
{
static_assert(std::numeric_limits<T>::is_integer);
- #if MPT_ENDIAN_IS_CONSTEXPR
+ MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20())
+ {
if constexpr(endian_type::endian == mpt::endian::big)
{
typename std::make_unsigned<base_type>::type uval = val;
@@ -937,7 +893,8 @@
data[i] = static_cast<std::byte>((uval >> (8*i)) & 0xffu);
}
}
- #else // !MPT_ENDIAN_IS_CONSTEXPR
+ } else
+ {
if constexpr(mpt::endian::native == mpt::endian::little || mpt::endian::native == mpt::endian::big)
{
if constexpr(mpt::endian::native != endian_type::endian)
@@ -950,12 +907,13 @@
using unsigned_base_type = typename std::make_unsigned<base_type>::type;
data = EndianEncode<unsigned_base_type, Tendian, sizeof(T)>(val);
}
- #endif // MPT_ENDIAN_IS_CONSTEXPR
+ }
}
- MPT_ENDIAN_CONSTEXPR_FUN base_type get() const noexcept
+ MPT_CONSTEXPR20_FUN base_type get() const noexcept
{
static_assert(std::numeric_limits<T>::is_integer);
- #if MPT_ENDIAN_IS_CONSTEXPR
+ MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20())
+ {
if constexpr(endian_type::endian == mpt::endian::big)
{
typename std::make_unsigned<base_type>::type uval = 0;
@@ -973,7 +931,8 @@
}
return static_cast<base_type>(uval);
}
- #else // !MPT_ENDIAN_IS_CONSTEXPR
+ } else
+ {
if constexpr(mpt::endian::native == mpt::endian::little || mpt::endian::native == mpt::endian::big)
{
base_type val = base_type();
@@ -988,23 +947,23 @@
using unsigned_base_type = typename std::make_unsigned<base_type>::type;
return EndianDecode<unsigned_base_type, Tendian, sizeof(T)>(data);
}
- #endif // MPT_ENDIAN_IS_CONSTEXPR
+ }
}
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator = (const base_type & val) noexcept { set(val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN operator base_type () const noexcept { return get(); }
+ MPT_CONSTEXPR20_FUN packed & operator = (const base_type & val) noexcept { set(val); return *this; }
+ MPT_CONSTEXPR20_FUN operator base_type () const noexcept { return get(); }
public:
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator &= (base_type val) noexcept { set(get() & val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator |= (base_type val) noexcept { set(get() | val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator ^= (base_type val) noexcept { set(get() ^ val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator += (base_type val) noexcept { set(get() + val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator -= (base_type val) noexcept { set(get() - val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator *= (base_type val) noexcept { set(get() * val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator /= (base_type val) noexcept { set(get() / val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator %= (base_type val) noexcept { set(get() % val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator ++ () noexcept { set(get() + 1); return *this; } // prefix
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator -- () noexcept { set(get() - 1); return *this; } // prefix
- MPT_ENDIAN_CONSTEXPR_FUN base_type operator ++ (int) noexcept { base_type old = get(); set(old + 1); return old; } // postfix
- MPT_ENDIAN_CONSTEXPR_FUN base_type operator -- (int) noexcept { base_type old = get(); set(old - 1); return old; } // postfix
+ MPT_CONSTEXPR20_FUN packed & operator &= (base_type val) noexcept { set(get() & val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator |= (base_type val) noexcept { set(get() | val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator ^= (base_type val) noexcept { set(get() ^ val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator += (base_type val) noexcept { set(get() + val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator -= (base_type val) noexcept { set(get() - val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator *= (base_type val) noexcept { set(get() * val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator /= (base_type val) noexcept { set(get() / val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator %= (base_type val) noexcept { set(get() % val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator ++ () noexcept { set(get() + 1); return *this; } // prefix
+ MPT_CONSTEXPR20_FUN packed & operator -- () noexcept { set(get() - 1); return *this; } // prefix
+ MPT_CONSTEXPR20_FUN base_type operator ++ (int) noexcept { base_type old = get(); set(old + 1); return old; } // postfix
+ MPT_CONSTEXPR20_FUN base_type operator -- (int) noexcept { base_type old = get(); set(old - 1); return old; } // postfix
};
using int64le = packed< int64, LittleEndian_tag>;
@@ -1053,24 +1012,24 @@
template <typename T> struct make_be { using type = packed<typename std::remove_const<T>::type, BigEndian_tag>; };
template <typename T>
-MPT_ENDIAN_CONSTEXPR_FUN auto as_le(T v) noexcept -> typename mpt::make_le<typename std::remove_const<T>::type>::type
+MPT_CONSTEXPR14_FUN auto as_le(T v) noexcept -> typename mpt::make_le<typename std::remove_const<T>::type>::type
{
- typename mpt::make_le<typename std::remove_const<T>::type>::type res;
+ typename mpt::make_le<typename std::remove_const<T>::type>::type res{};
res = v;
return res;
}
template <typename T>
-MPT_ENDIAN_CONSTEXPR_FUN auto as_be(T v) noexcept -> typename mpt::make_be<typename std::remove_const<T>::type>::type
+MPT_CONSTEXPR14_FUN auto as_be(T v) noexcept -> typename mpt::make_be<typename std::remove_const<T>::type>::type
{
- typename mpt::make_be<typename std::remove_const<T>::type>::type res;
+ typename mpt::make_be<typename std::remove_const<T>::type>::type res{};
res = v;
return res;
}
template <typename Tpacked>
-MPT_ENDIAN_CONSTEXPR_FUN Tpacked as_endian(typename Tpacked::base_type v) noexcept
+MPT_CONSTEXPR14_FUN Tpacked as_endian(typename Tpacked::base_type v) noexcept
{
- Tpacked res;
+ Tpacked res{};
res = v;
return res;
}
Index: common/mptBaseMacros.h
===================================================================
--- common/mptBaseMacros.h (revision 12225)
+++ common/mptBaseMacros.h (working copy)
@@ -51,7 +51,16 @@
#define MPT_CONSTEXPR14_VAR constexpr
#define MPT_CONSTEXPR17_FUN constexpr MPT_FORCEINLINE
#define MPT_CONSTEXPR17_VAR constexpr
+#if MPT_CXX_AT_LEAST(20)
+#define MPT_CONSTEXPR20_FUN constexpr MPT_FORCEINLINE
+#define MPT_CONSTEXPR20_VAR constexpr
+#else // !C++20
+#define MPT_CONSTEXPR20_FUN MPT_FORCEINLINE
+#define MPT_CONSTEXPR20_VAR const
+#endif // C++20
+
+
namespace mpt
{
template <auto V> struct constant_value { static constexpr decltype(V) value() { return V; } };
@@ -61,8 +70,10 @@
#if MPT_CXX_AT_LEAST(20)
+#define MPT_IS_CONSTANT_EVALUATED20() std::is_constant_evaluated()
#define MPT_IS_CONSTANT_EVALUATED() std::is_constant_evaluated()
#else // !C++20
+#define MPT_IS_CONSTANT_EVALUATED20() false
// this pessimizes the case for C++17 by always assuming constexpr context, which implies always running constexpr-friendly code
#define MPT_IS_CONSTANT_EVALUATED() true
#endif // C++20
endian-cpp20-v4.patch (17,934 bytes)
Index: common/Endianness.h
===================================================================
--- common/Endianness.h (revision 12227)
+++ common/Endianness.h (working copy)
@@ -13,6 +13,9 @@
#include "BuildSettings.h"
#include <array>
+#if MPT_CXX_AT_LEAST(20)
+#include <bit>
+#endif // C++20
#include <limits>
#include <cmath>
@@ -27,16 +30,44 @@
+OPENMPT_NAMESPACE_BEGIN
+
+
+
+namespace mpt {
+
+
+
#if MPT_CXX_AT_LEAST(20)
-// nothing
+using std::endian;
-#elif MPT_COMPILER_GENERIC
+static_assert(mpt::endian::big != mpt::endian::little, "platform with all scalar types having size 1 is not supported");
-// rely on runtime detection instead of using non-standard macros
+static constexpr mpt::endian get_endian() noexcept
+{
+ return mpt::endian::native;
+}
-#else
+static constexpr bool endian_is_little() noexcept
+{
+ return get_endian() == mpt::endian::little;
+}
+static constexpr bool endian_is_big() noexcept
+{
+ return get_endian() == mpt::endian::big;
+}
+
+static constexpr bool endian_is_weird() noexcept
+{
+ return !endian_is_little() && !endian_is_big();
+}
+
+#else // !C++20
+
+#if !MPT_COMPILER_GENERIC
+
#if MPT_COMPILER_MSVC
#define MPT_PLATFORM_LITTLE_ENDIAN
#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG
@@ -75,101 +106,26 @@
#endif
#endif
-#endif
+#endif // !MPT_COMPILER_GENERIC
-#if defined(MPT_PLATFORM_BIG_ENDIAN) || defined(MPT_PLATFORM_LITTLE_ENDIAN)
-#define MPT_PLATFORM_ENDIAN_KNOWN 1
-#else
-#define MPT_PLATFORM_ENDIAN_KNOWN 0
-#endif
-
-
-
-#if MPT_PLATFORM_ENDIAN_KNOWN
-//#define MPT_ENDIAN_IS_CONSTEXPR 1
-// For now, we do not want to use constexpr endianness functions and types.
-// It bloats the binary size somewhat (possibly because of either the zeroing
-// constructor or because of not being able to use byteswap intrinsics) and has
-// currently no compelling benefit for us
-#define MPT_ENDIAN_IS_CONSTEXPR 0
-#else
-#define MPT_ENDIAN_IS_CONSTEXPR 0
-#endif
-
-#if MPT_ENDIAN_IS_CONSTEXPR
-#define MPT_ENDIAN_CONSTEXPR_FUN MPT_CONSTEXPR14_FUN
-#define MPT_ENDIAN_CONSTEXPR_VAR MPT_CONSTEXPR14_VAR
-#else
-#define MPT_ENDIAN_CONSTEXPR_FUN MPT_FORCEINLINE
-#define MPT_ENDIAN_CONSTEXPR_VAR const
-#endif
-
-
-
-OPENMPT_NAMESPACE_BEGIN
-
-
-
-namespace mpt {
-
-
-
-// C++20 std::endian
-#if MPT_CXX_AT_LEAST(20)
-using std::endian;
-static_assert(mpt::endian::big != mpt::endian::little, "platform with all scalar types having size 1 is not supported");
-#else // !C++20
enum class endian
{
little = 0x78563412u,
big = 0x12345678u,
weird = 1u,
-#if MPT_PLATFORM_ENDIAN_KNOWN && defined(MPT_PLATFORM_LITTLE_ENDIAN)
- native = little
-#elif MPT_PLATFORM_ENDIAN_KNOWN && defined(MPT_PLATFORM_BIG_ENDIAN)
- native = big
+#if MPT_COMPILER_GENERIC
+ native = 0u,
+#elif defined(MPT_PLATFORM_LITTLE_ENDIAN)
+ native = little,
+#elif defined(MPT_PLATFORM_BIG_ENDIAN)
+ native = big,
#else
- native = 0u
+ native = 0u,
#endif
};
-#endif // C++20
-MPT_CONSTEXPR11_FUN bool endian_known() noexcept
-{
- return ((mpt::endian::native == mpt::endian::little) || (mpt::endian::native == mpt::endian::big));
-}
+static_assert(mpt::endian::big != mpt::endian::little, "platform with all scalar types having size 1 is not supported");
-MPT_CONSTEXPR11_FUN bool endian_unknown() noexcept
-{
- return ((mpt::endian::native != mpt::endian::little) && (mpt::endian::native != mpt::endian::big));
-}
-
-
-
-#if MPT_CXX_AT_LEAST(20)
-
-static MPT_CONSTEXPR11_FUN mpt::endian get_endian() noexcept
-{
- return mpt::endian::native;
-}
-
-static MPT_CONSTEXPR11_FUN bool endian_is_little() noexcept
-{
- return get_endian() == mpt::endian::little;
-}
-
-static MPT_CONSTEXPR11_FUN bool endian_is_big() noexcept
-{
- return get_endian() == mpt::endian::big;
-}
-
-static MPT_CONSTEXPR11_FUN bool endian_is_weird() noexcept
-{
- return !endian_is_little() && !endian_is_big();
-}
-
-#else // !C++20
-
namespace detail {
static MPT_FORCEINLINE mpt::endian endian_probe() noexcept
@@ -178,9 +134,8 @@
static_assert(sizeof(endian_probe_type) == 4);
constexpr endian_probe_type endian_probe_big = 0x12345678u;
constexpr endian_probe_type endian_probe_little = 0x78563412u;
- const std::byte probe[sizeof(endian_probe_type)] = { mpt::as_byte(0x12), mpt::as_byte(0x34), mpt::as_byte(0x56), mpt::as_byte(0x78) };
- endian_probe_type test;
- std::memcpy(&test, probe, sizeof(endian_probe_type));
+ const std::array<std::byte, sizeof(endian_probe_type)> probe{ mpt::as_byte(0x12), mpt::as_byte(0x34), mpt::as_byte(0x56), mpt::as_byte(0x78) };
+ const endian_probe_type test = mpt::bit_cast<endian_probe_type>(probe);
mpt::endian result = mpt::endian::native;
switch(test)
{
@@ -197,11 +152,11 @@
return result;
}
-}
+} // namespace detail
static MPT_FORCEINLINE mpt::endian get_endian() noexcept
{
- if constexpr(mpt::endian_known())
+ if constexpr((mpt::endian::native == mpt::endian::little) || (mpt::endian::native == mpt::endian::big))
{
return mpt::endian::native;
} else
@@ -262,7 +217,32 @@
-#if !MPT_ENDIAN_IS_CONSTEXPR
+#define MPT_constexpr_bswap16(x) \
+ ( uint16(0) \
+ | ((static_cast<uint16>(x) >> 8) & 0x00FFu) \
+ | ((static_cast<uint16>(x) << 8) & 0xFF00u) \
+ ) \
+/**/
+#define MPT_constexpr_bswap32(x) \
+ ( uint32(0) \
+ | ((static_cast<uint32>(x) & 0x000000FFu) << 24) \
+ | ((static_cast<uint32>(x) & 0x0000FF00u) << 8) \
+ | ((static_cast<uint32>(x) & 0x00FF0000u) >> 8) \
+ | ((static_cast<uint32>(x) & 0xFF000000u) >> 24) \
+ ) \
+/**/
+#define MPT_constexpr_bswap64(x) \
+ ( uint64(0) \
+ | (((static_cast<uint64>(x) >> 0) & 0xffull) << 56) \
+ | (((static_cast<uint64>(x) >> 8) & 0xffull) << 48) \
+ | (((static_cast<uint64>(x) >> 16) & 0xffull) << 40) \
+ | (((static_cast<uint64>(x) >> 24) & 0xffull) << 32) \
+ | (((static_cast<uint64>(x) >> 32) & 0xffull) << 24) \
+ | (((static_cast<uint64>(x) >> 40) & 0xffull) << 16) \
+ | (((static_cast<uint64>(x) >> 48) & 0xffull) << 8) \
+ | (((static_cast<uint64>(x) >> 56) & 0xffull) << 0) \
+ ) \
+/**/
#if MPT_COMPILER_GCC
#define MPT_bswap16 __builtin_bswap16
@@ -296,44 +276,19 @@
#endif
} } // namespace mpt::detail
-#endif // !MPT_ENDIAN_IS_CONSTEXPR
-
-
// No intrinsics available
#ifndef MPT_bswap16
-#define MPT_bswap16(x) \
- ( uint16(0) \
- | ((static_cast<uint16>(x) >> 8) & 0x00FFu) \
- | ((static_cast<uint16>(x) << 8) & 0xFF00u) \
- ) \
-/**/
+#define MPT_bswap16(x) MPT_constexpr_bswap16(x)
#endif
#ifndef MPT_bswap32
-#define MPT_bswap32(x) \
- ( uint32(0) \
- | ((static_cast<uint32>(x) & 0x000000FFu) << 24) \
- | ((static_cast<uint32>(x) & 0x0000FF00u) << 8) \
- | ((static_cast<uint32>(x) & 0x00FF0000u) >> 8) \
- | ((static_cast<uint32>(x) & 0xFF000000u) >> 24) \
- ) \
-/**/
+#define MPT_bswap32(x) MPT_constexpr_bswap32(x)
#endif
#ifndef MPT_bswap64
-#define MPT_bswap64(x) \
- ( uint64(0) \
- | (((static_cast<uint64>(x) >> 0) & 0xffull) << 56) \
- | (((static_cast<uint64>(x) >> 8) & 0xffull) << 48) \
- | (((static_cast<uint64>(x) >> 16) & 0xffull) << 40) \
- | (((static_cast<uint64>(x) >> 24) & 0xffull) << 32) \
- | (((static_cast<uint64>(x) >> 32) & 0xffull) << 24) \
- | (((static_cast<uint64>(x) >> 40) & 0xffull) << 16) \
- | (((static_cast<uint64>(x) >> 48) & 0xffull) << 8) \
- | (((static_cast<uint64>(x) >> 56) & 0xffull) << 0) \
- ) \
-/**/
+#define MPT_bswap64(x) MPT_constexpr_bswap64(x)
#endif
+
template <typename T, typename Tendian, std::size_t size>
static MPT_CONSTEXPR17_FUN std::array<std::byte, size> EndianEncode(T val) noexcept
{
@@ -397,24 +352,28 @@
namespace detail
{
-static MPT_ENDIAN_CONSTEXPR_FUN uint64 SwapBytes(uint64 value) noexcept { return MPT_bswap64(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN uint32 SwapBytes(uint32 value) noexcept { return MPT_bswap32(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN uint16 SwapBytes(uint16 value) noexcept { return MPT_bswap16(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN int64 SwapBytes(int64 value) noexcept { return MPT_bswap64(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN int32 SwapBytes(int32 value) noexcept { return MPT_bswap32(value); }
-static MPT_ENDIAN_CONSTEXPR_FUN int16 SwapBytes(int16 value) noexcept { return MPT_bswap16(value); }
+static MPT_CONSTEXPR20_FUN uint64 SwapBytes(uint64 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap64(value); } else { return MPT_bswap64(value); } }
+static MPT_CONSTEXPR20_FUN uint32 SwapBytes(uint32 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap32(value); } else { return MPT_bswap32(value); } }
+static MPT_CONSTEXPR20_FUN uint16 SwapBytes(uint16 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap16(value); } else { return MPT_bswap16(value); } }
+static MPT_CONSTEXPR20_FUN int64 SwapBytes(int64 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap64(value); } else { return MPT_bswap64(value); } }
+static MPT_CONSTEXPR20_FUN int32 SwapBytes(int32 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap32(value); } else { return MPT_bswap32(value); } }
+static MPT_CONSTEXPR20_FUN int16 SwapBytes(int16 value) noexcept { MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20()) { return MPT_constexpr_bswap16(value); } else { return MPT_bswap16(value); } }
// Do NOT remove these overloads, even if they seem useless.
// We do not want risking to extend 8bit integers to int and then
// endian-converting and casting back to int.
// Thus these overloads.
-static MPT_ENDIAN_CONSTEXPR_FUN uint8 SwapBytes(uint8 value) noexcept { return value; }
-static MPT_ENDIAN_CONSTEXPR_FUN int8 SwapBytes(int8 value) noexcept { return value; }
-static MPT_ENDIAN_CONSTEXPR_FUN char SwapBytes(char value) noexcept { return value; }
+static MPT_CONSTEXPR20_FUN uint8 SwapBytes(uint8 value) noexcept { return value; }
+static MPT_CONSTEXPR20_FUN int8 SwapBytes(int8 value) noexcept { return value; }
+static MPT_CONSTEXPR20_FUN char SwapBytes(char value) noexcept { return value; }
} // namespace detail
} // namespace mpt
+#undef MPT_constexpr_bswap16
+#undef MPT_constexpr_bswap32
+#undef MPT_constexpr_bswap64
+
#undef MPT_bswap16
#undef MPT_bswap32
#undef MPT_bswap64
@@ -912,16 +871,13 @@
using base_type = T;
using endian_type = Tendian;
public:
-#if MPT_ENDIAN_IS_CONSTEXPR
- std::array<std::byte, sizeof(base_type)> data{};
-#else // !MPT_ENDIAN_IS_CONSTEXPR
std::array<std::byte, sizeof(base_type)> data;
-#endif // MPT_ENDIAN_IS_CONSTEXPR
public:
- MPT_ENDIAN_CONSTEXPR_FUN void set(base_type val) noexcept
+ MPT_CONSTEXPR20_FUN void set(base_type val) noexcept
{
static_assert(std::numeric_limits<T>::is_integer);
- #if MPT_ENDIAN_IS_CONSTEXPR
+ MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20())
+ {
if constexpr(endian_type::endian == mpt::endian::big)
{
typename std::make_unsigned<base_type>::type uval = val;
@@ -937,7 +893,8 @@
data[i] = static_cast<std::byte>((uval >> (8*i)) & 0xffu);
}
}
- #else // !MPT_ENDIAN_IS_CONSTEXPR
+ } else
+ {
if constexpr(mpt::endian::native == mpt::endian::little || mpt::endian::native == mpt::endian::big)
{
if constexpr(mpt::endian::native != endian_type::endian)
@@ -950,12 +907,13 @@
using unsigned_base_type = typename std::make_unsigned<base_type>::type;
data = EndianEncode<unsigned_base_type, Tendian, sizeof(T)>(val);
}
- #endif // MPT_ENDIAN_IS_CONSTEXPR
+ }
}
- MPT_ENDIAN_CONSTEXPR_FUN base_type get() const noexcept
+ MPT_CONSTEXPR20_FUN base_type get() const noexcept
{
static_assert(std::numeric_limits<T>::is_integer);
- #if MPT_ENDIAN_IS_CONSTEXPR
+ MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20())
+ {
if constexpr(endian_type::endian == mpt::endian::big)
{
typename std::make_unsigned<base_type>::type uval = 0;
@@ -973,7 +931,8 @@
}
return static_cast<base_type>(uval);
}
- #else // !MPT_ENDIAN_IS_CONSTEXPR
+ } else
+ {
if constexpr(mpt::endian::native == mpt::endian::little || mpt::endian::native == mpt::endian::big)
{
base_type val = base_type();
@@ -988,23 +947,23 @@
using unsigned_base_type = typename std::make_unsigned<base_type>::type;
return EndianDecode<unsigned_base_type, Tendian, sizeof(T)>(data);
}
- #endif // MPT_ENDIAN_IS_CONSTEXPR
+ }
}
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator = (const base_type & val) noexcept { set(val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN operator base_type () const noexcept { return get(); }
+ MPT_CONSTEXPR20_FUN packed & operator = (const base_type & val) noexcept { set(val); return *this; }
+ MPT_CONSTEXPR20_FUN operator base_type () const noexcept { return get(); }
public:
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator &= (base_type val) noexcept { set(get() & val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator |= (base_type val) noexcept { set(get() | val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator ^= (base_type val) noexcept { set(get() ^ val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator += (base_type val) noexcept { set(get() + val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator -= (base_type val) noexcept { set(get() - val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator *= (base_type val) noexcept { set(get() * val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator /= (base_type val) noexcept { set(get() / val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator %= (base_type val) noexcept { set(get() % val); return *this; }
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator ++ () noexcept { set(get() + 1); return *this; } // prefix
- MPT_ENDIAN_CONSTEXPR_FUN packed & operator -- () noexcept { set(get() - 1); return *this; } // prefix
- MPT_ENDIAN_CONSTEXPR_FUN base_type operator ++ (int) noexcept { base_type old = get(); set(old + 1); return old; } // postfix
- MPT_ENDIAN_CONSTEXPR_FUN base_type operator -- (int) noexcept { base_type old = get(); set(old - 1); return old; } // postfix
+ MPT_CONSTEXPR20_FUN packed & operator &= (base_type val) noexcept { set(get() & val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator |= (base_type val) noexcept { set(get() | val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator ^= (base_type val) noexcept { set(get() ^ val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator += (base_type val) noexcept { set(get() + val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator -= (base_type val) noexcept { set(get() - val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator *= (base_type val) noexcept { set(get() * val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator /= (base_type val) noexcept { set(get() / val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator %= (base_type val) noexcept { set(get() % val); return *this; }
+ MPT_CONSTEXPR20_FUN packed & operator ++ () noexcept { set(get() + 1); return *this; } // prefix
+ MPT_CONSTEXPR20_FUN packed & operator -- () noexcept { set(get() - 1); return *this; } // prefix
+ MPT_CONSTEXPR20_FUN base_type operator ++ (int) noexcept { base_type old = get(); set(old + 1); return old; } // postfix
+ MPT_CONSTEXPR20_FUN base_type operator -- (int) noexcept { base_type old = get(); set(old - 1); return old; } // postfix
};
using int64le = packed< int64, LittleEndian_tag>;
@@ -1053,24 +1012,24 @@
template <typename T> struct make_be { using type = packed<typename std::remove_const<T>::type, BigEndian_tag>; };
template <typename T>
-MPT_ENDIAN_CONSTEXPR_FUN auto as_le(T v) noexcept -> typename mpt::make_le<typename std::remove_const<T>::type>::type
+MPT_CONSTEXPR20_FUN auto as_le(T v) noexcept -> typename mpt::make_le<typename std::remove_const<T>::type>::type
{
- typename mpt::make_le<typename std::remove_const<T>::type>::type res;
+ typename mpt::make_le<typename std::remove_const<T>::type>::type res{};
res = v;
return res;
}
template <typename T>
-MPT_ENDIAN_CONSTEXPR_FUN auto as_be(T v) noexcept -> typename mpt::make_be<typename std::remove_const<T>::type>::type
+MPT_CONSTEXPR20_FUN auto as_be(T v) noexcept -> typename mpt::make_be<typename std::remove_const<T>::type>::type
{
- typename mpt::make_be<typename std::remove_const<T>::type>::type res;
+ typename mpt::make_be<typename std::remove_const<T>::type>::type res{};
res = v;
return res;
}
template <typename Tpacked>
-MPT_ENDIAN_CONSTEXPR_FUN Tpacked as_endian(typename Tpacked::base_type v) noexcept
+MPT_CONSTEXPR20_FUN Tpacked as_endian(typename Tpacked::base_type v) noexcept
{
- Tpacked res;
+ Tpacked res{};
res = v;
return res;
}
Index: common/mptBaseMacros.h
===================================================================
--- common/mptBaseMacros.h (revision 12227)
+++ common/mptBaseMacros.h (working copy)
@@ -51,7 +51,16 @@
#define MPT_CONSTEXPR14_VAR constexpr
#define MPT_CONSTEXPR17_FUN constexpr MPT_FORCEINLINE
#define MPT_CONSTEXPR17_VAR constexpr
+#if MPT_CXX_AT_LEAST(20)
+#define MPT_CONSTEXPR20_FUN constexpr MPT_FORCEINLINE
+#define MPT_CONSTEXPR20_VAR constexpr
+#else // !C++20
+#define MPT_CONSTEXPR20_FUN MPT_FORCEINLINE
+#define MPT_CONSTEXPR20_VAR const
+#endif // C++20
+
+
namespace mpt
{
template <auto V> struct constant_value { static constexpr decltype(V) value() { return V; } };
@@ -61,8 +70,10 @@
#if MPT_CXX_AT_LEAST(20)
+#define MPT_IS_CONSTANT_EVALUATED20() std::is_constant_evaluated()
#define MPT_IS_CONSTANT_EVALUATED() std::is_constant_evaluated()
#else // !C++20
+#define MPT_IS_CONSTANT_EVALUATED20() false
// this pessimizes the case for C++17 by always assuming constexpr context, which implies always running constexpr-friendly code
#define MPT_IS_CONSTANT_EVALUATED() true
#endif // C++20
| ||||
| Has the bug occurred in previous versions? | |||||
| Tested code revision (in case you know it) | |||||
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2019-10-14 16:20 | manx | New Issue | |
| 2019-10-14 16:20 | manx | Status | new => assigned |
| 2019-10-14 16:20 | manx | Assigned To | => manx |
| 2019-10-14 16:20 | manx | File Added: endian-cpp20-v1.patch | |
| 2019-10-19 17:01 | manx | File Added: endian-cpp20-v2.patch | |
| 2019-10-19 18:09 | manx | File Added: endian-cpp20-v3.patch | |
| 2019-10-19 18:10 | manx | Note Added: 0004112 | |
| 2019-10-19 18:10 | manx | Target Version | OpenMPT 1.?? (libopenmpt 1.0) (goals) => OpenMPT 1.29.01.00 / libopenmpt 0.5.0 (upgrade first) |
| 2019-10-20 06:59 | manx | File Added: endian-cpp20-v4.patch | |
| 2019-10-20 07:07 | manx | Status | assigned => resolved |
| 2019-10-20 07:07 | manx | Resolution | open => fixed |
| 2019-10-20 07:07 | manx | Fixed in Version | => OpenMPT 1.29.01.00 / libopenmpt 0.5.0 (upgrade first) |
| 2019-10-20 07:07 | manx | Note Added: 0004113 |