operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {},
_Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
{
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 3560. ranges::is_permutation should short-circuit for sized_ranges
+ if constexpr (sized_range<_Range1>)
+ if constexpr (sized_range<_Range2>)
+ if (ranges::distance(__r1) != ranges::distance(__r2))
+ return false;
+
return (*this)(ranges::begin(__r1), ranges::end(__r1),
ranges::begin(__r2), ranges::end(__r2),
std::move(__pred),
operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {},
_Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
{
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 3560. ranges::equal [...] should short-circuit for sized_ranges
+ if constexpr (sized_range<_Range1>)
+ if constexpr (sized_range<_Range2>)
+ if (ranges::distance(__r1) != ranges::distance(__r2))
+ return false;
+
return (*this)(ranges::begin(__r1), ranges::end(__r1),
ranges::begin(__r2), ranges::end(__r2),
std::move(__pred),
}
#if __cplusplus > 201103L
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr
template<typename _ForwardIterator1, typename _ForwardIterator2,
typename _BinaryPredicate>
_GLIBCXX20_CONSTEXPR
= typename iterator_traits<_ForwardIterator2>::iterator_category;
using _It1_is_RA = is_same<_Cat1, random_access_iterator_tag>;
using _It2_is_RA = is_same<_Cat2, random_access_iterator_tag>;
- constexpr bool __ra_iters = _It1_is_RA() && _It2_is_RA();
- if (__ra_iters)
+ constexpr bool __ra_iters = __and_<_It1_is_RA, _It2_is_RA>::value;
+ if constexpr (__ra_iters)
{
- auto __d1 = std::distance(__first1, __last1);
- auto __d2 = std::distance(__first2, __last2);
- if (__d1 != __d2)
+ if ((__last1 - __first1) != (__last2 - __first2))
return false;
}
if (!__pred(__first1, __first2))
break;
- if (__ra_iters)
+ if constexpr (__ra_iters)
{
if (__first1 == __last1)
return true;
}
return true;
}
+#pragma GCC diagnostic pop
/**
* @brief Checks whether a permutaion of the second sequence is equal
}
#if __cplusplus >= 201103L
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr
+
// 4-iterator version of std::equal<It1, It2> for use in C++11.
template<typename _II1, typename _II2>
_GLIBCXX20_CONSTEXPR
using _Cat1 = typename iterator_traits<_II1>::iterator_category;
using _Cat2 = typename iterator_traits<_II2>::iterator_category;
using _RAIters = __and_<is_same<_Cat1, _RATag>, is_same<_Cat2, _RATag>>;
- if (_RAIters())
+ if constexpr (_RAIters::value)
{
- auto __d1 = std::distance(__first1, __last1);
- auto __d2 = std::distance(__first2, __last2);
- if (__d1 != __d2)
+ if ((__last1 - __first1) != (__last2 - __first2))
return false;
return _GLIBCXX_STD_A::equal(__first1, __last1, __first2);
}
-
- for (; __first1 != __last1 && __first2 != __last2;
- ++__first1, (void)++__first2)
- if (!(*__first1 == *__first2))
- return false;
- return __first1 == __last1 && __first2 == __last2;
+ else
+ {
+ for (; __first1 != __last1 && __first2 != __last2;
+ ++__first1, (void)++__first2)
+ if (!(*__first1 == *__first2))
+ return false;
+ return __first1 == __last1 && __first2 == __last2;
+ }
}
// 4-iterator version of std::equal<It1, It2, BinaryPred> for use in C++11.
using _Cat1 = typename iterator_traits<_II1>::iterator_category;
using _Cat2 = typename iterator_traits<_II2>::iterator_category;
using _RAIters = __and_<is_same<_Cat1, _RATag>, is_same<_Cat2, _RATag>>;
- if (_RAIters())
+ if constexpr (_RAIters::value)
{
- auto __d1 = std::distance(__first1, __last1);
- auto __d2 = std::distance(__first2, __last2);
- if (__d1 != __d2)
+ if ((__last1 - __first1) != (__last2 - __first2))
return false;
return _GLIBCXX_STD_A::equal(__first1, __last1, __first2,
__binary_pred);
}
-
- for (; __first1 != __last1 && __first2 != __last2;
- ++__first1, (void)++__first2)
- if (!bool(__binary_pred(*__first1, *__first2)))
- return false;
- return __first1 == __last1 && __first2 == __last2;
+ else
+ {
+ for (; __first1 != __last1 && __first2 != __last2;
+ ++__first1, (void)++__first2)
+ if (!bool(__binary_pred(*__first1, *__first2)))
+ return false;
+ return __first1 == __last1 && __first2 == __last2;
+ }
}
+#pragma GCC diagnostic pop
#endif // C++11
#ifdef __glibcxx_robust_nonmodifying_seq_ops // C++ >= 14
--- /dev/null
+// { dg-do run { target c++20 } }
+
+// LWG 3560. ranges::equal and ranges::is_permutation should short-circuit
+// for sized_ranges
+
+#include <algorithm>
+#include <testsuite_iterators.h>
+#include <testsuite_hooks.h>
+
+struct X
+{
+ // Any equality comparison will cause the test to fail.
+ bool operator==(const X&) const { VERIFY(false); }
+};
+
+void
+test_std_equal()
+{
+ X vals[3];
+ __gnu_test::random_access_container<X> r1(vals, vals+3);
+ __gnu_test::random_access_container<X> r2(vals, vals+2);
+ VERIFY( ! std::equal(r1.begin(), r1.end(), r2.begin(), r2.end()) );
+
+ std::ranges::equal_to pred;
+ VERIFY( ! std::equal(r1.begin(), r1.end(), r2.begin(), r2.end(), pred) );
+}
+
+void
+test_std_ranges_equal()
+{
+ X vals[3];
+ __gnu_test::test_random_access_range<X> r1(vals, vals+3);
+ __gnu_test::test_random_access_range<X> r2(vals, vals+2);
+
+ // Any application of the projection will cause the test to fail.
+ auto proj = [](const X&) -> const X& { VERIFY(false); };
+ VERIFY( ! std::ranges::equal(r1.begin(), r1.end(), r2.begin(), r2.end(), {},
+ proj, proj) );
+
+ __gnu_test::test_forward_sized_range<X> r3(vals, vals+3);
+ __gnu_test::test_forward_sized_range<X> r4(vals, vals+2);
+ VERIFY( ! std::ranges::equal(r3, r4, {}, proj, proj) );
+}
+
+int main()
+{
+ test_std_equal();
+ test_std_ranges_equal();
+}
--- /dev/null
+// { dg-do run { target c++20 } }
+
+// LWG 3560. ranges::equal and ranges::is_permutation should short-circuit
+// for sized_ranges
+
+#include <algorithm>
+#include <testsuite_iterators.h>
+#include <testsuite_hooks.h>
+
+struct X
+{
+ // Any equality comparison will cause the test to fail.
+ bool operator==(const X&) const { VERIFY(false); }
+};
+
+void
+test_std_is_permutation()
+{
+ X vals[3];
+ __gnu_test::random_access_container<X> r1(vals, vals+3);
+ __gnu_test::random_access_container<X> r2(vals, vals+2);
+ VERIFY( ! std::is_permutation(r1.begin(), r1.end(), r2.begin(), r2.end()) );
+
+ std::ranges::equal_to pred;
+ VERIFY( ! std::is_permutation(r1.begin(), r1.end(), r2.begin(), r2.end(),
+ pred) );
+}
+
+void
+test_std_ranges_is_permutation()
+{
+ X vals[3];
+ __gnu_test::test_random_access_range<X> r1(vals, vals+3);
+ __gnu_test::test_random_access_range<X> r2(vals, vals+2);
+
+ // Any application of the projection will cause the test to fail.
+ auto proj = [](const X&) -> const X& { VERIFY(false); };
+ VERIFY( ! std::ranges::is_permutation(r1.begin(), r1.end(),
+ r2.begin(), r2.end(),
+ {}, proj, proj) );
+
+ __gnu_test::test_forward_sized_range<X> r3(vals, vals+3);
+ __gnu_test::test_forward_sized_range<X> r4(vals, vals+2);
+ VERIFY( ! std::ranges::is_permutation(r3, r4, {}, proj, proj) );
+}
+
+int main()
+{
+ test_std_is_permutation();
+ test_std_ranges_is_permutation();
+}