Skip to content

Commit

Permalink
P2609R3: Relaxing Ranges Just A Smidge (#3486)
Browse files Browse the repository at this point in the history
Co-authored-by: Casey Carter <Casey@Carter.net>
  • Loading branch information
JMazurkiewicz and CaseyCarter authored Feb 23, 2023
1 parent 10aab6d commit 2aa2ff9
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 58 deletions.
107 changes: 54 additions & 53 deletions stl/inc/xutility
Original file line number Diff line number Diff line change
Expand Up @@ -493,24 +493,33 @@ _EXPORT_STD template <class _Ty>
{ _RANGES iter_move(__t) } -> _Can_reference;
}
using iter_rvalue_reference_t = decltype(_RANGES iter_move(_STD declval<_Ty&>()));
// clang-format on

template <class _It>
concept _Indirectly_readable_impl = requires(const _It __i) {
typename iter_value_t<_It>;
typename iter_reference_t<_It>;
typename iter_rvalue_reference_t<_It>;
{ *__i } -> same_as<iter_reference_t<_It>>;
{ _RANGES iter_move(__i) } -> same_as<iter_rvalue_reference_t<_It>>;
} && common_reference_with<iter_reference_t<_It>&&, iter_value_t<_It>&>
&& common_reference_with<iter_reference_t<_It>&&, iter_rvalue_reference_t<_It>&&>
&& common_reference_with<iter_rvalue_reference_t<_It>&&, const iter_value_t<_It>&>;
concept _Indirectly_readable_impl =
requires(const _It __i) {
typename iter_value_t<_It>;
typename iter_reference_t<_It>;
typename iter_rvalue_reference_t<_It>;
{ *__i } -> same_as<iter_reference_t<_It>>;
{ _RANGES iter_move(__i) } -> same_as<iter_rvalue_reference_t<_It>>;
} && common_reference_with<iter_reference_t<_It>&&, iter_value_t<_It>&>
&& common_reference_with<iter_reference_t<_It>&&, iter_rvalue_reference_t<_It>&&>
&& common_reference_with<iter_rvalue_reference_t<_It>&&, const iter_value_t<_It>&>;

_EXPORT_STD template <class _It>
concept indirectly_readable = _Indirectly_readable_impl<remove_cvref_t<_It>>;
// clang-format on

template <class _Ty>
struct _Indirect_value_impl {
using type = iter_value_t<_Ty>&;
};

template <indirectly_readable _It>
using _Indirect_value_t = typename _Indirect_value_impl<_It>::type;

_EXPORT_STD template <indirectly_readable _Ty>
using iter_common_reference_t = common_reference_t<iter_reference_t<_Ty>, iter_value_t<_Ty>&>;
using iter_common_reference_t = common_reference_t<iter_reference_t<_Ty>, _Indirect_value_t<_Ty>>;

_EXPORT_STD template <class _It, class _Ty>
concept indirectly_writable =
Expand Down Expand Up @@ -629,69 +638,56 @@ concept contiguous_iterator = random_access_iterator<_It>
&& requires(const _It& __i) {
{ _STD to_address(__i) } -> same_as<add_pointer_t<iter_reference_t<_It>>>;
};
// clang-format on

_EXPORT_STD template <class _Fn, class _It>
concept indirectly_unary_invocable = indirectly_readable<_It>
&& copy_constructible<_Fn>
&& invocable<_Fn&, iter_value_t<_It>&>
&& invocable<_Fn&, iter_reference_t<_It>>
&& invocable<_Fn&, iter_common_reference_t<_It>>
&& common_reference_with<
invoke_result_t<_Fn&, iter_value_t<_It>&>,
concept indirectly_unary_invocable =
indirectly_readable<_It> && copy_constructible<_Fn> && invocable<_Fn&, _Indirect_value_t<_It>>
&& invocable<_Fn&, iter_reference_t<_It>> && invocable<_Fn&, iter_common_reference_t<_It>>
&& common_reference_with<invoke_result_t<_Fn&, _Indirect_value_t<_It>>,
invoke_result_t<_Fn&, iter_reference_t<_It>>>;

