[gcc(refs/users/ppalka/heads/integer_class_type)] Implement integer-like class types as defined in [iterator.concept.winc]

Patrick Palka ppalka@gcc.gnu.org
Fri Jan 17 06:07:00 GMT 2020


https://gcc.gnu.org/g:f09ede1b9efce84a4c649c58ec44125800177053

commit f09ede1b9efce84a4c649c58ec44125800177053
Author: Patrick Palka <ppalka@gcc.gnu.org>
Date:   Wed Jan 15 14:37:45 2020 +0000

    Implement integer-like class types as defined in [iterator.concept.winc]

Diff:
---
 libstdc++-v3/include/bits/iterator_concepts.h      |  15 +-
 libstdc++-v3/include/bits/range_access.h           | 516 +++++++++++++++++++++
 .../testsuite/std/ranges/iota/difference_type.cc   | 221 +++++++++
 3 files changed, 745 insertions(+), 7 deletions(-)

diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h
index bf58159..32cf02c 100644
--- a/libstdc++-v3/include/bits/iterator_concepts.h
+++ b/libstdc++-v3/include/bits/iterator_concepts.h
@@ -494,20 +494,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   namespace ranges::__detail
   {
-#if __SIZEOF_INT128__
-    using __max_diff_type = __int128;
-    using __max_size_type = unsigned __int128;
-#else
-    using __max_diff_type = long long;
-    using __max_size_type = unsigned long long;
-#endif
+    class __max_diff_type;
+    class __max_size_type;
 
     template<typename _Tp>
       concept __is_integer_like = integral<_Tp>
+#if __SIZEOF_INT128__
+	|| same_as<_Tp, __int128> || same_as<_Tp, unsigned __int128>
+#endif
 	|| same_as<_Tp, __max_diff_type> || same_as<_Tp, __max_size_type>;
 
     template<typename _Tp>
       concept __is_signed_integer_like = signed_integral<_Tp>
+#if __SIZEOF_INT128__
+	|| same_as<_Tp, __int128>
+#endif
 	|| same_as<_Tp, __max_diff_type>;
 
   } // namespace ranges::__detail
diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h
index 8b546a5..697712b2 100644
--- a/libstdc++-v3/include/bits/range_access.h
+++ b/libstdc++-v3/include/bits/range_access.h
@@ -347,6 +347,522 @@ namespace ranges
 
   namespace __detail
   {
+    class __max_size_type
+    {
+    public:
+      __max_size_type() = default;
+
+      template<integral _Tp>
+	constexpr
+	__max_size_type(_Tp __i) noexcept
+	: _M_val(__i), _M_msb(__i < 0)
+	{ }
+
+      template<int __dummy = 0>
+	constexpr explicit
+	__max_size_type(const __max_diff_type& __d) noexcept
+	: __max_size_type(__d._M_rep)
+	{ }
+
+      template<integral _Tp>
+	constexpr explicit operator _Tp() const noexcept
+	{ return _M_val; }
+
+      constexpr explicit
+      operator bool() const noexcept { return _M_val != 0 || _M_msb != 0; }
+
+      constexpr __max_size_type
+      operator+() const noexcept { return *this; }
+
+      constexpr __max_size_type
+      operator~() const noexcept
+      { return __max_size_type{~_M_val, !_M_msb}; }
+
+      constexpr __max_size_type
+      operator-() const noexcept
+      { return operator~() + 1; }
+
+      constexpr __max_size_type&
+      operator+=(const __max_size_type& __r) noexcept
+      {
+	const auto __sum = _M_val + __r._M_val;
+	const bool __overflow = (__sum < _M_val);
+	_M_msb = _M_msb ^ __r._M_msb ^ __overflow;
+	_M_val = __sum;
+	return *this;
+      }
+
+      constexpr __max_size_type&
+      operator-=(const __max_size_type& __r) noexcept
+      { return *this += -__r; }
+
+      constexpr __max_size_type&
+      operator*=(const __max_size_type& __r) noexcept
+      {
+	const bool __lsb = _M_val % 2;
+	*this >>= 1;
+
+	auto __rcopy = __r;
+	const 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_size_type&
+      operator/=(const __max_size_type& __r) noexcept
+      {
+	__glibcxx_assert(__r != 0);
+
+	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)
+	  {
+	    const 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
+      {
+	*this = *this - (*this / __r) * __r;
+	return *this;
+      }
+
+      constexpr __max_size_type&
+      operator<<=(const __max_size_type& __r) noexcept
+      {
+	constexpr auto __bits = sizeof(__rep) * __CHAR_BIT__;
+	__glibcxx_assert(__r._M_val < __bits);
+	__glibcxx_assert(__r._M_msb == 0);
+	if (_M_val & (__rep(1) << __bits - __r._M_val))
+	  _M_msb = 1;
+	else
+	  _M_msb = 0;
+	_M_val <<= __r._M_val;
+	return *this;
+      }
+
+      constexpr __max_size_type&
+      operator>>=(const __max_size_type& __r) noexcept
+      {
+	constexpr auto __bits = sizeof(__rep) * __CHAR_BIT__;
+	__glibcxx_assert(__r._M_val < __bits);
+	__glibcxx_assert(__r._M_msb == 0);
+
+	_M_val >>= __r._M_val;
+	if (_M_msb && __r._M_val != 0)
+	  {
+	    _M_val |= __rep(1) << (__bits - __r._M_val);
+	    _M_msb = 0;
+	  }
+
+	return *this;
+      }
+
+      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_size_type&
+      operator|=(const __max_size_type& __r) noexcept
+      {
+	_M_val |= __r._M_val;
+	_M_msb |= __r._M_msb;
+	return *this;
+      }
+
+      constexpr __max_size_type&
+      operator^=(const __max_size_type& __r) noexcept
+      {
+	_M_val ^= __r._M_val;
+	_M_msb ^= __r._M_msb;
+	return *this;
+      }
+
+      friend constexpr __max_size_type
+      operator+(__max_size_type __l, const __max_size_type& __r) noexcept
+      {
+	__l += __r;
+	return __l;
+      }
+
+      friend constexpr __max_size_type
+      operator-(__max_size_type __l, const __max_size_type& __r) noexcept
+      {
+	__l -= __r;
+	return __l;
+      }
+
+      friend constexpr __max_size_type
+      operator*(__max_size_type __l, const __max_size_type& __r) noexcept
+      {
+	__l *= __r;
+	return __l;
+      }
+
+      friend constexpr __max_size_type
+      operator/(__max_size_type __l, const __max_size_type& __r) noexcept
+      {
+	__l /= __r;
+	return __l;
+      }
+
+      friend constexpr __max_size_type
+      operator%(__max_size_type __l, const __max_size_type& __r) noexcept
+      {
+	__l %= __r;
+	return __l;
+      }
+
+      friend constexpr __max_size_type
+      operator<<(__max_size_type __l, const __max_size_type& __r) noexcept
+      {
+	__l <<= __r;
+	return __l;
+      }
+
+      friend constexpr __max_size_type
+      operator>>(__max_size_type __l, const __max_size_type& __r) noexcept
+      {
+	__l >>= __r;
+	return __l;
+      }
+
+      friend constexpr __max_size_type
+      operator&(__max_size_type __l, const __max_size_type& __r) noexcept
+      {
+	__l &= __r;
+	return __l;
+      }
+
+      friend constexpr __max_size_type
+      operator|(__max_size_type __l, const __max_size_type& __r) noexcept
+      {
+	__l |= __r;
+	return __l;
+      }
+
+      friend constexpr __max_size_type
+      operator^(__max_size_type __l, const __max_size_type& __r) noexcept
+      {
+	__l ^= __r;
+	return __l;
+      }
+
+      friend constexpr bool
+      operator==(const __max_size_type& __l, const __max_size_type& __r)
+      noexcept
+      { return __l._M_val == __r._M_val && __l._M_msb == __r._M_msb; }
+
+      friend constexpr bool
+      operator!=(const __max_size_type& __l, const __max_size_type& __r)
+      noexcept
+      { return !(__l == __r); }
+
+      friend constexpr bool
+      operator<(const __max_size_type& __l, const __max_size_type& __r) noexcept
+      {
+	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_size_type& __l, const __max_size_type& __r) noexcept
+      { return __r < __l; }
+
+      friend constexpr bool
+      operator<=(const __max_size_type& __l, const __max_size_type& __r) noexcept
+      { return !(__l > __r); }
+
+      friend constexpr bool
+      operator>=(const __max_size_type& __l, const __max_size_type& __r) noexcept
+      { return __r <= __l; }
+
+#ifdef __SIZEOF_INT128__
+      using __rep = unsigned __int128;
+#else
+      using __rep = unsigned long long;
+#endif
+    private:
+      __rep _M_val = 0;
+      unsigned _M_msb : 1 = 0;
+
+      constexpr explicit
+      __max_size_type(__rep __val, int __msb) noexcept
+      : _M_val(__val), _M_msb(__msb)
+      { }
+
+      friend class __max_diff_type;
+    };
+
+    class __max_diff_type
+    {
+    public:
+      __max_diff_type() = default;
+
+      template<integral _Tp>
+	constexpr
+	__max_diff_type(_Tp __i) noexcept
+	: _M_rep(__i)
+	{ }
+
+      constexpr explicit
+      __max_diff_type(const __max_size_type& __d) noexcept
+      : _M_rep(__d)
+      { }
+
+      template<integral _Tp>
+	constexpr explicit operator _Tp() const noexcept
+	{ return static_cast<_Tp>(_M_rep); }
+
+      constexpr explicit
+      operator bool() const noexcept { return _M_rep != 0; }
+
+      constexpr __max_diff_type
+      operator+() const noexcept { return *this; }
+
+      constexpr __max_diff_type
+      operator-() const noexcept
+      { return __max_diff_type(-_M_rep); }
+
+      constexpr __max_diff_type
+      operator~() const noexcept
+      { return __max_diff_type(~_M_rep); }
+
+      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
+      {
+	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
+	  {
+	    auto __rcopy = __r;
+	    if (__neg)
+	      _M_rep = -_M_rep;
+	    if (__rneg)
+	      __rcopy = -__rcopy;
+	    _M_rep = -(_M_rep / __rcopy._M_rep);
+	  }
+	return *this;
+      }
+
+      constexpr __max_diff_type&
+      operator%=(const __max_diff_type& __r) noexcept
+      {
+	*this = *this - (*this / __r) * __r;
+	return *this;
+      }
+
+      constexpr __max_diff_type&
+      operator<<=(const __max_diff_type& __r) noexcept
+      {
+	_M_rep.operator<<=(__r._M_rep);
+	return *this;
+      }
+
+      constexpr __max_diff_type&
+      operator>>=(const __max_diff_type& __r) noexcept
+      {
+	const auto __msb = _M_rep._M_msb;
+	_M_rep >>= __r._M_rep;
+	_M_rep._M_msb |= __msb;
+	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
+      {
+	_M_rep ^= __r._M_rep;
+	return *this;
+      }
+
+      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 __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 __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 __max_diff_type
+      operator^(__max_diff_type __l, const __max_diff_type& __r) noexcept
+      {
+	__l ^= __r;
+	return __l;
+      }
+
+      friend constexpr bool
+      operator==(const __max_diff_type& __l, const __max_diff_type& __r)
+      noexcept
+      {
+	return __l._M_rep == __r._M_rep;
+      }
+
+      friend constexpr bool
+      operator!=(const __max_diff_type& __l, const __max_diff_type& __r)
+      noexcept
+      { return !(__l == __r); }
+
+      constexpr bool
+      operator<(const __max_diff_type& __r) const noexcept
+      {
+	const auto __lsign = _M_rep._M_msb;
+	const auto __rsign = __r._M_rep._M_msb;
+	if (__lsign ^ __rsign)
+	  return __lsign;
+	else
+	  return _M_rep < __r._M_rep;
+      }
+
+      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 !(__r < __l); }
+
+      friend constexpr bool
+      operator>=(const __max_diff_type& __l, const __max_diff_type& __r) noexcept
+      { return !(__l < __r); }
+
+    private:
+      __max_size_type _M_rep = 0;
+
+      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; }
+
+    constexpr __max_size_type
+    __to_unsigned_like(__max_diff_type __t) noexcept
+    { return __max_size_type(__t); }
+
     template<integral _Tp>
       constexpr make_unsigned_t<_Tp>
       __to_unsigned_like(_Tp __t) noexcept
diff --git a/libstdc++-v3/testsuite/std/ranges/iota/difference_type.cc b/libstdc++-v3/testsuite/std/ranges/iota/difference_type.cc
new file mode 100644
index 0000000..a3b3029
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/iota/difference_type.cc
@@ -0,0 +1,221 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <ranges>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  using I = unsigned long long;
+  auto imax = std::numeric_limits<I>::max();
+  std::ranges::iota_view<I, I> i(0, imax);
+  auto begin = i.begin();
+  static_assert( std::input_or_output_iterator<decltype(begin)> );
+  auto size = std::ranges::end(i) - std::ranges::begin(i);
+  VERIFY( size > 0 );
+  VERIFY( size == imax );
+}
+
+void
+test02()
+{
+#if __SIZEOF_INT128__
+  using I = unsigned __int128;
+  auto imax = std::numeric_limits<I>::max();
+  std::ranges::iota_view<I, I> i(0, imax);
+  auto begin = i.begin();
+  static_assert( std::input_or_output_iterator<decltype(begin)> );
+  auto size = std::ranges::end(i) - std::ranges::begin(i);
+  VERIFY( size > 0 );
+  VERIFY( size == imax );
+#endif
+}
+
+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;
+
+void
+test03()
+{
+  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 == -1);
+  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 == -1);
+  static_assert(max_diff_t(5) / -3 == -1);
+  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)) == rep_t(-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);
+  static_assert(((mu+1)|mu) == -1);
+  static_assert((mu+1)+(mu+1) < mu+1);
+
+  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) == rep_t(-1));
+
+  static_assert(max_size_t() == 0);
+  static_assert(max_diff_t() == 0);
+
+  auto f = [] (auto a) { a /= a; return a; };
+  static_assert(f(max_size_t(5)) == 1);
+  static_assert(f(max_size_t(-5)) == 1);
+  static_assert(f(max_diff_t(5)) == 1);
+
+  auto g = [] (auto a) { a >>= a; return a; };
+  static_assert(g(max_size_t(5)) == 0);
+  static_assert(g(max_diff_t(5)) == 0);
+
+  auto h = [] (auto a) { a <<= a; return a; };
+  static_assert(h(max_size_t(3)) == 24);
+  static_assert(h(max_diff_t(3)) == 24);
+}
+
+template<bool signed_p, bool shorten_p>
+void
+test04()
+{
+  using hw_type = std::conditional_t<signed_p, long, unsigned long>;
+  using max_type = std::conditional_t<signed_p, max_diff_t, max_size_t>;
+  using shorten_type = std::conditional_t<shorten_p, hw_type, max_type>;
+  const int min = (signed_p ? -1000 : 0);
+  const int max = 1000;
+  for (hw_type i = min; i <= max; i++)
+    {
+      bool ok = true;
+      if (!signed_p && !shorten_p)
+	;
+      else
+	{
+	  ok &= (~i == shorten_type(~max_type(i)));
+	  ok &= (-i == shorten_type(-max_type(i)));
+	}
+      for (hw_type j = min; j <= max; j++)
+	{
+	  ok &= (i*j == shorten_type(max_type(i)*j));
+	  ok &= (i+j == shorten_type(max_type(i)+j));
+	  if (j != 0)
+	    ok &= (i/j == shorten_type(max_type(i)/j));
+	  if (!signed_p && !shorten_p)
+	    ;
+	  else
+	    ok &= (i-j == shorten_type(max_type(i)-j));
+	  ok &= ((i&j) == shorten_type(max_type(i)&j));
+	  ok &= ((i|j) == shorten_type(max_type(i)|j));
+	  ok &= ((i^j) == shorten_type(max_type(i)^j));
+	  if (!ok)
+	    {
+	      fprintf(stderr,
+		      "Inconsistency found: %d %d %ld %ld\n",
+		      signed_p, shorten_p, i, j) ;
+	       VERIFY(0);
+	    }
+	}
+    }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04<false,false>();
+  test04<false,true>();
+  test04<true,false>();
+  test04<true,true>();
+}



More information about the Libstdc++-cvs mailing list