[libc++] Fix the signature of std::rotl and std::rotr

- Changed parameters type in `std::rotr` and `std::rorl` functions from `unsigned int` to `int`.
- Implemented behaviour for negative parameter values.

Fixes #64544

Reviewed By: #libc, philnik

Spies: arichardson, philnik, libcxx-commits

Differential Revision: https://reviews.llvm.org/D157569
This commit is contained in:
Daniil Kalinin 2023-08-12 08:44:49 -07:00 committed by Nikolas Klauser
parent 415d9e8ca3
commit 45500fa08a
5 changed files with 63 additions and 18 deletions

View File

@ -20,29 +20,30 @@
_LIBCPP_BEGIN_NAMESPACE_STD
template<class _Tp>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
_Tp __rotr(_Tp __t, unsigned int __cnt) _NOEXCEPT
{
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotr(_Tp __t, int __cnt) _NOEXCEPT {
static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__rotr requires an unsigned integer type");
const unsigned int __dig = numeric_limits<_Tp>::digits;
if ((__cnt % __dig) == 0)
return __t;
if (__cnt < 0) {
__cnt *= -1;
return (__t << (__cnt % __dig)) | (__t >> (__dig - (__cnt % __dig))); // rotr with negative __cnt is similar to rotl
}
return (__t >> (__cnt % __dig)) | (__t << (__dig - (__cnt % __dig)));
}
#if _LIBCPP_STD_VER >= 20
template <__libcpp_unsigned_integer _Tp>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp rotl(_Tp __t, unsigned int __cnt) noexcept {
const unsigned int __dig = numeric_limits<_Tp>::digits;
if ((__cnt % __dig) == 0)
return __t;
return (__t << (__cnt % __dig)) | (__t >> (__dig - (__cnt % __dig)));
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp rotl(_Tp __t, int __cnt) noexcept {
return std::__rotr(__t, -__cnt);
}
template <__libcpp_unsigned_integer _Tp>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp rotr(_Tp __t, unsigned int __cnt) noexcept {
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp rotr(_Tp __t, int __cnt) noexcept {
return std::__rotr(__t, __cnt);
}

View File

@ -34,9 +34,9 @@ namespace std {
// [bit.rotate], rotating
template<class T>
constexpr T rotl(T x, unsigned int s) noexcept; // C++20
constexpr T rotl(T x, int s) noexcept; // C++20
template<class T>
constexpr T rotr(T x, unsigned int s) noexcept; // C++20
constexpr T rotr(T x, int s) noexcept; // C++20
// [bit.count], counting
template<class T>

View File

@ -31,6 +31,7 @@ constexpr bool test()
ASSERT_SAME_TYPE(decltype(std::rotl(T(), 0)), T);
ASSERT_NOEXCEPT(std::rotl(T(), 0));
T max = std::numeric_limits<T>::max();
T highbit = std::rotr(T(1), 1);
assert(std::rotl(T(max - 1), 0) == T(max - 1));
assert(std::rotl(T(max - 1), 1) == T(max - 2));
@ -41,6 +42,14 @@ constexpr bool test()
assert(std::rotl(T(max - 1), 6) == T(max - 64));
assert(std::rotl(T(max - 1), 7) == T(max - 128));
assert(std::rotl(T(max - 1), -1) == T(max - highbit));
assert(std::rotl(T(max - 1), -2) == T(max - (highbit >> 1)));
assert(std::rotl(T(max - 1), -3) == T(max - (highbit >> 2)));
assert(std::rotl(T(max - 1), -4) == T(max - (highbit >> 3)));
assert(std::rotl(T(max - 1), -5) == T(max - (highbit >> 4)));
assert(std::rotl(T(max - 1), -6) == T(max - (highbit >> 5)));
assert(std::rotl(T(max - 1), -7) == T(max - (highbit >> 6)));
assert(std::rotl(T(1), 0) == T(1));
assert(std::rotl(T(1), 1) == T(2));
assert(std::rotl(T(1), 2) == T(4));
@ -50,6 +59,14 @@ constexpr bool test()
assert(std::rotl(T(1), 6) == T(64));
assert(std::rotl(T(1), 7) == T(128));
assert(std::rotl(T(128), -1) == T(64));
assert(std::rotl(T(128), -2) == T(32));
assert(std::rotl(T(128), -3) == T(16));
assert(std::rotl(T(128), -4) == T(8));
assert(std::rotl(T(128), -5) == T(4));
assert(std::rotl(T(128), -6) == T(2));
assert(std::rotl(T(128), -7) == T(1));
#ifndef TEST_HAS_NO_INT128
if constexpr (std::is_same_v<T, __uint128_t>) {
T val = (T(1) << 63) | (T(1) << 64);
@ -59,6 +76,12 @@ constexpr bool test()
assert(std::rotl(val, 1) == val << 1);
assert(std::rotl(val, 127) == val >> 1);
assert(std::rotl(T(3), 127) == ((T(1) << 127) | T(1)));
assert(std::rotl(val, -128) == val);
assert(std::rotl(val, -256) == val);
assert(std::rotl(val, -1) == val >> 1);
assert(std::rotl(val, -127) == val << 1);
assert(std::rotl(T(3), -1) == ((T(1) << 127) | T(1)));
}
#endif

View File

@ -42,6 +42,14 @@ constexpr bool test()
assert(std::rotr(T(max - 1), 6) == T(max - (highbit >> 5)));
assert(std::rotr(T(max - 1), 7) == T(max - (highbit >> 6)));
assert(std::rotr(T(max - 1), -1) == T(max - 2));
assert(std::rotr(T(max - 1), -2) == T(max - 4));
assert(std::rotr(T(max - 1), -3) == T(max - 8));
assert(std::rotr(T(max - 1), -4) == T(max - 16));
assert(std::rotr(T(max - 1), -5) == T(max - 32));
assert(std::rotr(T(max - 1), -6) == T(max - 64));
assert(std::rotr(T(max - 1), -7) == T(max - 128));
assert(std::rotr(T(128), 0) == T(128));
assert(std::rotr(T(128), 1) == T(64));
assert(std::rotr(T(128), 2) == T(32));
@ -51,6 +59,14 @@ constexpr bool test()
assert(std::rotr(T(128), 6) == T(2));
assert(std::rotr(T(128), 7) == T(1));
assert(std::rotr(T(1), -1) == T(2));
assert(std::rotr(T(1), -2) == T(4));
assert(std::rotr(T(1), -3) == T(8));
assert(std::rotr(T(1), -4) == T(16));
assert(std::rotr(T(1), -5) == T(32));
assert(std::rotr(T(1), -6) == T(64));
assert(std::rotr(T(1), -7) == T(128));
#ifndef TEST_HAS_NO_INT128
if constexpr (std::is_same_v<T, __uint128_t>) {
T val = (T(1) << 63) | (T(1) << 64);
@ -60,6 +76,12 @@ constexpr bool test()
assert(std::rotr(val, 1) == val >> 1);
assert(std::rotr(val, 127) == val << 1);
assert(std::rotr(T(3), 1) == ((T(1) << 127) | T(1)));
assert(std::rotr(val, -128) == val);
assert(std::rotr(val, -256) == val);
assert(std::rotr(val, -1) == val << 1);
assert(std::rotr(val, -127) == val >> 1);
assert(std::rotr(T(3), -127) == ((T(1) << 127) | T(1)));
}
#endif

View File

@ -109,7 +109,6 @@ libcxx/include/__bit/countl.h
libcxx/include/__bit/countr.h
libcxx/include/__bit/endian.h
libcxx/include/__bit/popcount.h
libcxx/include/__bit/rotate.h
libcxx/include/bitset
libcxx/include/cctype
libcxx/include/chrono