_EXPORT_STD template <class _Fn, class _It>
concept indirectly_regular_unary_invocable = indirectly_readable<_It>
&& copy_constructible<_Fn>
&& regular_invocable<_Fn&, iter_value_t<_It>&>
&& regular_invocable<_Fn&, iter_reference_t<_It>>
&& regular_invocable<_Fn&, iter_common_reference_t<_It>>
&& common_reference_with<
invoke_result_t<_Fn&, iter_value_t<_It>&>,
concept indirectly_regular_unary_invocable =
indirectly_readable<_It> && copy_constructible<_Fn> && regular_invocable<_Fn&, _Indirect_value_t<_It>>
&& regular_invocable<_Fn&, iter_reference_t<_It>> && regular_invocable<_Fn&, iter_common_reference_t<_It>>
&& common_reference_with<invoke_result_t<_Fn&, _Indirect_value_t<_It>>,
invoke_result_t<_Fn&, iter_reference_t<_It>>>;

_EXPORT_STD template <class _Fn, class _It>
concept indirect_unary_predicate = indirectly_readable<_It>
&& copy_constructible<_Fn>
&& predicate<_Fn&, iter_value_t<_It>&>
&& predicate<_Fn&, iter_reference_t<_It>>
&& predicate<_Fn&, iter_common_reference_t<_It>>;
concept indirect_unary_predicate =
indirectly_readable<_It> && copy_constructible<_Fn> && predicate<_Fn&, _Indirect_value_t<_It>>
&& predicate<_Fn&, iter_reference_t<_It>> && predicate<_Fn&, iter_common_reference_t<_It>>;

_EXPORT_STD template <class _Fn, class _It1, class _It2>
concept indirect_binary_predicate = indirectly_readable<_It1>
&& indirectly_readable<_It2>
&& copy_constructible<_Fn>
&& predicate<_Fn&, iter_value_t<_It1>&, iter_value_t<_It2>&>
&& predicate<_Fn&, iter_value_t<_It1>&, iter_reference_t<_It2>>
&& predicate<_Fn&, iter_reference_t<_It1>, iter_value_t<_It2>&>
&& predicate<_Fn&, iter_reference_t<_It1>, iter_reference_t<_It2>>
&& predicate<_Fn&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;
concept indirect_binary_predicate = indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fn>
&& predicate<_Fn&, _Indirect_value_t<_It1>, _Indirect_value_t<_It2>>
&& predicate<_Fn&, _Indirect_value_t<_It1>, iter_reference_t<_It2>>
&& predicate<_Fn&, iter_reference_t<_It1>, _Indirect_value_t<_It2>>
&& predicate<_Fn&, iter_reference_t<_It1>, iter_reference_t<_It2>>
&& predicate<_Fn&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;

_EXPORT_STD template <class _Fn, class _It1, class _It2 = _It1>
concept indirect_equivalence_relation = indirectly_readable<_It1>
&& indirectly_readable<_It2>
&& copy_constructible<_Fn>
&& equivalence_relation<_Fn&, iter_value_t<_It1>&, iter_value_t<_It2>&>
&& equivalence_relation<_Fn&, iter_value_t<_It1>&, iter_reference_t<_It2>>
&& equivalence_relation<_Fn&, iter_reference_t<_It1>, iter_value_t<_It2>&>
concept indirect_equivalence_relation =
indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fn>
&& equivalence_relation<_Fn&, _Indirect_value_t<_It1>, _Indirect_value_t<_It2>>
&& equivalence_relation<_Fn&, _Indirect_value_t<_It1>, iter_reference_t<_It2>>
&& equivalence_relation<_Fn&, iter_reference_t<_It1>, _Indirect_value_t<_It2>>
&& equivalence_relation<_Fn&, iter_reference_t<_It1>, iter_reference_t<_It2>>
&& equivalence_relation<_Fn&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;

