[libc++][pstl] Implementation of parallel std::lexicographical_compare() based on std::mismatch() (#212366)
This PR adds an implementation of parallel
`std::lexicographical_compare()` based on parallel `std::mismatch()`.
The implementation is close to a one-liner:
```c++
auto __res = _Mismatch()(__policy, __first1, __last1, __first2, __last2, [&](_Ref1 __lhs, _Ref2 __rhs) {
return !__comp(__lhs, __rhs) && !__comp(__rhs, __lhs);
});
```
Included tests check that:
- Semantics of the iterator-only version is correct.
- Semantics of the predicated version is correct.
- The functions correctly SFINAE out when the first argument is not an
execution policy.
- The `noexcept` policy is followed.
- The `nodiscard` policy is followed.
- `static_assert` verifies iterators' categories.
Part of #99938.
This commit is contained in:
parent
2e3f4ef585
commit
b4d2b2f9a3
8 changed files with 510 additions and 1 deletions
|
|
@ -253,6 +253,56 @@ template <class _ExecutionPolicy,
|
|||
std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__predicate));
|
||||
}
|
||||
|
||||
template <class _ExecutionPolicy,
|
||||
class _ForwardIterator1,
|
||||
class _ForwardIterator2,
|
||||
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
|
||||
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool lexicographical_compare(
|
||||
_ExecutionPolicy&& __policy,
|
||||
_ForwardIterator1 __first1,
|
||||
_ForwardIterator1 __last1,
|
||||
_ForwardIterator2 __first2,
|
||||
_ForwardIterator2 __last2) {
|
||||
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "lexicographical_compare requires ForwardIterators");
|
||||
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "lexicographical_compare requires ForwardIterators");
|
||||
using _Implementation =
|
||||
__pstl::__dispatch<__pstl::__lexicographical_compare, __pstl::__current_configuration, _RawPolicy>;
|
||||
return __pstl::__handle_exception<_Implementation>(
|
||||
std::forward<_ExecutionPolicy>(__policy),
|
||||
std::move(__first1),
|
||||
std::move(__last1),
|
||||
std::move(__first2),
|
||||
std::move(__last2),
|
||||
less<>{});
|
||||
}
|
||||
|
||||
template <class _ExecutionPolicy,
|
||||
class _ForwardIterator1,
|
||||
class _ForwardIterator2,
|
||||
class _Comp,
|
||||
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
|
||||
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool lexicographical_compare(
|
||||
_ExecutionPolicy&& __policy,
|
||||
_ForwardIterator1 __first1,
|
||||
_ForwardIterator1 __last1,
|
||||
_ForwardIterator2 __first2,
|
||||
_ForwardIterator2 __last2,
|
||||
_Comp __comp) {
|
||||
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "lexicographical_compare requires ForwardIterators");
|
||||
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "lexicographical_compare requires ForwardIterators");
|
||||
using _Implementation =
|
||||
__pstl::__dispatch<__pstl::__lexicographical_compare, __pstl::__current_configuration, _RawPolicy>;
|
||||
return __pstl::__handle_exception<_Implementation>(
|
||||
std::forward<_ExecutionPolicy>(__policy),
|
||||
std::move(__first1),
|
||||
std::move(__last1),
|
||||
std::move(__first2),
|
||||
std::move(__last2),
|
||||
std::move(__comp));
|
||||
}
|
||||
|
||||
template <class _ExecutionPolicy,
|
||||
class _ForwardIterator1,
|
||||
class _ForwardIterator2,
|
||||
|
|
|
|||
|
|
@ -346,6 +346,13 @@ struct __adjacent_find;
|
|||
// operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last,
|
||||
// _BinaryPredicate __predicate) const noexcept;
|
||||
|
||||
template <class _Backend, class _ExecutionPolicy>
|
||||
struct __lexicographical_compare;
|
||||
// template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Comp>
|
||||
// optional<bool>
|
||||
// operator()(_Policy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
|
||||
// _ForwardIterator2 __first2, _ForwardIterator2 __last2, _Comp __comp) const noexcept;
|
||||
|
||||
} // namespace __pstl
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ namespace __pstl {
|
|||
// mismatch family
|
||||
// ---------------
|
||||
// - adjacent_find
|
||||
// - lexicographical_compare
|
||||
// - mismatch_3leg
|
||||
//
|
||||
// for_each family
|
||||
|
|
@ -224,6 +225,33 @@ struct __find_first_of<__default_backend_tag, _ExecutionPolicy> {
|
|||
// mismatch family
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
template <class _ExecutionPolicy>
|
||||
struct __lexicographical_compare<__default_backend_tag, _ExecutionPolicy> {
|
||||
template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Comp>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
|
||||
operator()(_Policy&& __policy,
|
||||
_ForwardIterator1 __first1,
|
||||
_ForwardIterator1 __last1,
|
||||
_ForwardIterator2 __first2,
|
||||
_ForwardIterator2 __last2,
|
||||
_Comp __comp) const noexcept {
|
||||
using _Mismatch = __dispatch<__mismatch, __current_configuration, _ExecutionPolicy>;
|
||||
using _Ref1 = __iterator_reference<_ForwardIterator1>;
|
||||
using _Ref2 = __iterator_reference<_ForwardIterator2>;
|
||||
// find the first pair of elements that are not equal, or the end of one or both of the ranges
|
||||
auto __res = _Mismatch()(__policy, __first1, __last1, __first2, __last2, [&](_Ref1 __lhs, _Ref2 __rhs) {
|
||||
return !__comp(__lhs, __rhs) && !__comp(__rhs, __lhs); // derive equality from the less-than predicate
|
||||
});
|
||||
if (!__res) // if the underlying mismatch operation failed, return nullopt
|
||||
return nullopt;
|
||||
if (__res->first == __last1) // the first range is exhausted,
|
||||
return __res->second != __last2; // it is lexicographically less if the second range is not exhausted.
|
||||
if (__res->second == __last2) // the second range is exhausted,
|
||||
return false; // the first range is not exhausted, so it is not lexicographically less.
|
||||
return __comp(*__res->first, *__res->second); // otherwise, compare the first pair of non-equal elements
|
||||
}
|
||||
};
|
||||
|
||||
template <class _ExecutionPolicy>
|
||||
struct __mismatch_3leg<__default_backend_tag, _ExecutionPolicy> {
|
||||
template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Comp>
|
||||
|
|
@ -674,7 +702,8 @@ struct __adjacent_difference<__default_backend_tag, _ExecutionPolicy> {
|
|||
++__result;
|
||||
_ForwardIterator1 __first2 = std::next(__first1);
|
||||
if (__first2 == __last1)
|
||||
return __result; // edge case: not enough elements to perform adjacent difference, just return the output iterator
|
||||
return __result; // edge case: not enough elements to perform adjacent difference, just return the output
|
||||
// iterator
|
||||
// Process as a binary transform of two iterator ranges: [__first1 + 1, __last1) and [__first1, __last1 - 1)
|
||||
return _TransformBinary()(
|
||||
__policy,
|
||||
|
|
|
|||
|
|
@ -114,6 +114,17 @@ void f(non_forward_iterator non_fwd,
|
|||
(void)std::generate_n(pol, non_fwd, n, func); // expected-error@*:* {{static assertion failed: generate_n}}
|
||||
}
|
||||
|
||||
{
|
||||
(void)std::lexicographical_compare(
|
||||
pol, it, it, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: lexicographical_compare}}
|
||||
(void)std::lexicographical_compare(
|
||||
pol, it, it, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: lexicographical_compare}}
|
||||
(void)std::lexicographical_compare(
|
||||
pol, non_fwd, non_fwd, it, it); // expected-error@*:* {{static assertion failed: lexicographical_compare}}
|
||||
(void)std::lexicographical_compare(
|
||||
pol, non_fwd, non_fwd, it, it, pred); // expected-error@*:* {{static assertion failed: lexicographical_compare}}
|
||||
}
|
||||
|
||||
{
|
||||
(void)std::reverse_copy(
|
||||
pol, non_bidir, non_bidir, it); // expected-error@*:* {{static assertion failed: reverse_copy}}
|
||||
|
|
|
|||
|
|
@ -75,4 +75,8 @@ void test() {
|
|||
std::adjacent_find(std::execution::par, std::begin(a), std::end(a));
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::adjacent_find(std::execution::par, std::begin(a), std::end(a), pred2);
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::lexicographical_compare(std::execution::par, std::begin(a), std::end(a), std::begin(b), std::end(b));
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::lexicographical_compare(std::execution::par, std::begin(a), std::end(a), std::begin(b), std::end(b), pred2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,178 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// REQUIRES: std-at-least-c++17
|
||||
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-pstl
|
||||
|
||||
// template <class ExecutionPolicy,
|
||||
// class ForwardIterator1,
|
||||
// class ForwardIterator2>
|
||||
// bool lexicographical_compare(ExecutionPolicy&& exec,
|
||||
// ForwardIterator1 first1,
|
||||
// ForwardIterator1 last1,
|
||||
// ForwardIterator2 first2,
|
||||
// ForwardIterator2 last2);
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
|
||||
#include "test_execution_policies.h"
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
#include "type_algorithms.h"
|
||||
#include "runway_sample.h"
|
||||
|
||||
EXECUTION_POLICY_SFINAE_TEST(lexicographical_compare);
|
||||
|
||||
static_assert(sfinae_test_lexicographical_compare<int, int*, int*, int*, int*>);
|
||||
static_assert(!sfinae_test_lexicographical_compare<std::execution::parallel_policy, int*, int*, int*, int*>);
|
||||
|
||||
// The types X and Y are provided to test that lexicographical_compare can be used with heterogeneous custom types.
|
||||
|
||||
struct X {
|
||||
X() = delete;
|
||||
X(int i) : i_(i) {}
|
||||
X(const X&) = delete;
|
||||
int value() const { return i_; }
|
||||
|
||||
private:
|
||||
int i_;
|
||||
};
|
||||
|
||||
struct Y {
|
||||
Y() = delete;
|
||||
Y(int i) : i_(i) {}
|
||||
Y(const Y&) = delete;
|
||||
int value() const { return i_; }
|
||||
|
||||
private:
|
||||
int i_;
|
||||
};
|
||||
|
||||
bool operator<(const X& lhs, const Y& rhs) { return lhs.value() < rhs.value(); }
|
||||
bool operator<(const Y& lhs, const X& rhs) { return lhs.value() < rhs.value(); }
|
||||
|
||||
template <class Iter1, class Iter2>
|
||||
struct Test {
|
||||
template <class ExecutionPolicy>
|
||||
void operator()(ExecutionPolicy&& policy) {
|
||||
{ // check the return types
|
||||
int lhs[] = {0};
|
||||
int rhs[] = {0};
|
||||
auto res = std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs)), Iter2(std::begin(rhs)));
|
||||
static_assert(std::is_same_v<decltype(res), bool>);
|
||||
}
|
||||
{ // 2 empty ranges
|
||||
int lhs[] = {0};
|
||||
int rhs[] = {0};
|
||||
assert(!std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs)), Iter2(std::begin(rhs))));
|
||||
}
|
||||
{ // left empty, right non-empty
|
||||
int lhs[] = {0};
|
||||
int rhs[] = {0};
|
||||
assert(std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))));
|
||||
}
|
||||
{ // left non-empty, right empty
|
||||
int lhs[] = {0};
|
||||
int rhs[] = {0};
|
||||
assert(!std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::begin(rhs))));
|
||||
}
|
||||
{ // same size, same single element
|
||||
int lhs[] = {0};
|
||||
int rhs[] = {0};
|
||||
assert(!std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))));
|
||||
}
|
||||
{ // left longer
|
||||
int lhs[] = {1, 2, 3, 4, 5};
|
||||
int rhs[] = {1, 2, 3};
|
||||
assert(!std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))));
|
||||
}
|
||||
{ // right longer
|
||||
int lhs[] = {1, 2, 3};
|
||||
int rhs[] = {1, 2, 3, 4, 5};
|
||||
assert(std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))));
|
||||
}
|
||||
{ // same size, left is lexicographically less than right
|
||||
int lhs[] = {1, 2, 2, 4, 5};
|
||||
int rhs[] = {1, 2, 3, 4, 5};
|
||||
assert(std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))));
|
||||
}
|
||||
{ // same size, right is lexicographically less than left
|
||||
int lhs[] = {1, 2, 3, 4, 5};
|
||||
int rhs[] = {1, 2, 2, 4, 5};
|
||||
assert(!std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))));
|
||||
}
|
||||
{ // same size, different at various positions
|
||||
int lhs[1073];
|
||||
int rhs[1073];
|
||||
std::iota(std::begin(lhs), std::end(lhs), 0);
|
||||
std::copy(std::begin(lhs), std::end(lhs), std::begin(rhs));
|
||||
runway_sample(std::size(lhs), [&](size_t i) {
|
||||
lhs[i] = -1;
|
||||
assert(std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))));
|
||||
lhs[i] = static_cast<int>(i);
|
||||
rhs[i] = -1;
|
||||
assert(!std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))));
|
||||
rhs[i] = static_cast<int>(i);
|
||||
});
|
||||
assert(!std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class Iter1, class Iter2>
|
||||
struct TestXY {
|
||||
template <class ExecutionPolicy>
|
||||
void operator()(ExecutionPolicy&& policy) {
|
||||
{ // same ranges
|
||||
X lhs[] = {X(1), X(5), X(7)};
|
||||
Y rhs[] = {Y(1), Y(5), Y(7)};
|
||||
assert(!std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))));
|
||||
}
|
||||
{ // one element difference
|
||||
X lhs[] = {X(1), X(5), X(7)};
|
||||
Y rhs[] = {Y(1), Y(5), Y(8)};
|
||||
assert(std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main(int, char**) {
|
||||
types::for_each(types::forward_iterator_list<const int*>{}, types::apply_type_identity{[](auto v) {
|
||||
using Iter = typename decltype(v)::type;
|
||||
types::for_each(
|
||||
types::forward_iterator_list<const int*>{},
|
||||
TestIteratorWithPolicies<types::partial_instantiation<Test, Iter>::template apply>{});
|
||||
}});
|
||||
types::for_each(types::forward_iterator_list<const X*>{}, types::apply_type_identity{[](auto v) {
|
||||
using Iter = typename decltype(v)::type;
|
||||
types::for_each(
|
||||
types::forward_iterator_list<const Y*>{},
|
||||
TestIteratorWithPolicies<types::partial_instantiation<TestXY, Iter>::template apply>{});
|
||||
}});
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// REQUIRES: std-at-least-c++17
|
||||
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-pstl
|
||||
|
||||
// template <class ExecutionPolicy,
|
||||
// class ForwardIterator1,
|
||||
// class ForwardIterator2,
|
||||
// class Compare>
|
||||
// bool lexicographical_compare(ExecutionPolicy&& exec,
|
||||
// ForwardIterator1 first1,
|
||||
// ForwardIterator1 last1,
|
||||
// ForwardIterator2 first2,
|
||||
// ForwardIterator2 last2,
|
||||
// Compare comp);
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
|
||||
#include "test_execution_policies.h"
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
#include "type_algorithms.h"
|
||||
#include "runway_sample.h"
|
||||
|
||||
EXECUTION_POLICY_SFINAE_TEST(lexicographical_compare);
|
||||
|
||||
static_assert(sfinae_test_lexicographical_compare<int, int*, int*, int*, int*, bool (*)(int, int)>);
|
||||
static_assert(
|
||||
!sfinae_test_lexicographical_compare<std::execution::parallel_policy, int*, int*, int*, int*, bool (*)(int, int)>);
|
||||
|
||||
// The types X and Y are provided to test that lexicographical_compare can be used with heterogeneous custom types.
|
||||
|
||||
struct X {
|
||||
X() = delete;
|
||||
X(int i) : i_(i) {}
|
||||
X(const X&) = delete;
|
||||
int value() const { return i_; }
|
||||
|
||||
private:
|
||||
int i_;
|
||||
};
|
||||
|
||||
struct Y {
|
||||
Y() = delete;
|
||||
Y(int i) : i_(i) {}
|
||||
Y(const Y&) = delete;
|
||||
int value() const { return i_; }
|
||||
|
||||
private:
|
||||
int i_;
|
||||
};
|
||||
|
||||
struct Comp {
|
||||
bool operator()(int lhs, int rhs) const { return lhs > rhs; }
|
||||
bool operator()(const X& lhs, const Y& rhs) const { return lhs.value() > rhs.value(); }
|
||||
bool operator()(const Y& lhs, const X& rhs) const { return lhs.value() > rhs.value(); }
|
||||
};
|
||||
|
||||
template <class Iter1, class Iter2>
|
||||
struct Test {
|
||||
template <class ExecutionPolicy>
|
||||
void operator()(ExecutionPolicy&& policy) {
|
||||
{ // check the return types
|
||||
int lhs[] = {0};
|
||||
int rhs[] = {0};
|
||||
auto res = std::lexicographical_compare(
|
||||
policy,
|
||||
Iter1(std::begin(lhs)),
|
||||
Iter1(std::begin(lhs)),
|
||||
Iter2(std::begin(rhs)),
|
||||
Iter2(std::begin(rhs)),
|
||||
Comp{});
|
||||
static_assert(std::is_same_v<decltype(res), bool>);
|
||||
}
|
||||
{ // 2 empty ranges
|
||||
int lhs[] = {0};
|
||||
int rhs[] = {0};
|
||||
assert(!std::lexicographical_compare(
|
||||
policy,
|
||||
Iter1(std::begin(lhs)),
|
||||
Iter1(std::begin(lhs)),
|
||||
Iter2(std::begin(rhs)),
|
||||
Iter2(std::begin(rhs)),
|
||||
Comp{}));
|
||||
}
|
||||
{ // left empty, right non-empty
|
||||
int lhs[] = {0};
|
||||
int rhs[] = {0};
|
||||
assert(std::lexicographical_compare(
|
||||
policy,
|
||||
Iter1(std::begin(lhs)),
|
||||
Iter1(std::begin(lhs)),
|
||||
Iter2(std::begin(rhs)),
|
||||
Iter2(std::end(rhs)),
|
||||
Comp{}));
|
||||
}
|
||||
{ // left non-empty, right empty
|
||||
int lhs[] = {0};
|
||||
int rhs[] = {0};
|
||||
assert(!std::lexicographical_compare(
|
||||
policy,
|
||||
Iter1(std::begin(lhs)),
|
||||
Iter1(std::end(lhs)),
|
||||
Iter2(std::begin(rhs)),
|
||||
Iter2(std::begin(rhs)),
|
||||
Comp{}));
|
||||
}
|
||||
{ // same size, same single element
|
||||
int lhs[] = {0};
|
||||
int rhs[] = {0};
|
||||
assert(!std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{}));
|
||||
}
|
||||
{ // left longer
|
||||
int lhs[] = {1, 2, 3, 4, 5};
|
||||
int rhs[] = {1, 2, 3};
|
||||
assert(!std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{}));
|
||||
}
|
||||
{ // right longer
|
||||
int lhs[] = {1, 2, 3};
|
||||
int rhs[] = {1, 2, 3, 4, 5};
|
||||
assert(std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{}));
|
||||
}
|
||||
{ // same size, left is lexicographically less than right
|
||||
int lhs[] = {1, 2, 4, 4, 5};
|
||||
int rhs[] = {1, 2, 3, 4, 5};
|
||||
assert(std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{}));
|
||||
}
|
||||
{ // same size, right is lexicographically less than left
|
||||
int lhs[] = {1, 2, 3, 4, 5};
|
||||
int rhs[] = {1, 2, 4, 4, 5};
|
||||
assert(!std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{}));
|
||||
}
|
||||
{ // same size, different at various positions
|
||||
int lhs[1073];
|
||||
int rhs[1073];
|
||||
std::iota(std::begin(lhs), std::end(lhs), 0);
|
||||
std::copy(std::begin(lhs), std::end(lhs), std::begin(rhs));
|
||||
runway_sample(std::size(lhs), [&](size_t i) {
|
||||
lhs[i] = 10'000;
|
||||
assert(std::lexicographical_compare(
|
||||
policy,
|
||||
Iter1(std::begin(lhs)),
|
||||
Iter1(std::end(lhs)),
|
||||
Iter2(std::begin(rhs)),
|
||||
Iter2(std::end(rhs)),
|
||||
Comp{}));
|
||||
lhs[i] = static_cast<int>(i);
|
||||
rhs[i] = 10'000;
|
||||
assert(!std::lexicographical_compare(
|
||||
policy,
|
||||
Iter1(std::begin(lhs)),
|
||||
Iter1(std::end(lhs)),
|
||||
Iter2(std::begin(rhs)),
|
||||
Iter2(std::end(rhs)),
|
||||
Comp{}));
|
||||
rhs[i] = static_cast<int>(i);
|
||||
});
|
||||
assert(!std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{}));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class Iter1, class Iter2>
|
||||
struct TestXY {
|
||||
template <class ExecutionPolicy>
|
||||
void operator()(ExecutionPolicy&& policy) {
|
||||
{ // same ranges
|
||||
X lhs[] = {X(1), X(5), X(7)};
|
||||
Y rhs[] = {Y(1), Y(5), Y(7)};
|
||||
assert(!std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{}));
|
||||
}
|
||||
{ // one element difference
|
||||
X lhs[] = {X(1), X(5), X(8)};
|
||||
Y rhs[] = {Y(1), Y(5), Y(7)};
|
||||
assert(std::lexicographical_compare(
|
||||
policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{}));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main(int, char**) {
|
||||
types::for_each(types::forward_iterator_list<const int*>{}, types::apply_type_identity{[](auto v) {
|
||||
using Iter = typename decltype(v)::type;
|
||||
types::for_each(
|
||||
types::forward_iterator_list<const int*>{},
|
||||
TestIteratorWithPolicies<types::partial_instantiation<Test, Iter>::template apply>{});
|
||||
}});
|
||||
types::for_each(types::forward_iterator_list<const X*>{}, types::apply_type_identity{[](auto v) {
|
||||
using Iter = typename decltype(v)::type;
|
||||
types::for_each(
|
||||
types::forward_iterator_list<const Y*>{},
|
||||
TestIteratorWithPolicies<types::partial_instantiation<TestXY, Iter>::template apply>{});
|
||||
}});
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -210,6 +210,22 @@ int main(int, char**) {
|
|||
assert_non_throwing([=, &policy] { (void)std::generate_n(policy, std::move(first1), n, gen); });
|
||||
}
|
||||
|
||||
{
|
||||
auto pred = maybe_throw(tokens[5], [](int, int) -> bool { return true; });
|
||||
|
||||
// lexicographical_compare(first1, last1, first2, last2)
|
||||
assert_non_throwing([=, &policy] {
|
||||
(void)std::lexicographical_compare(
|
||||
policy, std::move(first1), std::move(last1), std::move(first2), std::move(last2));
|
||||
});
|
||||
|
||||
// lexicographical_compare(first1, last1, first2, last2, pred)
|
||||
assert_non_throwing([=, &policy] {
|
||||
(void)std::lexicographical_compare(
|
||||
policy, std::move(first1), std::move(last1), std::move(first2), std::move(last2), pred);
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
// reverse_copy(first, last, dest)
|
||||
assert_non_throwing([=, &policy] {
|
||||
|
|
|
|||
Loading…
Reference in a new issue