Skip to content

Commit

Permalink
Add P0553R4 and P0556R3 to <bit> (with D1956 rename) (microsoft#310)
Browse files Browse the repository at this point in the history
Resolves microsoft#25 and resolves microsoft#26. Currently active for Clang and EDG, but not C1XX.
  • Loading branch information
barcharcraz authored and SuperWig committed Nov 21, 2019
1 parent 8afec00 commit 0e3471b
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 1 deletion.
118 changes: 118 additions & 0 deletions stl/inc/bit
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
#pragma message("The contents of <bit> are available only with C++20 or later.")
#else // ^^^ !_HAS_CXX20 / _HAS_CXX20 vvv

#include <limits>
#include <type_traits>

#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
Expand All @@ -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 <class _Ty>
inline constexpr bool _Is_standard_unsigned_integer =
_Is_any_of_v<remove_cv_t<_Ty>, unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long>;


template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, int> = 0>
_NODISCARD constexpr int countl_zero(_Ty _Val) noexcept;

template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, int> = 0>
_NODISCARD constexpr bool ispow2(const _Ty _Val) noexcept {
return _Val != 0 && (_Val & (_Val - 1)) == 0;
}

template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, 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 <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, 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 <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, int> = 0>
_NODISCARD constexpr _Ty bit_length(const _Ty _Val) noexcept {
return static_cast<_Ty>(numeric_limits<_Ty>::digits - _STD countl_zero(_Val));
}

template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, int> = 0>
_NODISCARD constexpr _Ty rotr(_Ty _Val, int _Rotation) noexcept;

template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, 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 <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, 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 <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, 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<unsigned int>::digits - _Digits);
} else {
return __builtin_clzll(_Val) - (numeric_limits<unsigned long long>::digits - _Digits);
}
}

template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, int> = 0>
_NODISCARD constexpr int countl_one(const _Ty _Val) noexcept {
return _STD countl_zero(static_cast<_Ty>(~_Val));
}

template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, 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 <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, int> _Enabled = 0>
_NODISCARD constexpr int countr_one(const _Ty _Val) noexcept {
return _STD countr_zero(static_cast<_Ty>(~_Val));
}

template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, 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")
Expand Down
11 changes: 10 additions & 1 deletion stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
// (mbrtoc8 and c8rtomb not yet implemented)
// P0487R1 Fixing operator>>(basic_istream&, CharT*)
// P0550R2 remove_cvref
// P0553R4 <bit> Rotating And Counting Functions
// P0556R3 <bit> ispow2(), ceil2(), floor2(), log2p1()
// (log2p1() is called bit_length() as of D1956)
// P0616R0 Using move() In <numeric>
// P0631R8 <numbers> Math Constants
// P0646R1 list/forward_list remove()/remove_if()/unique() Return size_type
Expand Down Expand Up @@ -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 <bit> 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
Expand Down

0 comments on commit 0e3471b

Please sign in to comment.