diff --git a/include/fstcpp/fstcpp.h b/include/fstcpp/fstcpp.h index 5eb0c7414..e17b33766 100644 --- a/include/fstcpp/fstcpp.h +++ b/include/fstcpp/fstcpp.h @@ -13,6 +13,17 @@ #include // Other libraries' .h files. // Your project's .h files. +#if defined(MSC_VER_) || defined(FORCE_MSC_VER_) +# define USE_GCC_INTRINSIC 0 +// Note: we do not support MSVC intrinsic for now +# define USE_MSVC_INTRINSIC 0 +#elif defined(__GNUC__) || defined(__clang__) +# define USE_GCC_INTRINSIC 1 +# define USE_MSVC_INTRINSIC 0 +#else +# define USE_GCC_INTRINSIC 0 +# define USE_MSVC_INTRINSIC 0 +#endif // Remove these when we upgrade to C++20 #pragma GCC diagnostic ignored "-Wpragmas" diff --git a/include/fstcpp/fstcpp_assertion.h b/include/fstcpp/fstcpp_assertion.h index 1f7265b13..e9606f665 100644 --- a/include/fstcpp/fstcpp_assertion.h +++ b/include/fstcpp/fstcpp_assertion.h @@ -102,16 +102,12 @@ // Compatibility layer for unreachable code hint #if defined(__cplusplus) && __cplusplus >= 202302L -// Prefer the standard library version if available # include # define FST_UNREACHABLE std::unreachable() -#elif defined(__GNUC__) || defined(__clang__) -// --- GCC / Clang --- +#elif USE_GCC_INTRINSIC # define FST_UNREACHABLE __builtin_unreachable() -#elif defined(_MSC_VER) -// --- MSVC --- -# define FST_UNREACHABLE __assume(0) +// TODO: implement MSVC version +// #elif USE_MSVC_INTRINSIC #else -// --- Fallback --- # define FST_UNREACHABLE std::abort() #endif diff --git a/include/fstcpp/fstcpp_stream_write_helper.h b/include/fstcpp/fstcpp_stream_write_helper.h index e3b9158ba..ad2999962 100644 --- a/include/fstcpp/fstcpp_stream_write_helper.h +++ b/include/fstcpp/fstcpp_stream_write_helper.h @@ -6,10 +6,10 @@ #pragma once // direct include // C system headers -#ifdef _MSC_VER -# include -#endif // C++ standard library headers +#if defined(__cplusplus) && __cplusplus >= 202302L +# include +#endif #include #include #include @@ -28,22 +28,24 @@ namespace platform { // clang-format off template U to_big_endian(U u) { return u; } #else -#if defined(__GNUC__) || defined(__clang__) +#if defined(__cplusplus) && __cplusplus >= 202302L +template +U to_big_endian(U u, std::integral_constant) { + return std::byteswap(u); +} +#elif USE_GCC_INTRINSIC template U to_big_endian(U u, std::integral_constant) { return u; } template U to_big_endian(U u, std::integral_constant) { return __builtin_bswap16(u); } template U to_big_endian(U u, std::integral_constant) { return __builtin_bswap32(u); } template U to_big_endian(U u, std::integral_constant) { return __builtin_bswap64(u); } -#elif defined(_MSC_VER) // MSVC -template U to_big_endian(U u, std::integral_constant) { return u; } -template U to_big_endian(U u, std::integral_constant) { return _byteswap_ushort(u); } -template U to_big_endian(U u, std::integral_constant) { return _byteswap_ulong(u); } -template U to_big_endian(U u, std::integral_constant) { return _byteswap_uint64(u); } +// TODO: implement MSVC version +// #elif USE_MSVC_INTRINSIC #else -template U to_big_endian(U u, std::integral_constant) { - U ret{ 0 }; +template +U to_big_endian(U u, std::integral_constant) { + U ret{0}; for (size_t i = 0; i < S; ++i) { - ret |= u & 0xff; - ret <<= 8; + ret = (ret << 8) | (u & 0xff); u >>= 8; } return ret; diff --git a/include/fstcpp/fstcpp_variable_info.h b/include/fstcpp/fstcpp_variable_info.h index f707aaaa8..470bb8ef1 100644 --- a/include/fstcpp/fstcpp_variable_info.h +++ b/include/fstcpp/fstcpp_variable_info.h @@ -7,10 +7,10 @@ // direct include #include "fstcpp/fstcpp.h" // C system headers -#ifdef _MSC_VER -# include -#endif // C++ standard library headers +#if defined(__cplusplus) && __cplusplus >= 202002L +# include +#endif #include #include #include @@ -26,19 +26,29 @@ namespace platform { // Can be replaced with std::bit_width when C++20 is available inline uint64_t clog2(uint64_t x) { -#if defined(__GNUC__) || defined(__clang__) - return 64 - __builtin_clzll(x - 1); -#elif defined(_MSC_VER) // MSVC if (x <= 1) return 0; - unsigned long index; - _BitScanReverse64(&index, x - 1); - return static_cast(index + 1); +#if defined(__cplusplus) && __cplusplus >= 202002L + return std::bit_width(x - 1); +#elif USE_GCC_INTRINSIC + return 64 - __builtin_clzll(x - 1); +// TODO: implement MSVC version +// #elif USE_MSVC_INTRINSIC #else uint64_t r = 0; - while (x > 1) { - x >>= 1; - r++; - } + x -= 1; + auto CheckAndShift = [&](uint64_t shift) { + if (x >> shift) { + r += shift; + x >>= shift; + } + }; + CheckAndShift(32); + CheckAndShift(16); + CheckAndShift(8); + CheckAndShift(4); + CheckAndShift(2); + CheckAndShift(1); + r += x; return r; #endif }