From 1980e1a295be31fd3b377a9ea3c254904b76fc71 Mon Sep 17 00:00:00 2001 From: Charlie Barto Date: Mon, 18 Nov 2019 23:27:19 -0800 Subject: [PATCH] Add P0553R4 and P0556R3 to (with D1956 rename) (#310) Resolves #25 and resolves #26. Currently active for Clang and EDG, but not C1XX. --- stl/inc/bit | 118 +++++++++++++++++++++++++++++++++++++++++++ stl/inc/yvals_core.h | 11 +++- 2 files changed, 128 insertions(+), 1 deletion(-) diff --git a/stl/inc/bit b/stl/inc/bit index 4db71a6390..7617ee3fcf 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -12,6 +12,9 @@ #pragma message("The contents of are available only with C++20 or later.") #else // ^^^ !_HAS_CXX20 / _HAS_CXX20 vvv +#include +#include + #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) @@ -22,6 +25,121 @@ _STL_DISABLE_CLANG_WARNINGS _STD_BEGIN enum class endian { little = 0, big = 1, native = little }; +#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212 +template +inline constexpr bool _Is_standard_unsigned_integer = + _Is_any_of_v, unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long>; + + +template , int> = 0> +_NODISCARD constexpr int countl_zero(_Ty _Val) noexcept; + +template , int> = 0> +_NODISCARD constexpr bool ispow2(const _Ty _Val) noexcept { + return _Val != 0 && (_Val & (_Val - 1)) == 0; +} + +template , int> = 0> +_NODISCARD constexpr _Ty ceil2(const _Ty _Val) noexcept /* strengthened */ { + if (_Val == 0) { + return 1; + } + + return static_cast<_Ty>(_Ty{1} << (numeric_limits<_Ty>::digits - _STD countl_zero(static_cast<_Ty>(_Val - 1)))); +} + +template , int> = 0> +_NODISCARD constexpr _Ty floor2(const _Ty _Val) noexcept { + if (_Val == 0) { + return 0; + } + + return static_cast<_Ty>(_Ty{1} << (numeric_limits<_Ty>::digits - 1 - _STD countl_zero(_Val))); +} + +template , int> = 0> +_NODISCARD constexpr _Ty bit_length(const _Ty _Val) noexcept { + return static_cast<_Ty>(numeric_limits<_Ty>::digits - _STD countl_zero(_Val)); +} + +template , int> = 0> +_NODISCARD constexpr _Ty rotr(_Ty _Val, int _Rotation) noexcept; + +template , int> = 0> +_NODISCARD constexpr _Ty rotl(const _Ty _Val, const int _Rotation) noexcept { + constexpr auto _Digits = numeric_limits<_Ty>::digits; + const auto _Remainder = _Rotation % _Digits; + if (_Remainder > 0) { + return static_cast<_Ty>( + static_cast<_Ty>(_Val << _Remainder) | static_cast<_Ty>(_Val >> (_Digits - _Remainder))); + } else if (_Remainder == 0) { + return _Val; + } else { // _Remainder < 0 + return _STD rotr(_Val, -_Remainder); + } +} + +template , int> _Enabled> +_NODISCARD constexpr _Ty rotr(const _Ty _Val, const int _Rotation) noexcept { + constexpr auto _Digits = numeric_limits<_Ty>::digits; + const auto _Remainder = _Rotation % _Digits; + if (_Remainder > 0) { + return static_cast<_Ty>( + static_cast<_Ty>(_Val >> _Remainder) | static_cast<_Ty>(_Val << (_Digits - _Remainder))); + } else if (_Remainder == 0) { + return _Val; + } else { // _Remainder < 0 + return _STD rotl(_Val, -_Remainder); + } +} + +template , int> _Enabled> +_NODISCARD constexpr int countl_zero(const _Ty _Val) noexcept { + constexpr int _Digits = numeric_limits<_Ty>::digits; + if (_Val == 0) { + return _Digits; + } + + if constexpr (sizeof(_Ty) <= sizeof(unsigned int)) { + return __builtin_clz(_Val) - (numeric_limits::digits - _Digits); + } else { + return __builtin_clzll(_Val) - (numeric_limits::digits - _Digits); + } +} + +template , int> = 0> +_NODISCARD constexpr int countl_one(const _Ty _Val) noexcept { + return _STD countl_zero(static_cast<_Ty>(~_Val)); +} + +template , int> = 0> +_NODISCARD constexpr int countr_zero(const _Ty _Val) noexcept { + if (_Val == 0) { + return numeric_limits<_Ty>::digits; + } + + if constexpr (sizeof(_Ty) <= sizeof(unsigned int)) { + return __builtin_ctz(_Val); + } else { + return __builtin_ctzll(_Val); + } +} + +template , int> _Enabled = 0> +_NODISCARD constexpr int countr_one(const _Ty _Val) noexcept { + return _STD countr_zero(static_cast<_Ty>(~_Val)); +} + +template , int> _Enabled = 0> +_NODISCARD constexpr int popcount(const _Ty _Val) noexcept { + if constexpr (sizeof(_Ty) <= sizeof(unsigned int)) { + return __builtin_popcount(_Val); + } else { + return __builtin_popcountll(_Val); + } +} +#endif // __cpp_lib_bitops + _STD_END #pragma pop_macro("new") diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 88df38ed05..16005311b5 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -31,6 +31,9 @@ // (mbrtoc8 and c8rtomb not yet implemented) // P0487R1 Fixing operator>>(basic_istream&, CharT*) // P0550R2 remove_cvref +// P0553R4 Rotating And Counting Functions +// P0556R3 ispow2(), ceil2(), floor2(), log2p1() +// (log2p1() is called bit_length() as of D1956) // P0616R0 Using move() In // P0631R8 Math Constants // P0646R1 list/forward_list remove()/remove_if()/unique() Return size_type @@ -945,7 +948,13 @@ // C++20 #if _HAS_CXX20 -#define __cpp_lib_bind_front 201907L +#define __cpp_lib_bind_front 201907L +#if defined(__clang__) || defined(__EDG__) +#define __cpp_lib_bitops 201907L +#else // ^^^ Clang and EDG / MSVC vvv +// a future MSVC update will embed CPU feature detection into intrinsics +// TRANSITION, VSO-1020212 +#endif // defined(__clang__) || defined(__EDG__) #define __cpp_lib_bounded_array_traits 201902L #ifdef __cpp_char8_t #define __cpp_lib_char8_t 201811L