[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