Skip to content

Commit

Permalink
Several range algorithms (#565)
Browse files Browse the repository at this point in the history
* Several range algorithms

In `<algorithm>`, implement:
* the generic algorithm result types from P2106R0 (lines 75-227)
* `ranges::for_each` and its result alias `for_each_result` (lines 289-322)
* `ranges::for_each_n` and its result alias `for_each_result_n` (lines 324-351) from P1243R4
* `ranges::find` (lines 353-384)
* `ranges::find_if` (lines 396-426)
* `ranges::find_if_not` (lines 454-484)
* `ranges::count` (lines 526-568)
* `ranges::count_if` (lines 587-617)
* `ranges::mismatch` and its result alias `mismatch_result` (lines 798-891)
* `ranges::equal` (lines 893-980)
* `ranges::all_of` (lines 1006-1033)
* `ranges::any_of` (lines 1060-1087)
* `ranges::none_of` (lines 1114-1141)
* `ranges::copy` and its result alias `copy_result` (lines 1143-1175)
* `ranges::copy_n` and its result alias `copy_n_result` (lines 1177-1207)
* `ranges::copy_if` and its result alias `copy_if_result` (lines 1262-1302)

In `<concepts>`:
* implement LWG-3194 which includes the resolution of LWG-3151 (lines 51-53)
* LWG-3175 has been merged, remove conditional implementation (line 183)
* replace `boolean` concept with _`boolean-testable`_ concept from P1964R2 (lines 198-237, 283)
* move `movable` (pun intended) into synopsis order (lines 254-256)
* Modify concept `copyable` per P2102R0 (lines 260-261)
* Implement concept `equivalence_relation` from P1716R3 (lines 290-293)

In `<xutility>`:
* promote `identity` from `<functional>` for visibility in `<algorithm>` (lines 160-168)
* promote `common_range` from `<ranges>` for visibility in `<algorithm>` (lines 3091-3095)
* remove LWG-3247 and LWG-3299 annotations (lines 622, 626, and 963)
* prefix `indirectly_` to the names of `readable_traits`, `readable`, and `writable` (a great many lines); and modify `iter_value_t` (lines 366-367), `iter_reference_t` (lines ), `iter_difference_t`, `iter_rvalue_reference_t`, `indirectly_readable` (lines 688-701) and `indirectly_swappable` per P1878R1
* define alias template `_Make_unsigned_like_t` to implement P1522R1's _`make-unsigned-like-t`_ (it does nothing interesting yet, since we provide no integer-class types) (lines 727-729)
* implement the "Indirect callable" concepts `indirectly_unary_invocable`, `indirectly_regular_unary_invocable`, `indirect_unary_predicate`, `indirect_binary_predicate`, `indirect_equivalence_relation`, `indirect_strict_weak_order`, and helpers `indirect_result_t` and `projected` (lines 852-926)
* implement `indirectly_copyable` and `indirectly_copyable_storable` concepts (lines 939-952)
* implement `indirectly_swappable`, `indirectly_comparable`, `permutable`, `mergeable`, and `sortable` concepts (lines 1032-1061)
* rename `safe_range` and `enable_safe_range` to `borrowed_range` and `enable_borrowed_range` per LWG-3379 (lines 2168-2173 and 2327-2330)
* remove "Implements D2091R0" comments (various lines in 2175-2710)
* add `ranges::data` to the list of access CPOs that hard error for arrays of incomplete element types (lines 2204-2205 and 2277-2278)
* `ranges::empty` rejects arrays of unbound bound per P2091R0 (lines 2664-2692)
* implement concept `_Not_same_as` (the exposition-only _`not-same-as`_ from the working draft) (lines 3087-3089)
* implement `ranges::dangling` (lines 3097-3102)
* implement `ranges::borrowed_iterator_t` (lines 3104-3106)

In `<yvals_core.h>`:
* Indicate implementation of:
  * P1207R4 Movability of Single-Pass Iterators
  * P1248R1 Fixing Relations
  * P1474R1 Helpful Pointers For contiguous_iterator
  * P1716R3 Range Comparison Algorithms Are Over-Constrained
  * P1878R1 Constraining Readable Types
  * P1964R2 Replacing `boolean` with _`boolean-testable`_
  * P2091R0 Fixing Issues With Range Access CPOs
  * P2102R0 Make "implicit expression variations" More Explicit
* and partial implementation of:
  * P1243R4 Rangify New Algorithms
* remove conditional definition of `_HAS_STD_BOOLEAN` (we never has `std::boolean` now)

`tests/std/include/instantiate_algorithms.hpp`:
* define non-movable type `Immobile`, and use it to ensure that standard algorithms neither copy nor move random number generators nor uniform random bit generators

Add header `tests/std/include/range_algorithm_support.hpp` with support machinery for the ranges algorithm tests. It notably defines:
* `is_permissive` for determining whether we are compiling in MSVC's permissive mode (lines 18-37)
* A class template `borrowed<bool>` whose specializations always model `range` and model `borrowed_range` iff the template parameter is `true` (lines 39-46)
* Function objects `get_first` and `get_second` which project the pertinent member from `pair` arguments (lines 48-54)
* A class template `move_only_range<T>` which adapts a `contiguous_range` of `T` into a move-only `view` with move-only `input_iterator`s (lines 56-150)
* A "phony" iterator class template `test_iterator` with tunable category, value type, and difference capability for instantiation tests (lines 152-363)
* A similar "phony" class template `test_range` with tunable category, size, and commonality (i.e., is the sentinel type the same as the iterator type) (lines 365-423)
* "phony" predicate and projection types for instantiation tests (lines 425-442)
* combinatoric instantiation machinery for instantiation tests that instantiate with all interesting kinds of output iterators or input ranges (lines 444-529)

A new compile-only test `tests/std/tests/P0896R4_ranges_algorithm_machinery` which covers:
* `indirectly_unary_invocable`/`indirectly_regular_unary_invocable`
* `indirect_unary_predicate`/`indirect_binary_predicate`/`indirect_result_t`
* `projected`
* `indirectly_copyable`/`indirectly_swappable`/`indirectly_comparable`
* `dangling`/`borrowed_iterator_t`
* the result types `in_found_result`/`in_fun_result`/`in_in_result`/`in_out_result`/`in_in_out_result`/`in_out_out_result`/`min_max_result`

Very simple smoke and instantiation tests for the 15 new algorithms in:
* `tests/std/tests/P0896R4_ranges_alg_all_of`
* `tests/std/tests/P0896R4_ranges_alg_any_of`
* `tests/std/tests/P0896R4_ranges_alg_copy`
* `tests/std/tests/P0896R4_ranges_alg_copy_if`
* `tests/std/tests/P0896R4_ranges_alg_copy_n`
* `tests/std/tests/P0896R4_ranges_alg_count`
* `tests/std/tests/P0896R4_ranges_alg_count_if`
* `tests/std/tests/P0896R4_ranges_alg_equal`
* `tests/std/tests/P0896R4_ranges_alg_find`
* `tests/std/tests/P0896R4_ranges_alg_find_if`
* `tests/std/tests/P0896R4_ranges_alg_find_if_not`
* `tests/std/tests/P0896R4_ranges_alg_for_each`
* `tests/std/tests/P0896R4_ranges_alg_for_each_n`
* `tests/std/tests/P0896R4_ranges_alg_mismatch`
* `tests/std/tests/P0896R4_ranges_alg_none_of`

Resolves:
* #537 `<concepts>`: LWG-3175 has been accepted, so we should remove commented-out code
* #540 LWG-3194 `ConvertibleTo` prose does not match code
* #546 LWG-3379 `safe` in several library names is misleading
* #559 P1964R2 "Replacing `boolean` with _`boolean-testable`_"
* #561 P2102R0 "Making 'Implicit Expression Variations' More Explicit"
* #563 P2091R0 "Fixing Issues With Range Access CPOs"
  • Loading branch information
CaseyCarter authored Mar 5, 2020
1 parent 3690083 commit 930b843
Show file tree
Hide file tree
Showing 47 changed files with 3,333 additions and 327 deletions.
800 changes: 800 additions & 0 deletions stl/inc/algorithm

Large diffs are not rendered by default.

83 changes: 38 additions & 45 deletions stl/inc/concepts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,9 @@ concept derived_from = __is_base_of(_Base, _Derived)
// CONCEPT convertible_to
template <class _From, class _To>
concept convertible_to = __is_convertible_to(_From, _To)
#if 1 // Implement the PR of LWG-3151
&& requires { static_cast<_To>(_STD declval<_From>()); };
#else // ^^^ LWG-3151 / N4810 vvv
&& requires(_From (&_Fn)()) { static_cast<_To>(_Fn()); };
#endif // select LWG-3151 vs. N4810
&& requires(add_rvalue_reference_t<_From> (&_Fn)()) {
static_cast<_To>(_Fn());
};

// CONCEPT common_reference_with
template <class _Ty1, class _Ty2>
Expand Down Expand Up @@ -181,12 +179,7 @@ concept swappable = requires(_Ty& __x, _Ty& __y) {

// CONCEPT swappable_with
template <class _Ty1, class _Ty2>
concept swappable_with =
#if 1 // Implement the PR of LWG-3175
common_reference_with<_Ty1, _Ty2>
#else // ^^^ LWG-3175 / N4810 vvv
common_reference_with<const remove_reference_t<_Ty1>&, const remove_reference_t<_Ty2>&>
#endif // select LWG-3175 vs. N4810
concept swappable_with = common_reference_with<_Ty1, _Ty2>
&& requires(_Ty1&& __t, _Ty2&& __u) {
_RANGES swap(static_cast<_Ty1&&>(__t), static_cast<_Ty1&&>(__t));
_RANGES swap(static_cast<_Ty2&&>(__u), static_cast<_Ty2&&>(__u));
Expand All @@ -201,41 +194,22 @@ concept copy_constructible = move_constructible<_Ty>
&& constructible_from<_Ty, const _Ty&> && convertible_to<const _Ty&, _Ty>
&& constructible_from<_Ty, const _Ty> && convertible_to<const _Ty, _Ty>;

// CONCEPT movable
// CONCEPT _Boolean_testable
template <class _Ty>
concept movable = is_object_v<_Ty> && move_constructible<_Ty> && assignable_from<_Ty&, _Ty> && swappable<_Ty>;

// CONCEPT boolean
#if _HAS_STD_BOOLEAN
#define _STL_BOOLEAN_CONCEPT boolean
#else
#define _STL_BOOLEAN_CONCEPT _Boolean
#endif
concept _Boolean_testable_impl = convertible_to<_Ty, bool>;

template <class _Ty>
concept _STL_BOOLEAN_CONCEPT = movable<remove_cvref_t<_Ty>>
&& requires(const remove_reference_t<_Ty>& __x, const remove_reference_t<_Ty>& __y, const bool __b) {
{ __x } -> convertible_to<bool>;
{ !__x } -> convertible_to<bool>;
{ __x && __y } -> same_as<bool>;
{ __x && __b } -> same_as<bool>;
{ __b && __y } -> same_as<bool>;
{ __x || __y } -> same_as<bool>;
{ __x || __b } -> same_as<bool>;
{ __b || __y } -> same_as<bool>;
{ __x == __y } -> convertible_to<bool>;
{ __x == __b } -> convertible_to<bool>;
{ __b == __y } -> convertible_to<bool>;
{ __x != __y } -> convertible_to<bool>;
{ __x != __b } -> convertible_to<bool>;
{ __b != __y } -> convertible_to<bool>;
concept _Boolean_testable = _Boolean_testable_impl<_Ty>
&& requires (_Ty&& __t) {
{ !static_cast<_Ty&&>(__t) } -> _Boolean_testable_impl;
};

// CONCEPT _Weakly_equality_comparable_with
template <class _Ty1, class _Ty2>
concept _Half_equality_comparable =
requires(const remove_reference_t<_Ty1>& __x, const remove_reference_t<_Ty2>& __y) {
{ __x == __y } -> _STL_BOOLEAN_CONCEPT;
{ __x != __y } -> _STL_BOOLEAN_CONCEPT;
{ __x == __y } -> _Boolean_testable;
{ __x != __y } -> _Boolean_testable;
};

template <class _Ty1, class _Ty2>
Expand All @@ -257,10 +231,10 @@ concept equality_comparable_with = equality_comparable<_Ty1> && equality_compara
// CONCEPT _Partially_ordered_with
template <class _Ty1, class _Ty2>
concept _Half_ordered = requires(const remove_reference_t<_Ty1>& __t, const remove_reference_t<_Ty2>& __u) {
{ __t < __u } -> _STL_BOOLEAN_CONCEPT;
{ __t > __u } -> _STL_BOOLEAN_CONCEPT;
{ __t <= __u } -> _STL_BOOLEAN_CONCEPT;
{ __t >= __u } -> _STL_BOOLEAN_CONCEPT;
{ __t < __u } -> _Boolean_testable;
{ __t > __u } -> _Boolean_testable;
{ __t <= __u } -> _Boolean_testable;
{ __t >= __u } -> _Boolean_testable;
};

template <class _Ty1, class _Ty2>
Expand All @@ -277,9 +251,20 @@ concept totally_ordered_with = totally_ordered<_Ty1> && totally_ordered<_Ty2>
&& totally_ordered<common_reference_t<const remove_reference_t<_Ty1>&, const remove_reference_t<_Ty2>&>>
&& _Partially_ordered_with<_Ty1, _Ty2>;

// CONCEPT movable
template <class _Ty>
concept movable = is_object_v<_Ty>
&& move_constructible<_Ty>
&& assignable_from<_Ty&, _Ty>
&& swappable<_Ty>;

// CONCEPT copyable
template <class _Ty>
concept copyable = copy_constructible<_Ty> && movable<_Ty> && assignable_from<_Ty&, const _Ty&>;
concept copyable = copy_constructible<_Ty>
&& movable<_Ty>
&& assignable_from<_Ty&, _Ty&>
&& assignable_from<_Ty&, const _Ty&>
&& assignable_from<_Ty&, const _Ty>;

// CONCEPT semiregular
template <class _Ty>
Expand All @@ -301,13 +286,21 @@ concept regular_invocable = invocable<_FTy, _ArgTys...>;

// CONCEPT predicate
template <class _FTy, class... _ArgTys>
concept predicate = regular_invocable<_FTy, _ArgTys...> && _STL_BOOLEAN_CONCEPT<invoke_result_t<_FTy, _ArgTys...>>;
concept predicate = regular_invocable<_FTy, _ArgTys...>
&& _Boolean_testable<invoke_result_t<_FTy, _ArgTys...>>;

// CONCEPT relation
template <class _FTy, class _Ty1, class _Ty2>
concept relation = predicate<_FTy, _Ty1, _Ty1> && predicate<_FTy, _Ty2, _Ty2> && predicate<_FTy, _Ty1, _Ty2>
concept relation =
predicate<_FTy, _Ty1, _Ty1>
&& predicate<_FTy, _Ty2, _Ty2>
&& predicate<_FTy, _Ty1, _Ty2>
&& predicate<_FTy, _Ty2, _Ty1>;

// CONCEPT equivalence_relation
template <class _FTy, class _Ty1, class _Ty2>
concept equivalence_relation = relation<_FTy, _Ty1, _Ty2>;

// CONCEPT strict_weak_order
template <class _FTy, class _Ty1, class _Ty2>
concept strict_weak_order = relation<_FTy, _Ty1, _Ty2>;
Expand Down
12 changes: 0 additions & 12 deletions stl/inc/functional
Original file line number Diff line number Diff line change
Expand Up @@ -658,18 +658,6 @@ _NODISCARD _Mem_fn<_Rx _Ty::*> mem_fn(_Rx _Ty::*_Pm) noexcept {
return _Mem_fn<_Rx _Ty::*>(_Pm);
}

#if _HAS_CXX20
// STRUCT identity
struct identity {
template <class _Ty>
_NODISCARD constexpr _Ty&& operator()(_Ty&& _Left) const noexcept {
return _STD forward<_Ty>(_Left);
}

using is_transparent = int;
};
#endif // _HAS_CXX20

#if _HAS_CXX17
// FUNCTION TEMPLATE not_fn
struct _Not_fn_tag {
Expand Down
9 changes: 3 additions & 6 deletions stl/inc/ranges
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,12 @@ namespace ranges {
// Much machinery defined in <xutility>

// clang-format off
// CONCEPT ranges::common_range
template <class _Rng>
concept common_range = range<_Rng> && same_as<iterator_t<_Rng>, sentinel_t<_Rng>>;

// CONCEPT ranges::viewable_range
template <class _Rng>
concept viewable_range = range<_Rng> && (safe_range<_Rng> || view<remove_cvref_t<_Rng>>);
// clang-format on
concept viewable_range = range<_Rng>
&& (borrowed_range<_Rng> || view<remove_cvref_t<_Rng>>);
} // namespace ranges

_STD_END

#pragma pop_macro("new")
Expand Down
4 changes: 2 additions & 2 deletions stl/inc/span
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ class span;
#ifdef __cpp_lib_concepts
namespace ranges {
template <class _Ty, size_t _Extent>
inline constexpr bool enable_safe_range<span<_Ty, _Extent>> = true;
inline constexpr bool enable_borrowed_range<span<_Ty, _Extent>> = true;
} // namespace ranges

// VARIABLE TEMPLATE _Is_span_v
Expand Down Expand Up @@ -293,7 +293,7 @@ concept _Is_span_compatible_range =
&& !_Is_std_array_v<remove_cvref_t<_Rng>>
&& _RANGES contiguous_range<_Rng>
&& _RANGES sized_range<_Rng>
&& (_RANGES safe_range<_Rng> || is_const_v<_Ty>)
&& (_RANGES borrowed_range<_Rng> || is_const_v<_Ty>)
&& is_convertible_v<remove_reference_t<_RANGES range_reference_t<_Rng>>(*)[], _Ty(*)[]>;
// clang-format on
#else // ^^^ __cpp_lib_concepts / !__cpp_lib_concepts vvv
Expand Down
2 changes: 1 addition & 1 deletion stl/inc/xstring
Original file line number Diff line number Diff line change
Expand Up @@ -1576,7 +1576,7 @@ private:
#ifdef __cpp_lib_concepts
namespace ranges {
template <class _Elem, class _Traits>
inline constexpr bool enable_safe_range<basic_string_view<_Elem, _Traits>> = true;
inline constexpr bool enable_borrowed_range<basic_string_view<_Elem, _Traits>> = true;
} // namespace ranges
#endif // __cpp_lib_concepts

Expand Down
Loading

0 comments on commit 930b843

Please sign in to comment.