forked from OSchip/llvm-project
[libc++][ranges] Implement `std::mergeable`.
Differential Revision: https://reviews.llvm.org/D119489
This commit is contained in:
parent
6b53ad298e
commit
eea3d90af1
|
@ -65,7 +65,7 @@ Section,Description,Dependencies,Assignee,Complete
|
|||
| [iterator.cust.swap]",Zoe Carver,✅
|
||||
`[alg.req] <https://wg21.link/alg.req>`_: pt. 3,`indirectly_comparable <https://llvm.org/D116268>`_,[projected],Nikolas Klauser,✅
|
||||
`[alg.req] <https://wg21.link/alg.req>`_: pt. 4,"| `permutable <https://llvm.org/D119222>`_
|
||||
| mergeable
|
||||
| `mergeable <https://llvm.org/D119489>`_
|
||||
| sortable",[iterator.concepts],Konstantin Varlamov,In progress
|
||||
`[std.iterator.tags] <https://wg21.link/std.iterator.tags>`_,"| `contiguous_iterator_tag <https://llvm.org/rG45d048c20440989df2b4e1be1f9343225e7741ab>`_
|
||||
| `iterator_concept specialization for pointers <https://llvm.org/rG45d048c20440989df2b4e1be1f9343225e7741ab>`_
|
||||
|
|
|
|
@ -243,6 +243,7 @@ set(files
|
|||
__iterator/iter_swap.h
|
||||
__iterator/iterator.h
|
||||
__iterator/iterator_traits.h
|
||||
__iterator/mergeable.h
|
||||
__iterator/move_iterator.h
|
||||
__iterator/next.h
|
||||
__iterator/ostream_iterator.h
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___ITERATOR_MERGEABLE_H
|
||||
#define _LIBCPP___ITERATOR_MERGEABLE_H
|
||||
|
||||
#include <__config>
|
||||
#include <__functional/identity.h>
|
||||
#include <__functional/ranges_operations.h>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/projected.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||
|
||||
template <class _Input1, class _Input2, class _Output,
|
||||
class _Comp = ranges::less, class _Proj1 = identity, class _Proj2 = identity>
|
||||
concept mergeable =
|
||||
input_iterator<_Input1> &&
|
||||
input_iterator<_Input2> &&
|
||||
weakly_incrementable<_Output> &&
|
||||
indirectly_copyable<_Input1, _Output> &&
|
||||
indirectly_copyable<_Input2, _Output> &&
|
||||
indirect_strict_weak_order<_Comp, projected<_Input1, _Proj1>, projected<_Input2, _Proj2>>;
|
||||
|
||||
#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___ITERATOR_MERGEABLE_H
|
|
@ -147,15 +147,20 @@ template<class In, class Out>
|
|||
template<class I1, class I2 = I1>
|
||||
concept indirectly_swappable = see below; // since C++20
|
||||
|
||||
// [alg.req.permutable], concept permutable // since C++20
|
||||
template<class I>
|
||||
concept permutable = see below;
|
||||
|
||||
template<class I1, class I2, class R, class P1 = identity,
|
||||
class P2 = identity>
|
||||
concept indirectly_comparable =
|
||||
indirect_binary_predicate<R, projected<I1, P1>, projected<I2, P2>>; // since C++20
|
||||
|
||||
// [alg.req.permutable], concept permutable // since C++20
|
||||
template<class I>
|
||||
concept permutable = see below;
|
||||
|
||||
// [alg.req.mergeable], concept mergeable
|
||||
template<class I1, class I2, class Out,
|
||||
class R = ranges::less, class P1 = identity, class P2 = identity>
|
||||
concept mergeable = see below; // since C++20
|
||||
|
||||
template<input_or_output_iterator I, sentinel_for<I> S>
|
||||
requires (!same_as<I, S> && copyable<I>)
|
||||
class common_iterator; // since C++20
|
||||
|
@ -623,6 +628,7 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
|
|||
#include <__iterator/iter_swap.h>
|
||||
#include <__iterator/iterator.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__iterator/mergeable.h>
|
||||
#include <__iterator/move_iterator.h>
|
||||
#include <__iterator/next.h>
|
||||
#include <__iterator/ostream_iterator.h>
|
||||
|
|
|
@ -628,6 +628,7 @@ module std [system] {
|
|||
module iter_swap { private header "__iterator/iter_swap.h" }
|
||||
module iterator { private header "__iterator/iterator.h" }
|
||||
module iterator_traits { private header "__iterator/iterator_traits.h" }
|
||||
module mergeable { private header "__iterator/mergeable.h" }
|
||||
module move_iterator { private header "__iterator/move_iterator.h" }
|
||||
module next { private header "__iterator/next.h" }
|
||||
module ostream_iterator { private header "__iterator/ostream_iterator.h" }
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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: modules-build
|
||||
|
||||
// WARNING: This test was generated by 'generate_private_header_tests.py'
|
||||
// and should not be edited manually.
|
||||
|
||||
// expected-error@*:* {{use of private header from outside its module: '__iterator/mergeable.h'}}
|
||||
#include <__iterator/mergeable.h>
|
|
@ -0,0 +1,129 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// template<class I1, class I2, class Out,
|
||||
// class R = ranges::less, class P1 = identity, class P2 = identity>
|
||||
// concept mergeable = see below; // since C++20
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
using CompDefault = std::ranges::less;
|
||||
using CompInt = bool(*)(int, int);
|
||||
using ProjDefault = std::identity;
|
||||
|
||||
using Input = cpp20_input_iterator<int*>;
|
||||
static_assert( std::input_iterator<Input>);
|
||||
using InputLong = cpp20_input_iterator<long*>;
|
||||
static_assert( std::input_iterator<InputLong>);
|
||||
|
||||
using Output = cpp17_output_iterator<int*>;
|
||||
static_assert( std::weakly_incrementable<Output>);
|
||||
|
||||
static_assert( std::indirectly_copyable<Input, Output>);
|
||||
static_assert( std::indirectly_copyable<InputLong, Output>);
|
||||
static_assert( std::indirect_strict_weak_order<CompDefault, Input, Input>);
|
||||
static_assert( std::indirect_strict_weak_order<CompInt, Input, Input>);
|
||||
static_assert( std::indirect_strict_weak_order<CompDefault, Input, InputLong>);
|
||||
static_assert( std::indirect_strict_weak_order<CompInt, Input, InputLong>);
|
||||
|
||||
// All requirements satisfied.
|
||||
static_assert( std::mergeable<Input, Input, Output>);
|
||||
static_assert( std::mergeable<Input, Input, Output, CompInt>);
|
||||
static_assert( std::mergeable<Input, Input, Output, CompInt, ProjDefault>);
|
||||
|
||||
// Non-default projections.
|
||||
struct Foo {};
|
||||
using ProjFooToInt = int(*)(Foo);
|
||||
using ProjFooToLong = long(*)(Foo);
|
||||
static_assert( std::indirect_strict_weak_order<CompDefault,
|
||||
std::projected<Foo*, ProjFooToInt>, std::projected<Foo*, ProjFooToLong>>);
|
||||
static_assert( std::mergeable<Foo*, Foo*, Foo*, CompDefault, ProjFooToInt, ProjFooToLong>);
|
||||
static_assert( std::indirect_strict_weak_order<CompInt,
|
||||
std::projected<Foo*, ProjFooToInt>, std::projected<Foo*, ProjFooToLong>>);
|
||||
static_assert( std::mergeable<Foo*, Foo*, Foo*, CompInt, ProjFooToInt, ProjFooToLong>);
|
||||
|
||||
// I1 or I2 is not an input iterator.
|
||||
static_assert(!std::input_iterator<Output>);
|
||||
static_assert(!std::mergeable<Output, Input, Output>);
|
||||
static_assert(!std::mergeable<Input, Output, Output>);
|
||||
|
||||
// O is not weakly incrementable.
|
||||
struct NotWeaklyIncrementable {
|
||||
int& operator*() const;
|
||||
};
|
||||
|
||||
static_assert(!std::weakly_incrementable<NotWeaklyIncrementable>);
|
||||
static_assert( std::indirectly_copyable<Input, NotWeaklyIncrementable>);
|
||||
static_assert( std::indirect_strict_weak_order<CompDefault, Input, Input>);
|
||||
static_assert(!std::mergeable<Input, Input, NotWeaklyIncrementable>);
|
||||
|
||||
// I1 or I2 is not indirectly copyable into O.
|
||||
struct AssignableOnlyFromInt {
|
||||
AssignableOnlyFromInt& operator=(int);
|
||||
template <class T>
|
||||
AssignableOnlyFromInt& operator=(T) = delete;
|
||||
};
|
||||
using OutputOnlyInt = cpp17_output_iterator<AssignableOnlyFromInt*>;
|
||||
static_assert( std::weakly_incrementable<OutputOnlyInt>);
|
||||
|
||||
static_assert( std::indirectly_copyable<Input, OutputOnlyInt>);
|
||||
static_assert(!std::indirectly_copyable<InputLong, OutputOnlyInt>);
|
||||
static_assert( std::indirect_strict_weak_order<CompDefault, Input, InputLong>);
|
||||
static_assert( std::mergeable<Input, Input, OutputOnlyInt>);
|
||||
static_assert(!std::mergeable<Input, InputLong, OutputOnlyInt>);
|
||||
static_assert(!std::mergeable<InputLong, Input, OutputOnlyInt>);
|
||||
|
||||
// No indirect strict weak order between I1 and I2 (bad comparison functor).
|
||||
using GoodComp = bool(*)(int, int);
|
||||
static_assert( std::indirect_strict_weak_order<GoodComp, Input, Input>);
|
||||
static_assert( std::mergeable<Input, Input, Output, GoodComp>);
|
||||
using BadComp = bool(*)(int*, int*);
|
||||
static_assert(!std::indirect_strict_weak_order<BadComp, Input, Input>);
|
||||
static_assert(!std::mergeable<Input, Input, Output, BadComp>);
|
||||
|
||||
// No indirect strict weak order between I1 and I2 (bad projection).
|
||||
using ToInt = int(*)(int);
|
||||
using ToPtr = int*(*)(int);
|
||||
static_assert( std::mergeable<Input, Input, Output, GoodComp, std::identity, std::identity>);
|
||||
static_assert( std::mergeable<Input, Input, Output, GoodComp, ToInt, ToInt>);
|
||||
static_assert(!std::mergeable<Input, Input, Output, GoodComp, ToPtr, ToInt>);
|
||||
static_assert(!std::mergeable<Input, Input, Output, GoodComp, ToInt, ToPtr>);
|
||||
static_assert(!std::mergeable<Input, Input, Output, bool(*)(int*, int), ToPtr, ToInt>);
|
||||
static_assert(!std::mergeable<Input, Input, Output, bool(*)(int, int*), ToInt, ToPtr>);
|
||||
|
||||
// A projection that only supports non-const references and has a non-const `operator()` still has to work.
|
||||
struct ProjectionOnlyMutable {
|
||||
int operator()(int&);
|
||||
int operator()(int&&) const = delete;
|
||||
};
|
||||
static_assert( std::mergeable<Input, Input, Output, CompDefault, ProjectionOnlyMutable, ProjectionOnlyMutable>);
|
||||
|
||||
// The output is weakly incrementable but not an output iterator.
|
||||
struct WeaklyIncrementable {
|
||||
using value_type = int;
|
||||
using difference_type = int;
|
||||
|
||||
int& operator*() const;
|
||||
WeaklyIncrementable& operator++();
|
||||
// `output_iterator` requires `i++` to return an iterator,
|
||||
// while `weakly_incrementable` requires only that `i++` be well-formed.
|
||||
void operator++(int);
|
||||
};
|
||||
static_assert( std::weakly_incrementable<WeaklyIncrementable>);
|
||||
static_assert( std::indirectly_copyable<int*, WeaklyIncrementable>);
|
||||
static_assert(!std::output_iterator<WeaklyIncrementable, int>);
|
||||
static_assert( std::mergeable<Input, Input, WeaklyIncrementable>);
|
|
@ -0,0 +1,38 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// template<class I1, class I2, class Out,
|
||||
// class R = ranges::less, class P1 = identity, class P2 = identity>
|
||||
// concept mergeable = see below; // since C++20
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class I1, class I2, class O>
|
||||
void test_subsumption() requires std::input_iterator<I1> && std::input_iterator<I2>;
|
||||
|
||||
template <class I1, class I2, class O>
|
||||
void test_subsumption() requires std::weakly_incrementable<O>;
|
||||
|
||||
template <class I1, class I2, class O>
|
||||
void test_subsumption() requires std::indirectly_copyable<I1, O> && std::indirectly_copyable<I2, O>;
|
||||
|
||||
template <class I1, class I2, class O>
|
||||
void test_subsumption() requires std::indirect_strict_weak_order<I1, I2>;
|
||||
|
||||
template <class I1, class I2, class O>
|
||||
constexpr bool test_subsumption() requires std::mergeable<I1, I2, O> {
|
||||
return true;
|
||||
}
|
||||
|
||||
static_assert(test_subsumption<int*, int*, int*>());
|
Loading…
Reference in New Issue