[gcc(refs/users/ppalka/heads/libstdcxx-constrained-algos)] Finish implementation of the integer-class types

Patrick Palka ppalka@gcc.gnu.org
Thu Jan 16 19:43:00 GMT 2020


https://gcc.gnu.org/g:313de0bb9aae1fd8697dc52e2e18bb54bcc45a21

commit 313de0bb9aae1fd8697dc52e2e18bb54bcc45a21
Author: Patrick Palka <ppalka@gcc.gnu.org>
Date:   Thu Jan 16 10:49:48 2020 -0500

    Finish implementation of the integer-class types

Diff:
---
 libstdc++-v3/include/bits/range_access.h           | 505 +++++++++++++--------
 .../testsuite/std/ranges/iota/difference_type.cc   | 101 ++++-
 2 files changed, 412 insertions(+), 194 deletions(-)

diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h
index 82922a0..a908718 100644
--- a/libstdc++-v3/include/bits/range_access.h
+++ b/libstdc++-v3/include/bits/range_access.h
@@ -348,417 +348,536 @@ namespace ranges
   namespace __detail
   {
 #ifdef _GLIBCXX_INTEGER_LIKE_TYPES
-    class __max_diff_type
+    class __max_size_type
     {
     public:
-      __max_diff_type() = default;
+      __max_size_type() = default;
 
-      template<signed_integral _Tp>
+      template<integral _Tp>
 	constexpr
-	__max_diff_type(_Tp __i) noexcept
-	: _M_val(__i < 0 ? rep(~__i) + rep(1) : __i), _M_sign_bit(__i < 0)
+	__max_size_type(_Tp __i) noexcept
+	: _M_val(__i), _M_msb(__i < 0)
 	{ }
 
-      template<unsigned_integral _Tp>
-	constexpr
-	__max_diff_type(_Tp __i) noexcept
-	: _M_val(__i), _M_sign_bit(false)
+      template<int __dummy = 0>
+	constexpr explicit
+	__max_size_type(const __max_diff_type& __d) noexcept
+	: __max_size_type(__d._M_rep)
 	{ }
 
-      template<signed_integral _Tp>
-	constexpr explicit operator _Tp() const noexcept
-	{
-	  _Tp __val = _M_val % (sizeof(_Tp) * __CHAR_BIT__);
-	  if (_M_sign_bit)
-	    return -__val;
-	  else
-	    return __val;
-	}
-
-      template<unsigned_integral _Tp>
+      template<integral _Tp>
 	constexpr explicit operator _Tp() const noexcept
 	{ return _M_val; }
 
       constexpr explicit
-      operator bool() const noexcept { return _M_val != 0; }
+      operator bool() const noexcept { return _M_val != 0 || _M_msb != 0; }
 
-      constexpr __max_diff_type
+      constexpr __max_size_type
       operator+() const noexcept { return *this; }
 
-      constexpr __max_diff_type
+      constexpr __max_size_type
+      operator~() const noexcept
+      { return __max_size_type{~_M_val, !_M_msb}; }
+
+      constexpr __max_size_type
       operator-() const noexcept
-      { return __max_diff_type{_M_val, !_M_sign_bit}; }
+      { return operator~() + 1; }
 
-      constexpr __max_diff_type
-      operator~() const noexcept
-      { return __max_diff_type{~_M_val, !_M_sign_bit}; }
+      constexpr __max_size_type&
+      operator+=(const __max_size_type& __r) noexcept
+      {
+	auto __sum = _M_val + __r._M_val;
+	bool __overflow = (__sum < _M_val);
+	_M_msb = _M_msb ^ __r._M_msb ^ __overflow;
+	_M_val = __sum;
+	return *this;
+      }
 
-      constexpr __max_diff_type&
-      operator+=(const __max_diff_type& __r) noexcept
+      constexpr __max_size_type&
+      operator-=(const __max_size_type& __r) noexcept
       {
-	if (_M_sign_bit == __r._M_sign_bit)
-	  _M_val += __r._M_val;
-	else if (_M_val >= __r._M_val)
-	  _M_val -= __r._M_val;
-	else
-	  {
-	    _M_val = __r._M_val - _M_val;
-	    _M_sign_bit = !_M_sign_bit;
-	  }
+	return *this += -__r;
+      }
+
+      constexpr __max_size_type&
+      operator&=(const __max_size_type& __r) noexcept
+      {
+	_M_val &= __r._M_val;
+	_M_msb &= __r._M_msb;
 	return *this;
       }
 
-      constexpr __max_diff_type&
-      operator-=(const __max_diff_type& __r) noexcept
+      friend constexpr __max_size_type
+      operator&(__max_size_type __l, const __max_size_type& __r) noexcept
       {
-	auto __rneg = __r;
-	__rneg._M_sign_bit = !__r._M_sign_bit;
-	return *this += __rneg;
+	__l &= __r;
+	return __l;
       }
 
-      constexpr __max_diff_type&
-      operator*=(const __max_diff_type& __r) noexcept
+      constexpr __max_size_type&
+      operator|=(const __max_size_type& __r) noexcept
       {
-	_M_val *= __r._M_val;
-	_M_sign_bit = (_M_sign_bit != __r._M_sign_bit);
+	_M_val |= __r._M_val;
+	_M_msb |= __r._M_msb;
 	return *this;
       }
 
-      constexpr __max_diff_type&
-      operator/=(const __max_diff_type& __r) noexcept
+      friend constexpr __max_size_type
+      operator|(__max_size_type __l, const __max_size_type& __r) noexcept
       {
-	_M_val /= __r._M_val;
-	_M_sign_bit = (_M_sign_bit != __r._M_sign_bit);
+	__l |= __r;
+	return __l;
+      }
+
+      constexpr __max_size_type&
+      operator^=(const __max_size_type& __r) noexcept
+      {
+	_M_val ^= __r._M_val;
+	_M_msb ^= __r._M_msb;
 	return *this;
       }
 
-      constexpr __max_diff_type&
-      operator%=(const __max_diff_type& __r) noexcept
+      friend constexpr __max_size_type
+      operator^(__max_size_type __l, const __max_size_type& __r) noexcept
       {
-	_M_val /= __r._M_val;
+	__l ^= __r;
+	return __l;
+      }
+
+      constexpr __max_size_type&
+      operator*=(const __max_size_type& __r) noexcept
+      {
+	bool __lsb = _M_val % 2;
+	*this >>= 1;
+
+	auto __rcopy = __r;
+	bool __rlsb = __rcopy._M_val % 2;
+	__rcopy >>= 1;
+
+	auto __res = 2 * _M_val * __rcopy._M_val;
+	__res += _M_val * __rlsb;
+	__res += __rcopy._M_val * __lsb;
+	_M_val = __res;
+	*this <<= 1;
+	*this += __rlsb * __lsb;
+
 	return *this;
       }
 
-      constexpr __max_diff_type&
-      operator<<=(const __max_diff_type& __r) noexcept
+      constexpr __max_size_type&
+      operator/=(const __max_size_type& __r) noexcept
+      {
+	__glibcxx_assert(__r != 0);
+
+	if (__r == 1)
+	  return *this;
+
+	if (*this == __r)
+	  {
+	    _M_val = 1;
+	    _M_msb = 0;
+	    return *this;
+	  }
+
+	if (_M_msb && __r._M_msb)
+	  {
+	    _M_val = (_M_val >= __r._M_val);
+	    _M_msb = 0;
+	  }
+	else if (!_M_msb && __r._M_msb)
+	  _M_val = 0;
+	else if (!_M_msb && !__r._M_msb)
+	  _M_val /= __r._M_val;
+	else if (_M_msb && !__r._M_msb)
+	  {
+	    auto __orig = *this;
+	    *this >>= 1;
+	    _M_val /= __r._M_val;
+	    *this <<= 1;
+	    if (__orig - *this * __r >= __r)
+	      _M_val++;
+	  }
+	return *this;
+      }
+
+      constexpr __max_size_type&
+      operator%=(const __max_size_type& __r) noexcept
       {
-	__glibcxx_assert(__r._M_val < numeric_limits<rep>::digits);
-	__glibcxx_assert(!__r._M_sign_bit);
+	*this = *this - (*this / __r) * __r;
+	return *this;
+      }
+
+      constexpr __max_size_type&
+      operator<<=(const __max_size_type& __r) noexcept
+      {
+	constexpr auto __digits = numeric_limits<__rep>::digits;
+	__glibcxx_assert(__r._M_val < __digits);
+	__glibcxx_assert(__r._M_msb == 0);
+	if (_M_val & (__rep(1) << __digits - __r._M_val))
+	  _M_msb = 1;
+	else
+	  _M_msb = 0;
 	_M_val <<= __r._M_val;
 	return *this;
       }
 
-      constexpr __max_diff_type&
-      operator>>=(const __max_diff_type& __r) noexcept
+      constexpr __max_size_type&
+      operator>>=(const __max_size_type& __r) noexcept
       {
-	__glibcxx_assert(__r._M_val < numeric_limits<rep>::digits);
-	__glibcxx_assert(!__r._M_sign_bit);
+	constexpr auto __digits = numeric_limits<__rep>::digits;
+	__glibcxx_assert(__r._M_val < __digits);
+	__glibcxx_assert(__r._M_msb == 0);
+	if (this == &__r)
+	  {
+	    _M_val = 0;
+	    return *this;
+	  }
+
 	_M_val >>= __r._M_val;
+	if (_M_msb && __r._M_val != 0)
+	  {
+	    _M_val |= __rep(1) << (__digits - __r._M_val);
+	    _M_msb = 0;
+	  }
+
 	return *this;
       }
 
-      friend constexpr __max_diff_type
-      operator+(__max_diff_type __l, const __max_diff_type& __r) noexcept
+      friend constexpr __max_size_type
+      operator+(__max_size_type __l, const __max_size_type& __r) noexcept
       {
 	__l += __r;
 	return __l;
       }
 
-      friend constexpr __max_diff_type
-      operator-(__max_diff_type __l, const __max_diff_type& __r) noexcept
+      friend constexpr __max_size_type
+      operator-(__max_size_type __l, const __max_size_type& __r) noexcept
       {
 	__l -= __r;
 	return __l;
       }
 
-      friend constexpr __max_diff_type
-      operator*(__max_diff_type __l, const __max_diff_type& __r) noexcept
+      friend constexpr __max_size_type
+      operator*(__max_size_type __l, const __max_size_type& __r) noexcept
       {
 	__l *= __r;
 	return __l;
       }
 
-      friend constexpr __max_diff_type
-      operator/(__max_diff_type __l, const __max_diff_type& __r) noexcept
+      friend constexpr __max_size_type
+      operator/(__max_size_type __l, const __max_size_type& __r) noexcept
       {
 	__l /= __r;
 	return __l;
       }
 
-      friend constexpr __max_diff_type
-      operator%(__max_diff_type __l, const __max_diff_type& __r) noexcept
+      friend constexpr __max_size_type
+      operator%(__max_size_type __l, const __max_size_type& __r) noexcept
       {
 	__l %= __r;
 	return __l;
       }
 
-      friend constexpr __max_diff_type
-      operator<<(__max_diff_type __l, const __max_diff_type& __r) noexcept
+      friend constexpr __max_size_type
+      operator<<(__max_size_type __l, const __max_size_type& __r) noexcept
       {
 	__l <<= __r;
 	return __l;
       }
 
-      friend constexpr __max_diff_type
-      operator>>(__max_diff_type __l, const __max_diff_type& __r) noexcept
+      friend constexpr __max_size_type
+      operator>>(__max_size_type __l, const __max_size_type& __r) noexcept
       {
 	__l >>= __r;
 	return __l;
       }
 
-      // TODO & | ^
-
       friend constexpr bool
-      operator==(const __max_diff_type& __l, const __max_diff_type& __r)
+      operator==(const __max_size_type& __l, const __max_size_type& __r)
       noexcept
       {
-	return __l._M_val == __r._M_val && __l._M_sign_bit == __r._M_sign_bit;
+	return __l._M_val == __r._M_val && __l._M_msb == __r._M_msb;
       }
 
       friend constexpr bool
-      operator!=(const __max_diff_type& __l, const __max_diff_type& __r)
+      operator!=(const __max_size_type& __l, const __max_size_type& __r)
       noexcept
       { return !(__l == __r); }
 
       friend constexpr bool
-      operator<(const __max_diff_type& __l, const __max_diff_type& __r)
-      noexcept
+      operator<(const __max_size_type& __l, const __max_size_type& __r) noexcept
       {
-	if (__l._M_sign_bit)
-	  {
-	    if (__r._M_sign_bit)
-	      return __l._M_val > __r._M_val;
-	    else
-	      return true;
-	  }
-	else if (__r._M_sign_bit)
-	  return false;
-	return __l._M_val < __r._M_val;
+	if (__l._M_msb == __r._M_msb)
+	  return __l._M_val < __r._M_val;
+	else
+	  return __r._M_msb;
       }
 
       friend constexpr bool
-      operator>(const __max_diff_type& __l, const __max_diff_type& __r)
-      noexcept
+      operator>(const __max_size_type& __l, const __max_size_type& __r) noexcept
       { return __r < __l; }
 
       friend constexpr bool
-      operator<=(const __max_diff_type& __l, const __max_diff_type& __r)
-      noexcept
-      { return !(__r < __l); }
+      operator<=(const __max_size_type& __l, const __max_size_type& __r) noexcept
+      { return !(__l > __r); }
 
       friend constexpr bool
-      operator>=(const __max_diff_type& __l, const __max_diff_type& __r)
-      noexcept
-      { return !(__l < __r); }
+      operator>=(const __max_size_type& __l, const __max_size_type& __r) noexcept
+      { return __r <= __l; }
 
-    private:
 #ifdef __SIZEOF_INT128__
-      using rep = unsigned __int128;
+      using __rep = unsigned __int128;
 #else
-      using rep = unsigned long long;
+      using __rep = unsigned long long;
 #endif
-      rep _M_val = 0;
-      bool _M_sign_bit = false;
+    private:
+      __rep _M_val = 0;
+      unsigned _M_msb : 1;
 
       constexpr explicit
-      __max_diff_type(rep __val, bool __sb) noexcept
-      : _M_val(__val), _M_sign_bit(__sb)
+      __max_size_type(__rep __val, int __msb) noexcept
+      : _M_val(__val), _M_msb(__msb)
       { }
 
-      friend class __max_size_type;
+      friend class __max_diff_type;
     };
 
-    class __max_size_type
+    class __max_diff_type
     {
     public:
-      __max_size_type() = default;
+      __max_diff_type() = default;
 
       template<integral _Tp>
 	constexpr
-	__max_size_type(_Tp __i) noexcept
-	: _M_val(__i), _M_msb(0)
+	__max_diff_type(_Tp __i) noexcept
+	: _M_rep(__i)
 	{ }
 
       constexpr explicit
-      __max_size_type(const __max_diff_type& __d)
-      : _M_val(__d._M_val), _M_msb(__d._M_sign_bit)
+      __max_diff_type(const __max_size_type& __d) noexcept
+      : _M_rep(__d)
       { }
 
       template<integral _Tp>
 	constexpr explicit operator _Tp() const noexcept
-	{ return _M_val; }
+	{ return static_cast<_Tp>(_M_rep); }
 
       constexpr explicit
-      operator bool() const noexcept { return _M_val != 0; }
+      operator bool() const noexcept { return _M_rep != 0; }
 
-      constexpr __max_size_type
+      constexpr __max_diff_type
       operator+() const noexcept { return *this; }
 
-      constexpr __max_size_type
+      constexpr __max_diff_type
       operator-() const noexcept
-      { return __max_size_type{_M_val, !_M_sign_bit}; }
+      { return __max_diff_type(-_M_rep); }
 
-      constexpr __max_size_type
+      constexpr __max_diff_type
       operator~() const noexcept
-      { return __max_size_type{~_M_val, !_M_sign_bit}; }
+      { return __max_diff_type(~_M_rep); }
 
-      constexpr __max_size_type&
-      operator+=(const __max_size_type& __r) noexcept
+      constexpr __max_diff_type&
+      operator+=(const __max_diff_type& __r) noexcept
+      {
+	_M_rep += __r._M_rep;
+	return *this;
+      }
+
+      constexpr __max_diff_type&
+      operator-=(const __max_diff_type& __r) noexcept
+      {
+	_M_rep -= __r._M_rep;
+	return *this;
+      }
+
+      constexpr __max_diff_type&
+      operator*=(const __max_diff_type& __r) noexcept
+      {
+	_M_rep *= __r._M_rep;
+	return *this;
+      }
+
+      constexpr __max_diff_type&
+      operator/=(const __max_diff_type& __r) noexcept
       {
-	if (_M_sign_bit == __r._M_sign_bit)
-	  _M_val += __r._M_val;
-	else if (_M_val >= __r._M_val)
-	  _M_val -= __r._M_val;
+	const auto __neg = *this < 0;
+	const auto __rneg = __r < 0;
+	if (!__neg && !__rneg)
+	  _M_rep = _M_rep / __r._M_rep;
+	else if (__neg && __rneg)
+	  _M_rep = -_M_rep / -__r._M_rep;
 	else
 	  {
-	    _M_val = __r._M_val - _M_val;
-	    _M_sign_bit = !_M_sign_bit;
+	    auto __rcopy = __r;
+	    if (__neg)
+	      _M_rep = -_M_rep;
+	    if (__rneg)
+	      __rcopy = -__rcopy;
+	    const auto __remainder = _M_rep % __rcopy._M_rep;
+	    _M_rep = -(_M_rep / __rcopy._M_rep);
+	    if (__remainder != 0)
+	      _M_rep = _M_rep - 1;
 	  }
 	return *this;
       }
 
-      constexpr __max_size_type&
-      operator-=(const __max_size_type& __r) noexcept
+      constexpr __max_diff_type&
+      operator%=(const __max_diff_type& __r) noexcept
       {
-	auto __rneg = __r;
-	__rneg._M_sign_bit = !__r._M_sign_bit;
-	return *this += __rneg;
+	*this = *this - (*this / __r) * __r;
+	return *this;
       }
 
-      constexpr __max_size_type&
-      operator*=(const __max_size_type& __r) noexcept
+      constexpr __max_diff_type&
+      operator<<=(const __max_diff_type& __r) noexcept
       {
-	_M_val *= __r._M_val;
-	_M_sign_bit ^= __r._M_sign_bit;
+	_M_rep.operator<<=(__r._M_rep);
 	return *this;
       }
 
-      constexpr __max_size_type&
-      operator/=(const __max_size_type& __r) noexcept
+      constexpr __max_diff_type&
+      operator>>=(const __max_diff_type& __r) noexcept
       {
-	_M_val /= __r._M_val;
-	_M_sign_bit ^= __r._M_sign_bit;
+	auto __msb = _M_rep._M_msb;
+	_M_rep >>= __r._M_rep;
+	_M_rep._M_msb |= __msb;
 	return *this;
       }
 
-      constexpr __max_size_type&
-      operator%=(const __max_size_type& __r) noexcept
+      constexpr __max_diff_type&
+      operator&=(const __max_diff_type& __r) noexcept
       {
-	_M_val /= __r._M_val;
+	_M_rep &= __r._M_rep;
 	return *this;
       }
 
-      constexpr __max_size_type&
-      operator<<=(const __max_size_type& __r) noexcept
+      constexpr __max_diff_type&
+      operator|=(const __max_diff_type& __r) noexcept
       {
-	__glibcxx_assert(__r._M_val < numeric_limits<rep>::digits);
-	__glibcxx_assert(__r._M_sign_bit == 0);
-	_M_val <<= __r._M_val;
+	_M_rep |= __r._M_rep;
 	return *this;
       }
 
-      constexpr __max_size_type&
-      operator>>=(const __max_size_type& __r) noexcept
+      constexpr __max_diff_type&
+      operator^=(const __max_diff_type& __r) noexcept
       {
-	__glibcxx_assert(__r._M_val < numeric_limits<rep>::digits);
-	__glibcxx_assert(__r._M_sign_bit == 0);
-	_M_val >>= __r._M_val;
+	_M_rep ^= __r._M_rep;
 	return *this;
       }
 
-      friend constexpr __max_size_type
-      operator+(__max_size_type __l, const __max_size_type& __r) noexcept
+      friend constexpr __max_diff_type
+      operator+(__max_diff_type __l, const __max_diff_type& __r) noexcept
       {
 	__l += __r;
 	return __l;
       }
 
-      friend constexpr __max_size_type
-      operator-(__max_size_type __l, const __max_size_type& __r) noexcept
+      friend constexpr __max_diff_type
+      operator-(__max_diff_type __l, const __max_diff_type& __r) noexcept
       {
 	__l -= __r;
 	return __l;
       }
 
-      friend constexpr __max_size_type
-      operator*(__max_size_type __l, const __max_size_type& __r) noexcept
+      friend constexpr __max_diff_type
+      operator*(__max_diff_type __l, const __max_diff_type& __r) noexcept
       {
 	__l *= __r;
 	return __l;
       }
 
-      friend constexpr __max_size_type
-      operator/(__max_size_type __l, const __max_size_type& __r) noexcept
+      friend constexpr __max_diff_type
+      operator/(__max_diff_type __l, const __max_diff_type& __r) noexcept
       {
 	__l /= __r;
 	return __l;
       }
 
-      friend constexpr __max_size_type
-      operator%(__max_size_type __l, const __max_size_type& __r) noexcept
+      friend constexpr __max_diff_type
+      operator%(__max_diff_type __l, const __max_diff_type& __r) noexcept
       {
 	__l %= __r;
 	return __l;
       }
 
-      friend constexpr __max_size_type
-      operator<<(__max_size_type __l, const __max_size_type& __r) noexcept
+      friend constexpr __max_diff_type
+      operator<<(__max_diff_type __l, const __max_diff_type& __r) noexcept
       {
 	__l <<= __r;
 	return __l;
       }
 
-      friend constexpr __max_size_type
-      operator>>(__max_size_type __l, const __max_size_type& __r) noexcept
+      friend constexpr __max_diff_type
+      operator>>(__max_diff_type __l, const __max_diff_type& __r) noexcept
       {
 	__l >>= __r;
 	return __l;
       }
 
-      // TODO & | ^ > <= >=
+      friend constexpr __max_diff_type
+      operator&(__max_diff_type __l, const __max_diff_type& __r) noexcept
+      {
+	__l &= __r;
+	return __l;
+      }
+
+      friend constexpr __max_diff_type
+      operator|(__max_diff_type __l, const __max_diff_type& __r) noexcept
+      {
+	__l |= __r;
+	return __l;
+      }
+
+      friend constexpr __max_diff_type
+      operator^(__max_diff_type __l, const __max_diff_type& __r) noexcept
+      {
+	__l ^= __r;
+	return __l;
+      }
 
       friend constexpr bool
-      operator==(const __max_size_type& __l, const __max_size_type& __r)
+      operator==(const __max_diff_type& __l, const __max_diff_type& __r)
       noexcept
       {
-	return __l._M_val == __r._M_val && __l._M_msb == __r._M_msb;
+	return __l._M_rep == __r._M_rep;
       }
 
       friend constexpr bool
-      operator!=(const __max_size_type& __l, const __max_size_type& __r)
+      operator!=(const __max_diff_type& __l, const __max_diff_type& __r)
       noexcept
       { return !(__l == __r); }
 
-      friend constexpr bool
-      operator<(const __max_size_type& __l, const __max_size_type& __r)
-      noexcept
+      constexpr bool
+      operator<(const __max_diff_type& __r) const noexcept
       {
-	if (__l._M_msb == __r._M_msb)
-	  return __l._M_val < __r._M_val;
+	auto __lsign = _M_rep._M_msb;
+	auto __rsign = __r._M_rep._M_msb;
+	if (__lsign ^ __rsign)
+	  return __lsign;
 	else
-	  return __r._M_msb;
+	  return _M_rep < __r._M_rep;
       }
 
       friend constexpr bool
-      operator>(const __max_size_type& __l, const __max_size_type& __r)
-      noexcept
+      operator>(const __max_diff_type& __l, const __max_diff_type& __r) noexcept
       { return __r < __l; }
 
+      friend constexpr bool
+      operator<=(const __max_diff_type& __l, const __max_diff_type& __r) noexcept
+      { return !(__r < __l); }
+
+      friend constexpr bool
+      operator>=(const __max_diff_type& __l, const __max_diff_type& __r) noexcept
+      { return !(__l < __r); }
+
     private:
-#ifdef __SIZEOF_INT128__
-      using rep = unsigned __int128;
-#else
-      using rep = unsigned long long;
-#endif
-      rep _M_val = 0;
-      unsigned _M_msb : 1;
+      __max_size_type _M_rep = 0;
 
-      constexpr explicit
-      __max_size_type(rep __val, int __sb) noexcept
-      : _M_val(__val), _M_sig_bit(__sb)
-      { }
+      friend class __max_size_type;
     };
 
+    static_assert(sizeof(__max_diff_type) == sizeof(__max_size_type));
+
     constexpr __max_size_type
     __to_unsigned_like(__max_size_type __t) noexcept
     { return __t; }
diff --git a/libstdc++-v3/testsuite/std/ranges/iota/difference_type.cc b/libstdc++-v3/testsuite/std/ranges/iota/difference_type.cc
index 4a342de..08cc49d 100644
--- a/libstdc++-v3/testsuite/std/ranges/iota/difference_type.cc
+++ b/libstdc++-v3/testsuite/std/ranges/iota/difference_type.cc
@@ -15,7 +15,7 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// { dg-options "-std=gnu++2a" }
+// { dg-options "-std=gnu++2a -D_GLIBCXX_INTEGER_LIKE_TYPES=1" }
 // { dg-do run { target c++2a } }
 
 #include <ranges>
@@ -49,9 +49,108 @@ test02()
 #endif
 }
 