_EXPORT_STD template <class _Fn, class _It1, class _It2 = _It1>
concept indirect_strict_weak_order = indirectly_readable<_It1>
&& indirectly_readable<_It2>
&& copy_constructible<_Fn>
&& strict_weak_order<_Fn&, iter_value_t<_It1>&, iter_value_t<_It2>&>
&& strict_weak_order<_Fn&, iter_value_t<_It1>&, iter_reference_t<_It2>>
&& strict_weak_order<_Fn&, iter_reference_t<_It1>, iter_value_t<_It2>&>
concept indirect_strict_weak_order =
indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fn>
&& strict_weak_order<_Fn&, _Indirect_value_t<_It1>, _Indirect_value_t<_It2>>
&& strict_weak_order<_Fn&, _Indirect_value_t<_It1>, iter_reference_t<_It2>>
&& strict_weak_order<_Fn&, iter_reference_t<_It1>, _Indirect_value_t<_It2>>
&& strict_weak_order<_Fn&, iter_reference_t<_It1>, iter_reference_t<_It2>>
&& strict_weak_order<_Fn&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;

_EXPORT_STD template <class _Fn, class... _Its>
requires (indirectly_readable<_Its> && ...)
&& invocable<_Fn, iter_reference_t<_Its>...>
requires (indirectly_readable<_Its> && ...) && invocable<_Fn, iter_reference_t<_Its>...>
using indirect_result_t = invoke_result_t<_Fn, iter_reference_t<_Its>...>;
// clang-format on

_EXPORT_STD template <indirectly_readable _It, indirectly_regular_unary_invocable<_It> _Proj>
struct projected {
Expand All @@ -701,6 +697,11 @@ struct projected {
}
};

template <class _It, class _Proj>
struct _Indirect_value_impl<projected<_It, _Proj>> {
using type = invoke_result_t<_Proj&, _Indirect_value_t<_It>>;
};

