зеркало из https://github.com/microsoft/STL.git
Implement P2494R2 Relaxing Range Adaptors To Allow Move-Only Types (#2965)
Co-authored-by: Nicole Mazzuca <mazzucan@outlook.com> Co-authored-by: A. Jiang <de34@live.cn> Co-authored-by: Stephan T. Lavavej <stl@nuwen.net> Co-authored-by: Casey Carter <Casey@Carter.net>
This commit is contained in:
Родитель
f241c79ac1
Коммит
04e304b147
102
stl/inc/ranges
102
stl/inc/ranges
|
@ -47,7 +47,13 @@ namespace ranges {
|
|||
&& same_as<sentinel_t<_Rng>, sentinel_t<const _Rng>>;
|
||||
|
||||
template <class _Ty>
|
||||
concept _Copy_constructible_object = copy_constructible<_Ty> && _Destructible_object<_Ty>;
|
||||
concept _Valid_movable_box_object =
|
||||
#if _HAS_CXX23
|
||||
move_constructible<_Ty>
|
||||
#else // ^^^ C++23 / C++20 vvv
|
||||
copy_constructible<_Ty>
|
||||
#endif // C++20
|
||||
&& _Destructible_object<_Ty>;
|
||||
|
||||
template <class _It>
|
||||
concept _Has_arrow = input_iterator<_It>
|
||||
|
@ -232,18 +238,21 @@ namespace ranges {
|
|||
template <bool _Enable, class _Rng, class _Derived>
|
||||
using _Cached_position_t = conditional_t<_Enable, _Cached_position<_Rng, _Derived>, view_interface<_Derived>>;
|
||||
|
||||
template <_Copy_constructible_object _Ty>
|
||||
class _Copyable_box { // a simplified optional that augments copy_constructible types with full copyability
|
||||
// A simplified optional that augments copy_constructible types with full copyability,
|
||||
// and move_constructible types with full movability.
|
||||
// In C++20, this corresponds to copyable-box.
|
||||
template <_Valid_movable_box_object _Ty>
|
||||
class _Movable_box {
|
||||
public:
|
||||
constexpr _Copyable_box() noexcept(is_nothrow_default_constructible_v<_Ty>) requires default_initializable<_Ty>
|
||||
constexpr _Movable_box() noexcept(is_nothrow_default_constructible_v<_Ty>) requires default_initializable<_Ty>
|
||||
: _Val(), _Engaged{true} {}
|
||||
|
||||
template <class... _Types>
|
||||
constexpr _Copyable_box(in_place_t, _Types&&... _Args) noexcept(
|
||||
constexpr _Movable_box(in_place_t, _Types&&... _Args) noexcept(
|
||||
is_nothrow_constructible_v<_Ty, _Types...>) // strengthened
|
||||
: _Val(_STD forward<_Types>(_Args)...), _Engaged{true} {}
|
||||
|
||||
constexpr ~_Copyable_box() {
|
||||
constexpr ~_Movable_box() {
|
||||
if (_Engaged) {
|
||||
_Val.~_Ty();
|
||||
}
|
||||
|
@ -251,33 +260,33 @@ namespace ranges {
|
|||
|
||||
// TRANSITION, LLVM-46269, destructor order is significant
|
||||
// clang-format off
|
||||
~_Copyable_box() requires is_trivially_destructible_v<_Ty> = default;
|
||||
~_Movable_box() requires is_trivially_destructible_v<_Ty> = default;
|
||||
|
||||
_Copyable_box(const _Copyable_box&) requires is_trivially_copy_constructible_v<_Ty> = default;
|
||||
_Movable_box(const _Movable_box&) requires is_trivially_copy_constructible_v<_Ty> = default;
|
||||
// clang-format on
|
||||
|
||||
constexpr _Copyable_box(const _Copyable_box& _That) : _Engaged{_That._Engaged} {
|
||||
constexpr _Movable_box(const _Movable_box& _That) : _Engaged{_That._Engaged} {
|
||||
if (_That._Engaged) {
|
||||
_Construct_in_place(_Val, _That._Val);
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
_Copyable_box(_Copyable_box&&) requires is_trivially_move_constructible_v<_Ty> = default;
|
||||
_Movable_box(_Movable_box&&) requires is_trivially_move_constructible_v<_Ty> = default;
|
||||
// clang-format on
|
||||
|
||||
constexpr _Copyable_box(_Copyable_box&& _That) : _Engaged{_That._Engaged} {
|
||||
constexpr _Movable_box(_Movable_box&& _That) : _Engaged{_That._Engaged} {
|
||||
if (_That._Engaged) {
|
||||
_Construct_in_place(_Val, _STD move(_That._Val));
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
_Copyable_box& operator=(const _Copyable_box&) noexcept
|
||||
_Movable_box& operator=(const _Movable_box&) noexcept
|
||||
requires copyable<_Ty> && is_trivially_copy_assignable_v<_Ty> = default;
|
||||
// clang-format on
|
||||
|
||||
constexpr _Copyable_box& operator=(const _Copyable_box& _That) noexcept(
|
||||
constexpr _Movable_box& operator=(const _Movable_box& _That) noexcept(
|
||||
is_nothrow_copy_constructible_v<_Ty>&& is_nothrow_copy_assignable_v<_Ty>) // strengthened
|
||||
requires copyable<_Ty> {
|
||||
if (_Engaged) {
|
||||
|
@ -299,7 +308,8 @@ namespace ranges {
|
|||
return *this;
|
||||
}
|
||||
|
||||
constexpr _Copyable_box& operator=(const _Copyable_box& _That) noexcept(is_nothrow_copy_constructible_v<_Ty>) {
|
||||
constexpr _Movable_box& operator=(const _Movable_box& _That) noexcept(
|
||||
is_nothrow_copy_constructible_v<_Ty>) requires copy_constructible<_Ty> {
|
||||
if (_STD addressof(_That) == this) {
|
||||
return *this;
|
||||
}
|
||||
|
@ -318,11 +328,11 @@ namespace ranges {
|
|||
}
|
||||
|
||||
// clang-format off
|
||||
_Copyable_box& operator=(_Copyable_box&&) noexcept
|
||||
_Movable_box& operator=(_Movable_box&&) noexcept
|
||||
requires movable<_Ty> && is_trivially_move_assignable_v<_Ty> = default;
|
||||
// clang-format on
|
||||
|
||||
constexpr _Copyable_box& operator=(_Copyable_box&& _That) noexcept(
|
||||
constexpr _Movable_box& operator=(_Movable_box&& _That) noexcept(
|
||||
is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>) // strengthened
|
||||
requires movable<_Ty> {
|
||||
if (_Engaged) {
|
||||
|
@ -344,7 +354,7 @@ namespace ranges {
|
|||
return *this;
|
||||
}
|
||||
|
||||
constexpr _Copyable_box& operator=(_Copyable_box&& _That) noexcept(is_nothrow_move_constructible_v<_Ty>) {
|
||||
constexpr _Movable_box& operator=(_Movable_box&& _That) noexcept(is_nothrow_move_constructible_v<_Ty>) {
|
||||
if (_STD addressof(_That) == this) {
|
||||
return *this;
|
||||
}
|
||||
|
@ -382,32 +392,39 @@ namespace ranges {
|
|||
bool _Engaged;
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
template <_Copy_constructible_object _Ty>
|
||||
requires (copyable<_Ty>
|
||||
|| (is_nothrow_copy_constructible_v<_Ty>
|
||||
&& (movable<_Ty> || is_nothrow_move_constructible_v<_Ty>)))
|
||||
class _Copyable_box<_Ty> { // provide the same API more efficiently when we can avoid the disengaged state
|
||||
// clang-format on
|
||||
// [range.move.wrap]
|
||||
template <class _Ty>
|
||||
concept _Use_simple_movable_box_wrapper =
|
||||
(copy_constructible<_Ty>
|
||||
// 1. If copy_constructible<T> is true, movable-box<T> should store only a T if either T models
|
||||
// copyable, or is_nothrow_move_constructible_v<T> && is_nothrow_copy_constructible_v<T> is true.
|
||||
? copyable<_Ty> || (is_nothrow_move_constructible_v<_Ty> && is_nothrow_copy_constructible_v<_Ty>)
|
||||
// 2. Otherwise, movable-box<T> should store only a T if either T models movable or
|
||||
// is_nothrow_move_constructible_v<T> is true.
|
||||
: movable<_Ty> || is_nothrow_move_constructible_v<_Ty>);
|
||||
|
||||
template <_Valid_movable_box_object _Ty>
|
||||
requires _Use_simple_movable_box_wrapper<_Ty>
|
||||
class _Movable_box<_Ty> { // provide the same API more efficiently when we can avoid the disengaged state
|
||||
public:
|
||||
// clang-format off
|
||||
_Copyable_box() requires default_initializable<_Ty> = default;
|
||||
_Movable_box() requires default_initializable<_Ty> = default;
|
||||
// clang-format on
|
||||
|
||||
template <class... _Types>
|
||||
constexpr _Copyable_box(in_place_t, _Types&&... _Args) noexcept(
|
||||
constexpr _Movable_box(in_place_t, _Types&&... _Args) noexcept(
|
||||
is_nothrow_constructible_v<_Ty, _Types...>) // strengthened
|
||||
: _Val(_STD forward<_Types>(_Args)...) {}
|
||||
|
||||
_Copyable_box(const _Copyable_box&) = default;
|
||||
_Copyable_box(_Copyable_box&&) = default;
|
||||
_Movable_box(const _Movable_box&) = default;
|
||||
_Movable_box(_Movable_box&&) = default;
|
||||
|
||||
// clang-format off
|
||||
_Copyable_box& operator=(const _Copyable_box&) requires copyable<_Ty> = default;
|
||||
_Copyable_box& operator=(_Copyable_box&&) requires movable<_Ty> = default;
|
||||
_Movable_box& operator=(const _Movable_box&) requires copyable<_Ty> = default;
|
||||
_Movable_box& operator=(_Movable_box&&) requires movable<_Ty> = default;
|
||||
// clang-format on
|
||||
|
||||
constexpr _Copyable_box& operator=(const _Copyable_box& _That) noexcept {
|
||||
constexpr _Movable_box& operator=(const _Movable_box& _That) noexcept requires copy_constructible<_Ty> {
|
||||
if (_STD addressof(_That) != this) {
|
||||
_Val.~_Ty();
|
||||
_Construct_in_place(_Val, _That._Val);
|
||||
|
@ -416,7 +433,7 @@ namespace ranges {
|
|||
return *this;
|
||||
}
|
||||
|
||||
constexpr _Copyable_box& operator=(_Copyable_box&& _That) noexcept {
|
||||
constexpr _Movable_box& operator=(_Movable_box&& _That) noexcept {
|
||||
if (_STD addressof(_That) != this) {
|
||||
_Val.~_Ty();
|
||||
_Construct_in_place(_Val, _STD move(_That._Val));
|
||||
|
@ -883,8 +900,7 @@ namespace ranges {
|
|||
inline constexpr empty_view<_Ty> empty;
|
||||
} // namespace views
|
||||
|
||||
template <copy_constructible _Ty>
|
||||
requires is_object_v<_Ty>
|
||||
template <_Valid_movable_box_object _Ty>
|
||||
class single_view : public view_interface<single_view<_Ty>> {
|
||||
public:
|
||||
// clang-format off
|
||||
|
@ -892,7 +908,7 @@ namespace ranges {
|
|||
// clang-format on
|
||||
|
||||
constexpr explicit single_view(const _Ty& _Val_) noexcept(is_nothrow_copy_constructible_v<_Ty>) // strengthened
|
||||
: _Val{in_place, _Val_} {}
|
||||
requires copy_constructible<_Ty> : _Val{in_place, _Val_} {}
|
||||
constexpr explicit single_view(_Ty&& _Val_) noexcept(is_nothrow_move_constructible_v<_Ty>) // strengthened
|
||||
: _Val{in_place, _STD move(_Val_)} {}
|
||||
|
||||
|
@ -928,7 +944,7 @@ namespace ranges {
|
|||
}
|
||||
|
||||
private:
|
||||
/* [[no_unique_address]] */ _Copyable_box<_Ty> _Val{};
|
||||
/* [[no_unique_address]] */ _Movable_box<_Ty> _Val{};
|
||||
};
|
||||
|
||||
template <class _Ty>
|
||||
|
@ -1729,7 +1745,7 @@ namespace ranges {
|
|||
class filter_view : public _Cached_position_t<forward_range<_Vw>, _Vw, filter_view<_Vw, _Pr>> {
|
||||
private:
|
||||
/* [[no_unique_address]] */ _Vw _Range{};
|
||||
/* [[no_unique_address]] */ _Copyable_box<_Pr> _Pred{};
|
||||
/* [[no_unique_address]] */ _Movable_box<_Pr> _Pred{};
|
||||
|
||||
template <class _View>
|
||||
struct _Category_base {};
|
||||
|
@ -1987,15 +2003,15 @@ namespace ranges {
|
|||
#define _NOEXCEPT_IDL0(...)
|
||||
#endif // _ITERATOR_DEBUG_LEVEL == 0
|
||||
|
||||
template <input_range _Vw, copy_constructible _Fn>
|
||||
requires view<_Vw> && is_object_v<_Fn>
|
||||
template <input_range _Vw, _Valid_movable_box_object _Fn>
|
||||
requires view<_Vw>
|
||||
&& regular_invocable<_Fn&, range_reference_t<_Vw>>
|
||||
&& _Can_reference<invoke_result_t<_Fn&, range_reference_t<_Vw>>>
|
||||
class transform_view : public view_interface<transform_view<_Vw, _Fn>> {
|
||||
// clang-format on
|
||||
private:
|
||||
/* [[no_unique_address]] */ _Vw _Range{};
|
||||
/* [[no_unique_address]] */ _Copyable_box<_Fn> _Fun{};
|
||||
/* [[no_unique_address]] */ _Movable_box<_Fn> _Fun{};
|
||||
|
||||
template <bool _Const>
|
||||
class _Sentinel;
|
||||
|
@ -2692,7 +2708,7 @@ namespace ranges {
|
|||
class take_while_view : public view_interface<take_while_view<_Vw, _Pr>> {
|
||||
private:
|
||||
/* [[no_unique_address]] */ _Vw _Range{};
|
||||
/* [[no_unique_address]] */ _Copyable_box<_Pr> _Pred{};
|
||||
/* [[no_unique_address]] */ _Movable_box<_Pr> _Pred{};
|
||||
|
||||
template <bool _Const, bool _Wrapped = true>
|
||||
class _Sentinel {
|
||||
|
@ -3064,7 +3080,7 @@ namespace ranges {
|
|||
class drop_while_view : public _Cached_position_t<forward_range<_Vw>, _Vw, drop_while_view<_Vw, _Pr>> {
|
||||
private:
|
||||
/* [[no_unique_address]] */ _Vw _Range{};
|
||||
/* [[no_unique_address]] */ _Copyable_box<_Pr> _Pred{};
|
||||
/* [[no_unique_address]] */ _Movable_box<_Pr> _Pred{};
|
||||
|
||||
public:
|
||||
// clang-format off
|
||||
|
@ -6289,7 +6305,7 @@ namespace ranges {
|
|||
class chunk_by_view : public _Cached_position<_Vw, chunk_by_view<_Vw, _Pr>> {
|
||||
private:
|
||||
/* [[no_unique_address]] */ _Vw _Range{};
|
||||
/* [[no_unique_address]] */ _Copyable_box<_Pr> _Pred{};
|
||||
/* [[no_unique_address]] */ _Movable_box<_Pr> _Pred{};
|
||||
|
||||
class _Iterator {
|
||||
private:
|
||||
|
|
|
@ -332,6 +332,7 @@
|
|||
// P2443R1 views::chunk_by
|
||||
// P2445R1 forward_like()
|
||||
// P2446R2 views::as_rvalue
|
||||
// P2494R2 Relaxing Range Adaptors To Allow Move-Only Types
|
||||
// P2499R0 string_view Range Constructor Should Be explicit
|
||||
// P2549R0 unexpected<E>::error()
|
||||
|
||||
|
@ -1570,9 +1571,9 @@ _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 202202L // P2387R3 Pipe Support For User-Defined Range Adaptors
|
||||
#define __cpp_lib_ranges 202207L // P2494R2 Relaxing Range Adaptors To Allow Move-Only Types
|
||||
#elif _HAS_CXX20 // ^^^ _HAS_CXX23 / _HAS_CXX20 vvv
|
||||
#define __cpp_lib_ranges 202110L // P2415R2 What Is A `view`?
|
||||
#define __cpp_lib_ranges 202110L // P2415R2 What Is A view?
|
||||
#endif // _HAS_CXX20
|
||||
#endif // defined(__cpp_lib_concepts)
|
||||
|
||||
|
|
|
@ -561,6 +561,7 @@ tests\P2443R1_views_chunk_by
|
|||
tests\P2443R1_views_chunk_by_death
|
||||
tests\P2445R1_forward_like
|
||||
tests\P2446R2_views_as_rvalue
|
||||
tests\P2494R2_move_only_range_adaptors
|
||||
tests\P2517R1_apply_conditional_noexcept
|
||||
tests\VSO_0000000_allocator_propagation
|
||||
tests\VSO_0000000_any_calling_conventions
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_latest_matrix.lst
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct BaseTransform {
|
||||
explicit BaseTransform(int v) : val(v) {}
|
||||
int operator()(int x) const {
|
||||
return val * x;
|
||||
}
|
||||
int val;
|
||||
};
|
||||
|
||||
enum SmfKind {
|
||||
Nothrow,
|
||||
Throwing,
|
||||
Deleted,
|
||||
};
|
||||
|
||||
template <SmfKind CCtor, SmfKind MCtor, SmfKind CAssign, SmfKind MAssign>
|
||||
struct Transform : BaseTransform {
|
||||
using BaseTransform::BaseTransform;
|
||||
|
||||
Transform(const Transform&) noexcept(CCtor == Nothrow) //
|
||||
requires(CCtor != Deleted) = default;
|
||||
Transform(const Transform&) requires(CCtor == Deleted) = delete;
|
||||
|
||||
Transform(Transform&&) noexcept(MCtor == Nothrow) //
|
||||
requires(MCtor != Deleted) = default;
|
||||
Transform(Transform&&) requires(MCtor == Deleted) = delete;
|
||||
|
||||
Transform& operator=(const Transform&) noexcept(CAssign == Nothrow) //
|
||||
requires(CAssign != Deleted) = default;
|
||||
Transform& operator=(const Transform&) requires(CAssign == Deleted) = delete;
|
||||
|
||||
Transform& operator=(Transform&&) noexcept(MAssign == Nothrow) //
|
||||
requires(MAssign != Deleted) = default;
|
||||
Transform& operator=(Transform&&) requires(MAssign == Deleted) = delete;
|
||||
};
|
||||
|
||||
template <SmfKind CCtor, SmfKind MCtor, SmfKind CAssign, SmfKind MAssign>
|
||||
void test_transform() {
|
||||
using T = Transform<CCtor, MCtor, CAssign, MAssign>;
|
||||
T t{11};
|
||||
|
||||
vector<int> v;
|
||||
ranges::copy(array{0, 1, 2, 3, 4, 5} | views::transform(move(t)), back_inserter(v));
|
||||
assert(ranges::equal(v, array{0, 11, 22, 33, 44, 55}));
|
||||
|
||||
if constexpr (is_copy_constructible_v<T>
|
||||
? copyable<T> || (is_nothrow_copy_constructible_v<T> && is_nothrow_move_constructible_v<T>)
|
||||
: movable<T> || is_nothrow_move_constructible_v<T>) {
|
||||
static_assert(sizeof(ranges::_Movable_box<T>) == sizeof(T));
|
||||
} else {
|
||||
static_assert(sizeof(ranges::_Movable_box<T>) > sizeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_transform<Nothrow, Nothrow, Nothrow, Nothrow>();
|
||||
test_transform<Throwing, Throwing, Throwing, Throwing>();
|
||||
|
||||
test_transform<Nothrow, Nothrow, Deleted, Deleted>();
|
||||
test_transform<Nothrow, Throwing, Deleted, Deleted>();
|
||||
test_transform<Throwing, Nothrow, Deleted, Deleted>();
|
||||
test_transform<Throwing, Throwing, Deleted, Deleted>();
|
||||
|
||||
test_transform<Deleted, Nothrow, Deleted, Nothrow>();
|
||||
test_transform<Deleted, Nothrow, Deleted, Throwing>();
|
||||
test_transform<Deleted, Nothrow, Deleted, Deleted>();
|
||||
|
||||
test_transform<Deleted, Throwing, Deleted, Nothrow>();
|
||||
test_transform<Deleted, Throwing, Deleted, Throwing>();
|
||||
test_transform<Deleted, Throwing, Deleted, Deleted>();
|
||||
}
|
|
@ -1457,10 +1457,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 != 202202L
|
||||
#error __cpp_lib_ranges is not 202202L
|
||||
#elif __cpp_lib_ranges != 202207L
|
||||
#error __cpp_lib_ranges is not 202207L
|
||||
#else
|
||||
STATIC_ASSERT(__cpp_lib_ranges == 202202L);
|
||||
STATIC_ASSERT(__cpp_lib_ranges == 202207L);
|
||||
#endif
|
||||
#elif _HAS_CXX20 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
|
||||
#ifndef __cpp_lib_ranges
|
||||
|
|
Загрузка…
Ссылка в новой задаче