зеркало из https://github.com/microsoft/STL.git
Implement ranges::lexicographical_compare (#1081)
This commit is contained in:
Родитель
d83bc99312
Коммит
eb33f1a1e9
|
@ -9935,6 +9935,59 @@ namespace ranges {
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr _Clamp_fn clamp{_Not_quite_object::_Construct_tag{}};
|
inline constexpr _Clamp_fn clamp{_Not_quite_object::_Construct_tag{}};
|
||||||
|
|
||||||
|
// VARIABLE ranges::lexicographical_compare
|
||||||
|
class _Lexicographical_compare_fn : private _Not_quite_object {
|
||||||
|
public:
|
||||||
|
using _Not_quite_object::_Not_quite_object;
|
||||||
|
|
||||||
|
template <input_iterator _It1, sentinel_for<_It1> _Se1, input_iterator _It2, sentinel_for<_It2> _Se2,
|
||||||
|
class _Pj1 = identity, class _Pj2 = identity,
|
||||||
|
indirect_strict_weak_order<projected<_It1, _Pj1>, projected<_It2, _Pj2>> _Pr = ranges::less>
|
||||||
|
_NODISCARD constexpr bool operator()(_It1 _First1, _Se1 _Last1, _It2 _First2, _Se2 _Last2, _Pr _Pred = {},
|
||||||
|
_Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) const {
|
||||||
|
_Adl_verify_range(_First1, _Last1);
|
||||||
|
_Adl_verify_range(_First2, _Last2);
|
||||||
|
|
||||||
|
return _Lexicographical_compare_unchecked(_Get_unwrapped(_STD move(_First1)),
|
||||||
|
_Get_unwrapped(_STD move(_Last1)), _Get_unwrapped(_STD move(_First2)),
|
||||||
|
_Get_unwrapped(_STD move(_Last2)), _Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <input_range _Rng1, input_range _Rng2, class _Pj1 = identity, class _Pj2 = identity,
|
||||||
|
indirect_strict_weak_order<projected<iterator_t<_Rng1>, _Pj1>, projected<iterator_t<_Rng2>, _Pj2>> _Pr =
|
||||||
|
ranges::less>
|
||||||
|
_NODISCARD constexpr bool operator()(
|
||||||
|
_Rng1&& _Range1, _Rng2&& _Range2, _Pr _Pred = {}, _Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) const {
|
||||||
|
return _Lexicographical_compare_unchecked(_Ubegin(_Range1), _Uend(_Range1), _Ubegin(_Range2),
|
||||||
|
_Uend(_Range2), _Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <class _It1, class _Se1, class _It2, class _Se2, class _Pr, class _Pj1, class _Pj2>
|
||||||
|
_NODISCARD static constexpr bool _Lexicographical_compare_unchecked(
|
||||||
|
_It1 _First1, _Se1 _Last1, _It2 _First2, _Se2 _Last2, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) {
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(input_iterator<_It1>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se1, _It1>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(input_iterator<_It2>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se2, _It2>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(indirect_strict_weak_order<_Pr, projected<_It1, _Pj1>, projected<_It2, _Pj2>>);
|
||||||
|
|
||||||
|
for (;; ++_First1, (void) ++_First2) {
|
||||||
|
if (_First2 == _Last2) {
|
||||||
|
return false;
|
||||||
|
} else if (_First1 == _Last1) {
|
||||||
|
return true;
|
||||||
|
} else if (_STD invoke(_Pred, _STD invoke(_Proj1, *_First1), _STD invoke(_Proj2, *_First2))) {
|
||||||
|
return true;
|
||||||
|
} else if (_STD invoke(_Pred, _STD invoke(_Proj2, *_First2), _STD invoke(_Proj1, *_First1))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr _Lexicographical_compare_fn lexicographical_compare{_Not_quite_object::_Construct_tag{}};
|
||||||
} // namespace ranges
|
} // namespace ranges
|
||||||
#endif // __cpp_lib_concepts
|
#endif // __cpp_lib_concepts
|
||||||
#endif // _HAS_CXX17
|
#endif // _HAS_CXX17
|
||||||
|
|
|
@ -265,6 +265,7 @@ tests\P0896R4_ranges_alg_heap
|
||||||
tests\P0896R4_ranges_alg_includes
|
tests\P0896R4_ranges_alg_includes
|
||||||
tests\P0896R4_ranges_alg_is_permutation
|
tests\P0896R4_ranges_alg_is_permutation
|
||||||
tests\P0896R4_ranges_alg_is_sorted
|
tests\P0896R4_ranges_alg_is_sorted
|
||||||
|
tests\P0896R4_ranges_alg_lexicographical_compare
|
||||||
tests\P0896R4_ranges_alg_merge
|
tests\P0896R4_ranges_alg_merge
|
||||||
tests\P0896R4_ranges_alg_minmax
|
tests\P0896R4_ranges_alg_minmax
|
||||||
tests\P0896R4_ranges_alg_mismatch
|
tests\P0896R4_ranges_alg_mismatch
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,224 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <concepts>
|
||||||
|
#include <ranges>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <range_algorithm_support.hpp>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using P = pair<int, int>;
|
||||||
|
|
||||||
|
struct instantiator {
|
||||||
|
static constexpr P left[] = {{0, 10}, {1, 20}, {2, 30}};
|
||||||
|
static constexpr P right_shorter_less[] = {{300, 0}, {200, 0}};
|
||||||
|
static constexpr P right_shorter_same[] = {{300, 0}, {200, 1}};
|
||||||
|
static constexpr P right_shorter_greater[] = {{300, 0}, {200, 2}};
|
||||||
|
static constexpr P right_less[] = {{300, 0}, {200, 1}, {100, 1}};
|
||||||
|
static constexpr P right_equal[] = {{300, 0}, {200, 1}, {100, 2}};
|
||||||
|
static constexpr P right_greater[] = {{300, 0}, {200, 1}, {100, 3}};
|
||||||
|
static constexpr P right_longer_less[] = {{300, 0}, {200, 1}, {100, 1}, {0, 3}};
|
||||||
|
static constexpr P right_longer_same[] = {{300, 0}, {200, 1}, {100, 2}, {0, 3}};
|
||||||
|
static constexpr P right_longer_greater[] = {{300, 0}, {200, 1}, {100, 3}, {0, 3}};
|
||||||
|
|
||||||
|
template <class In1, class In2>
|
||||||
|
static constexpr void call() {
|
||||||
|
using ranges::lexicographical_compare, ranges::less;
|
||||||
|
|
||||||
|
// Validate range overload
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_shorter_less};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second);
|
||||||
|
assert(!result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_shorter_same};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second);
|
||||||
|
assert(!result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_shorter_greater};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second);
|
||||||
|
assert(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_less};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second);
|
||||||
|
assert(!result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_equal};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second);
|
||||||
|
assert(!result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_greater};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second);
|
||||||
|
assert(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_longer_less};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second);
|
||||||
|
assert(!result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_longer_same};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second);
|
||||||
|
assert(result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_longer_greater};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second);
|
||||||
|
assert(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
In1 empty1{};
|
||||||
|
In2 range2{right_equal};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(empty1, range2, less{}, get_first, get_second);
|
||||||
|
assert(result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 empty2{};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(range1, empty2, less{}, get_first, get_second);
|
||||||
|
assert(!result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
In1 empty1{};
|
||||||
|
In2 empty2{};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(empty1, empty2, less{}, get_first, get_second);
|
||||||
|
assert(!result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate iterator overload
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_shorter_less};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(
|
||||||
|
range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second);
|
||||||
|
assert(!result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_shorter_same};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(
|
||||||
|
range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second);
|
||||||
|
assert(!result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_shorter_greater};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(
|
||||||
|
range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second);
|
||||||
|
assert(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_less};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(
|
||||||
|
range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second);
|
||||||
|
assert(!result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_equal};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(
|
||||||
|
range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second);
|
||||||
|
assert(!result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_greater};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(
|
||||||
|
range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second);
|
||||||
|
assert(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_longer_less};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(
|
||||||
|
range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second);
|
||||||
|
assert(!result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_longer_same};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(
|
||||||
|
range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second);
|
||||||
|
assert(result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 range2{right_longer_greater};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(
|
||||||
|
range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second);
|
||||||
|
assert(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
In1 empty1{};
|
||||||
|
In2 range2{right_equal};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(
|
||||||
|
empty1.begin(), empty1.end(), range2.begin(), range2.end(), less{}, get_first, get_second);
|
||||||
|
assert(result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
In1 range1{left};
|
||||||
|
In2 empty2{};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(
|
||||||
|
range1.begin(), range1.end(), empty2.begin(), empty2.end(), less{}, get_first, get_second);
|
||||||
|
assert(!result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
In1 empty1{};
|
||||||
|
In2 empty2{};
|
||||||
|
const same_as<bool> auto result = lexicographical_compare(
|
||||||
|
empty1.begin(), empty1.end(), empty2.begin(), empty2.end(), less{}, get_first, get_second);
|
||||||
|
assert(!result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef TEST_EVERYTHING
|
||||||
|
int main() {
|
||||||
|
// No constexpr tests here: we hit the constexpr step limits too quickly.
|
||||||
|
test_in_in<instantiator, const P, const P>();
|
||||||
|
}
|
||||||
|
#else // ^^^ test all range combinations / test only interesting combinations vvv
|
||||||
|
template <test::ProxyRef IsProxy>
|
||||||
|
using range_type = test::range<input_iterator_tag, const P, test::Sized::no, test::CanDifference::no, test::Common::no,
|
||||||
|
test::CanCompare::no, IsProxy>;
|
||||||
|
|
||||||
|
constexpr void run_tests() {
|
||||||
|
// The algorithm is very much oblivious to any properties above the minimum requirements: category, size,
|
||||||
|
// difference, none of it matters. Let's test input ranges with and without proxy references.
|
||||||
|
using test::ProxyRef;
|
||||||
|
|
||||||
|
instantiator::call<range_type<ProxyRef::yes>, range_type<ProxyRef::yes>>();
|
||||||
|
instantiator::call<range_type<ProxyRef::yes>, range_type<ProxyRef::no>>();
|
||||||
|
instantiator::call<range_type<ProxyRef::no>, range_type<ProxyRef::yes>>();
|
||||||
|
instantiator::call<range_type<ProxyRef::no>, range_type<ProxyRef::no>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
STATIC_ASSERT((run_tests(), true));
|
||||||
|
run_tests();
|
||||||
|
}
|
||||||
|
#endif // TEST_EVERYTHING
|
Загрузка…
Ссылка в новой задаче