template <weakly_incrementable _It, class _Proj>
struct incrementable_traits<projected<_It, _Proj>> {
using difference_type = iter_difference_t<_It>;
Expand Down
5 changes: 3 additions & 2 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@
// P2508R1 basic_format_string, format_string, wformat_string
// P2520R0 move_iterator<T*> Should Be A Random-Access Iterator
// P2588R3 barrier's Phase Completion Guarantees
// P2602R2 Poison Pills Are Too Toxic
// P2609R3 Relaxing Ranges Just A Smidge
// P2711R1 Making Multi-Param Constructors Of Views explicit

// _HAS_CXX20 indirectly controls:
Expand Down Expand Up @@ -351,7 +353,6 @@
// P2499R0 string_view Range Constructor Should Be explicit
// P2505R5 Monadic Functions For expected
// P2549R1 unexpected<E>::error()
// P2602R2 Poison Pills Are Too Toxic

// Parallel Algorithms Notes
// C++ allows an implementation to implement parallel algorithms as calls to the serial algorithms.
Expand Down Expand Up @@ -1762,7 +1763,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect

#if defined(__cpp_lib_concepts) // TRANSITION, GH-395
#if _HAS_CXX23
#define __cpp_lib_ranges 202211L // P2602R2 Poison Pills Are Too Toxic
#define __cpp_lib_ranges 202302L // P2609R3 Relaxing Ranges Just A Smidge
#elif _HAS_CXX20 // ^^^ _HAS_CXX23 / _HAS_CXX20 vvv
#define __cpp_lib_ranges 202110L // P2415R2 What Is A view?
#endif // _HAS_CXX20
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,7 @@ tests\P2474R2_views_repeat_death
tests\P2494R2_move_only_range_adaptors
tests\P2505R5_monadic_functions_for_std_expected
tests\P2517R1_apply_conditional_noexcept
tests\P2609R3_relaxing_ranges_just_a_smidge
tests\VSO_0000000_allocator_propagation
tests\VSO_0000000_any_calling_conventions
tests\VSO_0000000_c_math_functions
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/P2609R3_relaxing_ranges_just_a_smidge/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\concepts_latest_matrix.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <algorithm>
#include <memory>
#include <ranges>
#include <utility>
#include <vector>

using namespace std;

void test() {
auto ints = views::iota(0, 5);
auto project_to_unique_ptr = []<movable T>(T v) { return make_unique<T>(move(v)); };

using It = ranges::iterator_t<decltype(ints)>;
using Proj = decltype(project_to_unique_ptr);
using ProjectedIt = projected<It, Proj>;

{ // Check indirectly_unary_invocable
auto consume = [](auto) {};
static_assert(indirectly_unary_invocable<decltype(consume), ProjectedIt>);

ranges::for_each(ints, consume, project_to_unique_ptr);
ranges::for_each(ints.begin(), ints.end(), consume, project_to_unique_ptr);
}

{ // Check indirectly_regular_unary_invocable
static_assert(indirectly_regular_unary_invocable<decltype([](auto) {}), ProjectedIt>);
using Check [[maybe_unused]] = projected<ProjectedIt, Proj>;
}

{ // Check indirect_unary_predicate
auto unary_pred = [](auto) { return false; };
static_assert(indirect_unary_predicate<decltype(unary_pred), ProjectedIt>);

(void) ranges::find_if(ints, unary_pred, project_to_unique_ptr);
(void) ranges::find_if(ints.begin(), ints.end(), unary_pred, project_to_unique_ptr);
(void) ranges::count_if(ints, unary_pred, project_to_unique_ptr);
(void) ranges::count_if(ints.begin(), ints.end(), unary_pred, project_to_unique_ptr);
}

{ // Check indirect_binary_predicate
auto binary_pred = [](auto, auto) { return false; };
static_assert(indirect_binary_predicate<decltype(binary_pred), ProjectedIt, ProjectedIt>);

(void) ranges::adjacent_find(ints, binary_pred, project_to_unique_ptr);
(void) ranges::adjacent_find(ints.begin(), ints.end(), binary_pred, project_to_unique_ptr);
}

{ // Check indirect_equivalence_relation
auto rel = [](auto, auto) { return false; };
static_assert(indirect_equivalence_relation<decltype(rel), ProjectedIt>);

vector<int> out;
(void) ranges::unique_copy(ints, back_inserter(out), rel, project_to_unique_ptr);
(void) ranges::unique_copy(ints.begin(), ints.end(), back_inserter(out), rel, project_to_unique_ptr);
}

{ // Check indirect_strict_weak_order
auto rel = [](auto x, auto y) { return x < y; };
static_assert(indirect_strict_weak_order<decltype(rel), ProjectedIt>);

(void) ranges::is_sorted_until(ints, rel, project_to_unique_ptr);
(void) ranges::is_sorted_until(ints.begin(), ints.end(), rel, project_to_unique_ptr);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1505,10 +1505,10 @@ STATIC_ASSERT(__cpp_lib_quoted_string_io == 201304L);
#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
#ifndef __cpp_lib_ranges
#error __cpp_lib_ranges is not defined
#elif __cpp_lib_ranges != 202211L
#error __cpp_lib_ranges is not 202211L
#elif __cpp_lib_ranges != 202302L
#error __cpp_lib_ranges is not 202302L
#else
STATIC_ASSERT(__cpp_lib_ranges == 202211L);
STATIC_ASSERT(__cpp_lib_ranges == 202302L);
#endif
#elif _HAS_CXX20 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
#ifndef __cpp_lib_ranges
Expand Down

0 comments on commit 2aa2ff9

Please sign in to comment.