Commit f35da524 by Jonathan Wakely Committed by Jonathan Wakely

Adjust std::rotl, std::rotr etc to match final P0553R4 proposal

This proposal has now been accepted for C++20, with a few changes. This
patch adjusts std::rotl and std::rotr to match the final specification
and declares the additions for C++2a mode even when __STRICT_ANSI__ is
defined.

	* include/std/bit (__rotl, __rotr): Change second parameter from
	unsigned int to int and handle negative values.
	(rotl, rotr): Remove check for __STRICT_ANSI__. Change second
	parameter from unsigned int to int. Add nodiscard attribute.
	* testsuite/26_numerics/bit/bitops.rot/rotl.cc: Rename to ...
	* testsuite/26_numerics/bit/bit.rotate/rotl.cc: Here. Test negative
	shifts.
	* testsuite/26_numerics/bit/bitops.rot/rotr.cc: Rename to ...
	* testsuite/26_numerics/bit/bit.rotate/rotr.cc: Here. Test negative
	shifts.

From-SVN: r273706
parent 281ab2fb
2019-07-22 Jonathan Wakely <jwakely@redhat.com> 2019-07-22 Jonathan Wakely <jwakely@redhat.com>
* include/std/bit (__rotl, __rotr): Change second parameter from
unsigned int to int and handle negative values.
(rotl, rotr): Remove check for __STRICT_ANSI__. Change second
parameter from unsigned int to int. Add nodiscard attribute.
* testsuite/26_numerics/bit/bitops.rot/rotl.cc: Rename to ...
* testsuite/26_numerics/bit/bit.rotate/rotl.cc: Here. Test negative
shifts.
* testsuite/26_numerics/bit/bitops.rot/rotr.cc: Rename to ...
* testsuite/26_numerics/bit/bit.rotate/rotr.cc: Here. Test negative
shifts.
* include/std/bit (__ceil2): Make unrepresentable results undefined, * include/std/bit (__ceil2): Make unrepresentable results undefined,
as per P1355R2. Add debug assertion. Perform one left shift, not two, as per P1355R2. Add debug assertion. Perform one left shift, not two,
so that out of range values cause undefined behaviour. Ensure that so that out of range values cause undefined behaviour. Ensure that
......
...@@ -42,20 +42,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -42,20 +42,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp> template<typename _Tp>
constexpr _Tp constexpr _Tp
__rotl(_Tp __x, unsigned int __s) noexcept __rotl(_Tp __x, int __s) noexcept
{ {
constexpr auto _Nd = numeric_limits<_Tp>::digits; constexpr auto _Nd = numeric_limits<_Tp>::digits;
const unsigned __sN = __s % _Nd; const int __r = __s % _Nd;
return (__x << __sN) | (__x >> ((_Nd - __sN) % _Nd)); if (__r == 0)
return __x;
else if (__r > 0)
return (__x << __r) | (__x >> ((_Nd - __r) % _Nd));
else
return (__x >> -__r) | (__x << ((_Nd + __r) % _Nd)); // rotr(x, -r)
} }
template<typename _Tp> template<typename _Tp>
constexpr _Tp constexpr _Tp
__rotr(_Tp __x, unsigned int __s) noexcept __rotr(_Tp __x, int __s) noexcept
{ {
constexpr auto _Nd = numeric_limits<_Tp>::digits; constexpr auto _Nd = numeric_limits<_Tp>::digits;
const unsigned __sN = __s % _Nd; const int __r = __s % _Nd;
return (__x >> __sN) | (__x << ((_Nd - __sN) % _Nd)); if (__r == 0)
return __x;
else if (__r > 0)
return (__x >> __r) | (__x << ((_Nd - __r) % _Nd));
else
return (__x << -__r) | (__x >> ((_Nd + __r) % _Nd)); // rotl(x, -r)
} }
template<typename _Tp> template<typename _Tp>
...@@ -244,20 +254,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -244,20 +254,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using _If_is_unsigned_integer using _If_is_unsigned_integer
= enable_if_t<__is_unsigned_integer<_Tp>::value, _Up>; = enable_if_t<__is_unsigned_integer<_Tp>::value, _Up>;
#if ! __STRICT_ANSI__ // [bit.rot], rotating
// [bitops.rot], rotating
template<typename _Tp> template<typename _Tp>
constexpr _If_is_unsigned_integer<_Tp> [[nodiscard]] constexpr _If_is_unsigned_integer<_Tp>
rotl(_Tp __x, unsigned int __s) noexcept rotl(_Tp __x, int __s) noexcept
{ return std::__rotl(__x, __s); } { return std::__rotl(__x, __s); }
template<typename _Tp> template<typename _Tp>
constexpr _If_is_unsigned_integer<_Tp> [[nodiscard]] constexpr _If_is_unsigned_integer<_Tp>
rotr(_Tp __x, unsigned int __s) noexcept rotr(_Tp __x, int __s) noexcept
{ return std::__rotr(__x, __s); } { return std::__rotr(__x, __s); }
// [bitops.count], counting // [bit.count], counting
template<typename _Tp> template<typename _Tp>
constexpr _If_is_unsigned_integer<_Tp, int> constexpr _If_is_unsigned_integer<_Tp, int>
...@@ -283,9 +292,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -283,9 +292,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr _If_is_unsigned_integer<_Tp, int> constexpr _If_is_unsigned_integer<_Tp, int>
popcount(_Tp __x) noexcept popcount(_Tp __x) noexcept
{ return std::__popcount(__x); } { return std::__popcount(__x); }
#endif
// Integral power-of-two operations // [bit.pow.two], integral powers of 2
template<typename _Tp> template<typename _Tp>
constexpr _If_is_unsigned_integer<_Tp, bool> constexpr _If_is_unsigned_integer<_Tp, bool>
......
...@@ -21,11 +21,26 @@ ...@@ -21,11 +21,26 @@
#include <bit> #include <bit>
template<typename UInt> template<typename UInt>
constexpr bool
test_negative_shifts()
{
constexpr unsigned digits = std::numeric_limits<UInt>::digits;
UInt xarr[] = { (UInt)-1, 0, 1, 3, 6, 7, 0x10, 0x11, 0x22, 0x44, 0x80 };
int sarr[] = { 1, 4, 5, digits - 1, digits };
for (UInt x : xarr)
for (int s : sarr)
if (std::rotl(x, -s) != std::rotr(x, s))
return false;
return true;
}
template<typename UInt>
constexpr auto constexpr auto
test(UInt x) test(UInt x)
-> decltype(std::rotl(x, 0u)) -> decltype(std::rotl(x, 0))
{ {
static_assert( noexcept(std::rotl(x, 0u)) ); static_assert( noexcept(std::rotl(x, 0)) );
constexpr unsigned digits = std::numeric_limits<UInt>::digits; constexpr unsigned digits = std::numeric_limits<UInt>::digits;
...@@ -63,6 +78,8 @@ test(UInt x) ...@@ -63,6 +78,8 @@ test(UInt x)
static_assert( std::rotl((UInt)0b1010'0101, 4) == 0b1010'0101'0000 ); static_assert( std::rotl((UInt)0b1010'0101, 4) == 0b1010'0101'0000 );
} }
static_assert( test_negative_shifts<UInt>() );
return true; return true;
} }
......
...@@ -21,11 +21,26 @@ ...@@ -21,11 +21,26 @@
#include <bit> #include <bit>
template<typename UInt> template<typename UInt>
constexpr bool
test_negative_shifts()
{
constexpr unsigned digits = std::numeric_limits<UInt>::digits;
UInt xarr[] = { (UInt)-1, 0, 1, 3, 6, 7, 0x10, 0x11, 0x22, 0x44, 0x80 };
int sarr[] = { 1, 4, 5, digits - 1, digits };
for (UInt x : xarr)
for (int s : sarr)
if (std::rotr(x, -s) != std::rotl(x, s))
return false;
return true;
}
template<typename UInt>
constexpr auto constexpr auto
test(UInt x) test(UInt x)
-> decltype(std::rotr(x, 0u)) -> decltype(std::rotr(x, 0))
{ {
static_assert( noexcept(std::rotr(x, 0u)) ); static_assert( noexcept(std::rotr(x, 0)) );
constexpr unsigned digits = std::numeric_limits<UInt>::digits; constexpr unsigned digits = std::numeric_limits<UInt>::digits;
...@@ -65,6 +80,8 @@ test(UInt x) ...@@ -65,6 +80,8 @@ test(UInt x)
== (0b1010 | ((UInt)0b0101 << digits - 4)) ); == (0b1010 | ((UInt)0b0101 << digits - 4)) );
} }
static_assert( test_negative_shifts<UInt>() );
return true; return true;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment