[gcc(refs/users/ppalka/heads/libstdcxx-constrained-algos)] Add ranges [alg.min.max]

Patrick Palka ppalka@gcc.gnu.org
Mon Jan 27 15:26:00 GMT 2020


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

commit ea5106116211259502d94daf8a29cbf7983bcdfd
Author: Patrick Palka <ppalka@redhat.com>
Date:   Mon Jan 27 10:22:38 2020 -0500

    Add ranges [alg.min.max]

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h            | 267 +++++++++++++++++++++
 .../testsuite/25_algorithms/max/constrained.cc     |  82 +++++++
 .../25_algorithms/max_element/constrained.cc       |  60 +++++
 .../testsuite/25_algorithms/min/constrained.cc     |  82 +++++++
 .../25_algorithms/min_element/constrained.cc       |  60 +++++
 .../testsuite/25_algorithms/minmax/constrained.cc  |  98 ++++++++
 .../25_algorithms/minmax_element/constrained.cc    |  68 ++++++
 7 files changed, 717 insertions(+)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index d589020..75e6c3e 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -3111,6 +3111,273 @@ namespace ranges
 	       std::move(__proj1), std::move(__proj2)));
     }
 
+  template<typename _Tp, typename _Proj = identity,
+	   indirect_strict_weak_order<projected<const _Tp*, _Proj>>
+	     _Comp = ranges::less>
+    constexpr const _Tp&
+    min(const _Tp& __a, const _Tp& __b, _Comp __comp = {}, _Proj __proj = {})
+    {
+      if (std::__invoke(std::move(__comp),
+			std::__invoke(__proj, __b),
+			std::__invoke(__proj, __a)))
+	return __b;
+      else
+	return __a;
+    }
+
+  template<input_range _Range, typename _Proj = identity,
+	   indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>>
+	     _Comp = ranges::less>
+    requires indirectly_copyable_storable<iterator_t<_Range>,
+					  range_value_t<_Range>*>
+    constexpr range_value_t<_Range>
+    min(_Range&& __r, _Comp __comp = {}, _Proj __proj = {})
+    {
+      auto __first = ranges::begin(__r);
+      auto __last = ranges::end(__r);
+      __glibcxx_assert(__first != __last);
+      auto __result = *__first;
+      while (++__first != __last)
+	{
+	  auto __tmp = *__first;
+	  if (std::__invoke(__comp,
+			    std::__invoke(__proj, __tmp),
+			    std::__invoke(__proj, __result)))
+	    __result = std::move(__tmp);
+	}
+      return __result;
+    }
+
+  template<copyable _Tp, typename _Proj = identity,
+	   indirect_strict_weak_order<projected<const _Tp*, _Proj>>
+	     _Comp = ranges::less>
+    constexpr _Tp
+    min(initializer_list<_Tp> __r, _Comp __comp = {}, _Proj __proj = {})
+    {
+      return ranges::min(ranges::subrange(__r),
+			 std::move(__comp), std::move(__proj));
+    }
+
+  template<typename _Tp, typename _Proj = identity,
+	   indirect_strict_weak_order<projected<const _Tp*, _Proj>>
+	     _Comp = ranges::less>
+    constexpr const _Tp&
+    max(const _Tp& __a, const _Tp& __b, _Comp __comp = {}, _Proj __proj = {})
+    {
+      if (std::__invoke(std::move(__comp),
+			std::__invoke(__proj, __a),
+			std::__invoke(__proj, __b)))
+	return __b;
+      else
+	return __a;
+    }
+
+  template<input_range _Range, typename _Proj = identity,
+	   indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>>
+	     _Comp = ranges::less>
+    requires indirectly_copyable_storable<iterator_t<_Range>,
+					  range_value_t<_Range>*>
+    constexpr range_value_t<_Range>
+    max(_Range&& __r, _Comp __comp = {}, _Proj __proj = {})
+    {
+      auto __first = ranges::begin(__r);
+      auto __last = ranges::end(__r);
+      __glibcxx_assert(__first != __last);
+      auto __result = *__first;
+      while (++__first != __last)
+	{
+	  auto __tmp = *__first;
+	  if (std::__invoke(__comp,
+			    std::__invoke(__proj, __result),
+			    std::__invoke(__proj, __tmp)))
+	    __result = std::move(__tmp);
+	}
+      return __result;
+    }
+
+  template<copyable _Tp, typename _Proj = identity,
+	   indirect_strict_weak_order<projected<const _Tp*, _Proj>>
+	     _Comp = ranges::less>
+    constexpr _Tp
+    max(initializer_list<_Tp> __r, _Comp __comp = {}, _Proj __proj = {})
+    {
+      return ranges::max(ranges::subrange(__r),
+			 std::move(__comp), std::move(__proj));
+    }
+
+  template<typename _Tp>
+  struct minmax_result {
+    [[no_unique_address]] _Tp min;
+    [[no_unique_address]] _Tp max;
+
+    template<typename _Tp2>
+      requires convertible_to<const _Tp&, _Tp2>
+      operator minmax_result<_Tp2>() const & {
+	return {min, max};
+      }
+
+    template<typename _Tp2>
+      requires convertible_to<_Tp, _Tp2>
+      operator minmax_result<_Tp2>() && {
+	return {std::move(min), std::move(max)};
+      }
+  };
+
+  template<typename _Tp, typename _Proj = identity,
+	   indirect_strict_weak_order<projected<const _Tp*, _Proj>>
+	     _Comp = ranges::less>
+    constexpr minmax_result<const _Tp&>
+    minmax(const _Tp& __a, const _Tp& __b, _Comp __comp = {}, _Proj __proj = {})
+    {
+      if (std::__invoke(std::move(__comp),
+			std::__invoke(__proj, __b),
+			std::__invoke(__proj, __a)))
+	return {__b, __a};
+      else
+	return {__a, __b};
+    }
+
+  template<input_range _Range, typename _Proj = identity,
+	   indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>>
+	     _Comp = ranges::less>
+    requires indirectly_copyable_storable<iterator_t<_Range>,
+    range_value_t<_Range>*>
+    constexpr minmax_result<range_value_t<_Range>>
+    minmax(_Range&& __r, _Comp __comp = {}, _Proj __proj = {})
+    {
+      auto __first = ranges::begin(__r);
+      auto __last = ranges::end(__r);
+      __glibcxx_assert(__first != __last);
+      minmax_result<range_value_t<_Range>> __result = {*__first, *__first};
+      while (++__first != __last)
+	{
+	  auto __tmp = *__first;
+	  if (std::__invoke(__comp,
+			    std::__invoke(__proj, __tmp),
+			    std::__invoke(__proj, __result.min)))
+	    __result.min = std::move(__tmp);
+	  if (!std::__invoke(__comp,
+			     std::__invoke(__proj, __tmp),
+			     std::__invoke(__proj, __result.max)))
+	    __result.max = std::move(__tmp);
+	}
+      return __result;
+    }
+
+  template<copyable _Tp, typename _Proj = identity,
+	   indirect_strict_weak_order<projected<const _Tp*, _Proj>>
+	     _Comp = ranges::less>
+    constexpr minmax_result<_Tp>
+    minmax(initializer_list<_Tp> __r, _Comp __comp = {}, _Proj __proj = {})
+    {
+      return ranges::minmax(ranges::subrange(__r),
+			    std::move(__comp), std::move(__proj));
+    }
+
+  template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+	   typename _Proj = identity,
+	   indirect_strict_weak_order<projected<_Iter, _Proj>>
+	     _Comp = ranges::less>
+    constexpr _Iter
+    min_element(_Iter __first, _Sent __last,
+		_Comp __comp = {}, _Proj __proj = {})
+    {
+      if (__first == __last)
+	return __first;
+
+      auto __i = __first;
+      while (++__i != __last)
+	{
+	  if (std::__invoke(__comp,
+			    std::__invoke(__proj, *__i),
+			    std::__invoke(__proj, *__first)))
+	    __first = __i;
+	}
+      return __first;
+    }
+
+  template<forward_range _Range, typename _Proj = identity,
+	   indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>>
+	     _Comp = ranges::less>
+    constexpr safe_iterator_t<_Range>
+    min_element(_Range&& __r, _Comp __comp = {}, _Proj __proj = {})
+    {
+      return ranges::min_element(ranges::begin(__r), ranges::end(__r),
+				 std::move(__comp), std::move(__proj));
+    }
+
+  template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+	   typename _Proj = identity,
+	   indirect_strict_weak_order<projected<_Iter, _Proj>>
+	     _Comp = ranges::less>
+    constexpr _Iter
+    max_element(_Iter __first, _Sent __last,
+		_Comp __comp = {}, _Proj __proj = {})
+    {
+      if (__first == __last)
+	return __first;
+
+      auto __i = __first;
+      while (++__i != __last)
+	{
+	  if (std::__invoke(__comp,
+			    std::__invoke(__proj, *__first),
+			    std::__invoke(__proj, *__i)))
+	    __first = __i;
+	}
+      return __first;
+    }
+
+  template<forward_range _Range, typename _Proj = identity,
+	   indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>>
+	     _Comp = ranges::less>
+    constexpr safe_iterator_t<_Range>
+    max_element(_Range&& __r, _Comp __comp = {}, _Proj __proj = {})
+    {
+      return ranges::max_element(ranges::begin(__r), ranges::end(__r),
+				 std::move(__comp), std::move(__proj));
+    }
+
+  template<typename _Iter>
+  using minmax_element_result = minmax_result<_Iter>;
+
+  template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+	   typename _Proj = identity,
+	   indirect_strict_weak_order<projected<_Iter, _Proj>>
+	     _Comp = ranges::less>
+    constexpr minmax_element_result<_Iter>
+    minmax_element(_Iter __first, _Sent __last,
+		   _Comp __comp = {}, _Proj __proj = {})
+    {
+      if (__first == __last)
+	return {__first, __first};
+
+      minmax_element_result<_Iter> __result = {__first, __first};
+      auto __i = __first;
+      while (++__i != __last)
+	{
+	  if (std::__invoke(__comp,
+			    std::__invoke(__proj, *__i),
+			    std::__invoke(__proj, *__result.min)))
+	    __result.min = __i;
+	  if (!std::__invoke(__comp,
+			     std::__invoke(__proj, *__i),
+			     std::__invoke(__proj, *__result.max)))
+	    __result.max = __i;
+	}
+      return __result;
+    }
+
+  template<forward_range _Range, typename _Proj = identity,
+	   indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>>
+	     _Comp = ranges::less>
+    constexpr minmax_element_result<safe_iterator_t<_Range>>
+    minmax_element(_Range&& __r, _Comp __comp = {}, _Proj __proj = {})
+    {
+      return ranges::minmax_element(ranges::begin(__r), ranges::end(__r),
+				    std::move(__comp), std::move(__proj));
+    }
+
   template<typename _Iter>
   struct next_permutation_result {
     bool found;
diff --git a/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc
new file mode 100644
index 0000000..3fcdb3a
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc
@@ -0,0 +1,82 @@
+// 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 <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+using __gnu_test::test_container;
+using __gnu_test::test_range;
+using __gnu_test::input_iterator_wrapper;
+
+namespace ranges = std::ranges;
+
+struct X
+{
+  int i, j;
+};
+
+void
+test01()
+{
+  VERIFY( ranges::max(1, 2) == 2);
+  VERIFY( ranges::max(2, 1) == 2);
+  VERIFY( ranges::max(1, 2, ranges::greater{}) == 1);
+  VERIFY( ranges::max(1, 2, ranges::greater{}, std::negate<>{}) == 2);
+  VERIFY( ranges::max(1, 2, {}, std::negate<>{}) == 1);
+  VERIFY( ranges::max(X{1,2}, X{1,3}, {}, &X::i).j == 2 );
+}
+
+void
+test02()
+{
+  int x[] = {1,2,3,4};
+  do
+    {
+      test_range<int, input_iterator_wrapper> cx(x);
+      VERIFY( ranges::max(cx) == 4 );
+      cx.bounds.first = x;
+      VERIFY( ranges::max(cx, ranges::greater{}) == 1 );
+      cx.bounds.first = x;
+      VERIFY( ranges::max(cx, {}, std::negate<>{}) == 1);
+      cx.bounds.first = x;
+      VERIFY( ranges::max(cx, ranges::greater{}, std::negate<>{}) == 4 );
+    } while (ranges::next_permutation(x).found);
+
+  constexpr X y[] = {{0,5},{1,2},{1,3}};
+  static_assert(ranges::max(y, {}, &X::i).j == 2);
+}
+
+void
+test03()
+{
+  VERIFY( ranges::max({2,3,1,4}) == 4 );
+  VERIFY( ranges::max({2,3,1,4}, ranges::greater{}) == 1 );
+  VERIFY( ranges::max({2,3,1,4}, {}, std::negate<>{}) == 1 );
+  VERIFY( ranges::max({2,3,1,4}, ranges::greater{}, std::negate<>{}) == 4 );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/max_element/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/max_element/constrained.cc
new file mode 100644
index 0000000..427faed
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/max_element/constrained.cc
@@ -0,0 +1,60 @@
+// 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 <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+using __gnu_test::test_container;
+using __gnu_test::test_range;
+using __gnu_test::forward_iterator_wrapper;
+
+namespace ranges = std::ranges;
+
+struct X
+{
+  int i, j;
+};
+
+void
+test01()
+{
+  int x[] = {1,2,3,4};
+  do
+    {
+      test_range<int, forward_iterator_wrapper> cx(x);
+      VERIFY( *ranges::max_element(cx) == 4 );
+      VERIFY( *ranges::max_element(cx, ranges::greater{}) == 1 );
+      VERIFY( *ranges::max_element(cx, {}, std::negate<>{}) == 1);
+      VERIFY( *ranges::max_element(cx, ranges::greater{}, std::negate<>{}) == 4 );
+    } while (ranges::next_permutation(x).found);
+
+  test_container<int, forward_iterator_wrapper> cx(x);
+  VERIFY( ranges::max_element(cx.begin(), cx.begin()) == cx.begin() );
+
+  constexpr X y[] = {{0,5},{1,2},{1,3}};
+  static_assert(ranges::max_element(y, y+3, {}, &X::i)->j == 2);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc
new file mode 100644
index 0000000..c3a83b9
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc
@@ -0,0 +1,82 @@
+// 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 <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+using __gnu_test::test_container;
+using __gnu_test::test_range;
+using __gnu_test::input_iterator_wrapper;
+
+namespace ranges = std::ranges;
+
+struct X
+{
+  int i, j;
+};
+
+void
+test01()
+{
+  VERIFY( ranges::min(1, 2) == 1);
+  VERIFY( ranges::min(2, 1) == 1);
+  VERIFY( ranges::min(1, 2, ranges::greater{}) == 2);
+  VERIFY( ranges::min(1, 2, ranges::greater{}, std::negate<>{}) == 1);
+  VERIFY( ranges::min(1, 2, {}, std::negate<>{}) == 2);
+  VERIFY( ranges::min(X{1,2}, X{1,3}, {}, &X::i).j == 2 );
+}
+
+void
+test02()
+{
+  int x[] = {1,2,3,4};
+  do
+    {
+      test_range<int, input_iterator_wrapper> cx(x);
+      VERIFY( ranges::min(cx) == 1 );
+      cx.bounds.first = x;
+      VERIFY( ranges::min(cx, ranges::greater{}) == 4 );
+      cx.bounds.first = x;
+      VERIFY( ranges::min(cx, {}, std::negate<>{}) == 4);
+      cx.bounds.first = x;
+      VERIFY( ranges::min(cx, ranges::greater{}, std::negate<>{}) == 1 );
+    } while (ranges::next_permutation(x).found);
+
+  constexpr X y[] = {{5,0},{1,2},{1,3}};
+  static_assert(ranges::min(y, {}, &X::i).j == 2);
+}
+
+void
+test03()
+{
+  VERIFY( ranges::min({2,3,1,4}) == 1 );
+  VERIFY( ranges::min({2,3,1,4}, ranges::greater{}) == 4 );
+  VERIFY( ranges::min({2,3,1,4}, {}, std::negate<>{}) == 4 );
+  VERIFY( ranges::min({2,3,1,4}, ranges::greater{}, std::negate<>{}) == 1 );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/min_element/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/min_element/constrained.cc
new file mode 100644
index 0000000..5180605
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/min_element/constrained.cc
@@ -0,0 +1,60 @@
+// 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 <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+using __gnu_test::test_container;
+using __gnu_test::test_range;
+using __gnu_test::forward_iterator_wrapper;
+
+namespace ranges = std::ranges;
+
+struct X
+{
+  int i, j;
+};
+
+void
+test01()
+{
+  int x[] = {1,2,3,4};
+  do
+    {
+      test_range<int, forward_iterator_wrapper> cx(x);
+      VERIFY( *ranges::min_element(cx) == 1 );
+      VERIFY( *ranges::min_element(cx, ranges::greater{}) == 4 );
+      VERIFY( *ranges::min_element(cx, {}, std::negate<>{}) == 4);
+      VERIFY( *ranges::min_element(cx, ranges::greater{}, std::negate<>{}) == 1 );
+    } while (ranges::next_permutation(x).found);
+
+  test_container<int, forward_iterator_wrapper> cx(x);
+  VERIFY( ranges::min_element(cx.begin(), cx.begin()) == cx.begin() );
+
+  constexpr X y[] = {{5,0},{1,2},{1,3}};
+  static_assert(ranges::min_element(y, y+3, {}, &X::i)->j == 2);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc
new file mode 100644
index 0000000..aa9364a
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc
@@ -0,0 +1,98 @@
+// 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 <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+using __gnu_test::test_container;
+using __gnu_test::test_range;
+using __gnu_test::input_iterator_wrapper;
+
+namespace ranges = std::ranges;
+
+template<typename T1, typename T2>
+constexpr bool
+operator==(const ranges::minmax_result<T1>& lhs,
+	   const ranges::minmax_result<T2>& rhs)
+{
+  return (lhs.min == rhs.min
+	  && rhs.max == rhs.max);
+}
+
+
+struct X
+{
+  int i, j;
+};
+
+using res_t = ranges::minmax_result<int>;
+
+void
+test01()
+{
+  VERIFY( ranges::minmax(1, 2) == res_t(1,2) );
+  VERIFY( ranges::minmax(2, 1) == res_t(1,2) );
+  VERIFY( ranges::minmax(1, 2, ranges::greater{}) == res_t(2,1) );
+  VERIFY( ranges::minmax(1, 2, ranges::greater{}, std::negate<>{}) == res_t(1,2) );
+  VERIFY( ranges::minmax(1, 2, {}, std::negate<>{}) == res_t(2,1) );
+  VERIFY( ranges::minmax(X{1,2}, X{1,3}, {}, &X::i).min.j == 2 );
+  VERIFY( ranges::minmax(X{1,2}, X{1,3}, {}, &X::i).max.j == 3 );
+}
+
+void
+test02()
+{
+  int x[] = {1,2,3,4};
+  do
+    {
+      test_range<int, input_iterator_wrapper> cx(x);
+      VERIFY( ranges::minmax(cx) == res_t(1,4) );
+      cx.bounds.first = x;
+      VERIFY( ranges::minmax(cx, ranges::greater{}) == res_t(4,1) );
+      cx.bounds.first = x;
+      VERIFY( ranges::minmax(cx, {}, std::negate<>{}) == res_t(4,1));
+      cx.bounds.first = x;
+      VERIFY( ranges::minmax(cx, ranges::greater{}, std::negate<>{})
+	      == res_t(1,4) );
+    } while (ranges::next_permutation(x).found);
+
+  constexpr X y[] = {{1,5},{1,2},{1,3}};
+  static_assert(ranges::minmax(y, {}, &X::i).min.j == 5);
+  static_assert(ranges::minmax(y, {}, &X::i).max.j == 3);
+}
+
+void
+test03()
+{
+  VERIFY( ranges::minmax({2,3,1,4}) == res_t(1,4) );
+  VERIFY( ranges::minmax({2,3,1,4}, ranges::greater{}) == res_t(4,1) );
+  VERIFY( ranges::minmax({2,3,1,4}, {}, std::negate<>{}) == res_t(4,1) );
+  VERIFY( ranges::minmax({2,3,1,4}, ranges::greater{}, std::negate<>{})
+	  == res_t(1,4) );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/minmax_element/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/minmax_element/constrained.cc
new file mode 100644
index 0000000..40019c4
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/minmax_element/constrained.cc
@@ -0,0 +1,68 @@
+// 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 <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+using __gnu_test::test_container;
+using __gnu_test::test_range;
+using __gnu_test::forward_iterator_wrapper;
+
+namespace ranges = std::ranges;
+
+struct X
+{
+  int i, j;
+};
+
+void
+test01()
+{
+  int x[] = {1,2,3,4};
+  do
+    {
+      test_range<int, forward_iterator_wrapper> cx(x);
+      VERIFY( *ranges::minmax_element(cx).min == 1 );
+      VERIFY( *ranges::minmax_element(cx).max == 4 );
+      VERIFY( *ranges::minmax_element(cx, ranges::greater{}).min == 4 );
+      VERIFY( *ranges::minmax_element(cx, ranges::greater{}).max == 1 );
+      VERIFY( *ranges::minmax_element(cx, {}, std::negate<>{}).min == 4);
+      VERIFY( *ranges::minmax_element(cx, {}, std::negate<>{}).max == 1);
+      VERIFY( *ranges::minmax_element(cx, ranges::greater{}, std::negate<>{}).min
+	      == 1 );
+      VERIFY( *ranges::minmax_element(cx, ranges::greater{}, std::negate<>{}).max
+	      == 4 );
+    } while (ranges::next_permutation(x).found);
+
+  test_container<int, forward_iterator_wrapper> cx(x);
+  VERIFY( ranges::minmax_element(cx.begin(), cx.begin()).min == cx.begin() );
+  VERIFY( ranges::minmax_element(cx.begin(), cx.begin()).max == cx.begin() );
+
+  constexpr X y[] = {{1,5},{1,2},{1,3}};
+  static_assert(ranges::minmax_element(y, y+3, {}, &X::i).min->j == 5);
+  static_assert(ranges::minmax_element(y, y+3, {}, &X::i).max->j == 3);
+}
+
+int
+main()
+{
+  test01();
+}



More information about the Libstdc++-cvs mailing list