Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

P2609R3: Relaxing Ranges Just A Smidge #3486

Merged
merged 7 commits into from
Feb 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>>,
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
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
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.
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
// 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 @@ -1507,10 +1507,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