[libcxx-commits] [libcxx] 45500fa - [libc++] Fix the signature of std::rotl and std::rotr
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Aug 12 08:46:27 PDT 2023
Author: Daniil Kalinin
Date: 2023-08-12T08:46:11-07:00
New Revision: 45500fa08acdf3849de9de470cdee5f4c8ee2f32
URL: https://github.com/llvm/llvm-project/commit/45500fa08acdf3849de9de470cdee5f4c8ee2f32
DIFF: https://github.com/llvm/llvm-project/commit/45500fa08acdf3849de9de470cdee5f4c8ee2f32.diff
LOG: [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
Added:
Modified:
libcxx/include/__bit/rotate.h
libcxx/include/bit
libcxx/test/std/numerics/bit/bitops.rot/rotl.pass.cpp
libcxx/test/std/numerics/bit/bitops.rot/rotr.pass.cpp
libcxx/utils/data/ignore_format.txt
Removed:
################################################################################
diff --git a/libcxx/include/__bit/rotate.h b/libcxx/include/__bit/rotate.h
index e9f4c8d474b0a5..74413ed0383f5f 100644
--- a/libcxx/include/__bit/rotate.h
+++ b/libcxx/include/__bit/rotate.h
@@ -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
-{
- 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;
- return (__t >> (__cnt % __dig)) | (__t << (__dig - (__cnt % __dig)));
+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);
}
diff --git a/libcxx/include/bit b/libcxx/include/bit
index 6b35bb2c7a0bcb..84e2080377e4fa 100644
--- a/libcxx/include/bit
+++ b/libcxx/include/bit
@@ -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>
diff --git a/libcxx/test/std/numerics/bit/bitops.rot/rotl.pass.cpp b/libcxx/test/std/numerics/bit/bitops.rot/rotl.pass.cpp
index 9592db613364f0..a1be03453abe3d 100644
--- a/libcxx/test/std/numerics/bit/bitops.rot/rotl.pass.cpp
+++ b/libcxx/test/std/numerics/bit/bitops.rot/rotl.pass.cpp
@@ -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
diff --git a/libcxx/test/std/numerics/bit/bitops.rot/rotr.pass.cpp b/libcxx/test/std/numerics/bit/bitops.rot/rotr.pass.cpp
index 95752542c09486..89fef32c36d4ff 100644
--- a/libcxx/test/std/numerics/bit/bitops.rot/rotr.pass.cpp
+++ b/libcxx/test/std/numerics/bit/bitops.rot/rotr.pass.cpp
@@ -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
diff --git a/libcxx/utils/data/ignore_format.txt b/libcxx/utils/data/ignore_format.txt
index 36018d273f3177..20384d1c769e0a 100644
--- a/libcxx/utils/data/ignore_format.txt
+++ b/libcxx/utils/data/ignore_format.txt
@@ -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
More information about the libcxx-commits
mailing list