+void
+test03()
+{
+  using max_size_t = std::ranges::__detail::__max_size_type;
+  using max_diff_t = std::ranges::__detail::__max_diff_type;
+  using rep_t = max_size_t::__rep;
+
+  static_assert(max_size_t(7) % 3 == 1);
+  static_assert(max_size_t(7) % 4 == 3);
+
+  static_assert(-max_diff_t(1) == max_diff_t(-1));
+  static_assert(max_diff_t(3) % 2 == 1);
+  static_assert(max_diff_t(-3) / 2 == -2);
+  static_assert(max_diff_t(-3) % 2 == 1);
+  static_assert(max_diff_t(3) % -2 == -1);
+  static_assert(max_diff_t(-3) << 1 == -6);
+  static_assert(max_diff_t(-3) >> 1 == -2);
+  static_assert(max_diff_t(3) >> 1 == 1);
+  static_assert(max_diff_t(3) >> 2 == 0);
+
+  static_assert(max_diff_t(-5) / 3 == -2);
+  static_assert(max_diff_t(5) / -3 == -2);
+  static_assert(max_diff_t(-5) / -3 == 1);
+  static_assert(max_diff_t(5) / 3 == 1);
+
+  static_assert(max_diff_t(-6) / 3 == -2);
+  static_assert(max_diff_t(6) / -3 == -2);
+  static_assert(max_diff_t(-6) / -3 == 2);
+  static_assert(max_diff_t(6) / 3 == 2);
+
+  static_assert(~max_size_t(-3) == 2);
+  static_assert(~max_diff_t(-3) == 2);
+
+  static_assert(max_diff_t(1) < max_diff_t(3));
+  static_assert(max_diff_t(-1) < max_diff_t(3));
+  static_assert(max_diff_t(1) > max_diff_t(-3));
+  static_assert(max_diff_t(-1) > max_diff_t(-3));
+
+  constexpr max_size_t mu = std::numeric_limits<rep_t>::max();
+
+  static_assert(max_diff_t(mu)/-1 == -max_diff_t(mu));
+  static_assert(-max_diff_t(mu)/1 == -max_diff_t(mu));
+  static_assert(max_diff_t(mu)>>1 == max_diff_t(mu)/2);
+  static_assert(-max_diff_t(mu+1) == max_diff_t(mu+1));
+  static_assert(-(mu+1) == mu+1);
+  static_assert((mu+1)<<1 == 0);
+  static_assert(max_diff_t(mu+1)<<1 == 0);
+  static_assert(max_diff_t(mu+1)>>1 < 0);
+
+  static_assert(int(max_diff_t(mu+1)) == 0);
+  static_assert(rep_t(max_diff_t(mu+1)) == 0);
+  static_assert(int(max_diff_t(mu)) == -1);
+  static_assert(rep_t(max_diff_t(mu)) == -1);
+
+  static_assert(2*mu+1 > 2*mu);
+  static_assert(~(2*mu+1) == 0);
+  static_assert(mu/mu == 1);
+  static_assert(2*mu > mu);
+  static_assert(2*mu-mu == mu);
+  static_assert((2*mu)/mu == 2);
+  static_assert((2*mu+1)/mu == 2);
+  static_assert((2*mu-1)/(mu-1) == 2);
+  static_assert((2*mu-1)/mu == 1);
+  static_assert((2*mu+-1)/mu == 1);
+  static_assert(2*mu-1 < 2*mu);
+  static_assert(2*mu-1 <= 2*mu);
+  static_assert(2*mu+1 > 2*mu);
+  static_assert(2*mu+1 >= 2*mu);
+  static_assert((2*mu)/1 == 2*mu);
+  static_assert(mu/mu-1 == 0);
+  static_assert(mu*0 == 0);
+  static_assert((2*mu-1)*0 == 0);
+  static_assert((2*mu-1)>>1 == mu-1);
+  static_assert(mu+-1+1 == mu);
+  static_assert(mu+1+-1 == mu);
+  static_assert(mu+1);
+  static_assert((2*mu)/2 == mu);
+  static_assert((2*mu)>>1 == mu);
+  static_assert((mu<<1)>>1 == mu);
+  static_assert(1/mu == 0);
+  static_assert(mu/1 == mu);
+
+  constexpr max_size_t ou = 1;
+  constexpr max_diff_t ns = -1;
+
+  static_assert(max_size_t(ns) == -1);
+  static_assert(-max_diff_t(ou) == -1);
+  static_assert(-max_diff_t(-ou) == 1);
+  static_assert(max_size_t(-max_diff_t(-ou)) == 1);
+  static_assert(ns*ns == max_diff_t(ou));
+  static_assert(max_size_t(ns)*max_size_t(ns) == ou);
+  static_assert(-max_diff_t(0) == max_diff_t(0));
+  static_assert(-ou-ou == -2*ou);
+
+  static_assert(int(ns) == -1);
+  static_assert(rep_t(ns) == -1);
+}
+
 int
 main()
 {
   test01();
   test02();
+  test03();
 }



More information about the Libstdc++-cvs mailing list