зеркало из https://github.com/microsoft/STL.git
Implement views::empty and views::single range factories (#1201)
This commit is contained in:
Родитель
ea1aaf76cb
Коммит
7b0167c84a
|
@ -53,13 +53,6 @@ protected:
|
|||
_THROW(bad_optional_access{});
|
||||
}
|
||||
|
||||
struct _Nontrivial_dummy_type {
|
||||
constexpr _Nontrivial_dummy_type() noexcept {
|
||||
// This default constructor is user-provided to avoid zero-initialization when objects are value-initialized.
|
||||
}
|
||||
};
|
||||
_STL_INTERNAL_STATIC_ASSERT(!is_trivially_default_constructible_v<_Nontrivial_dummy_type>);
|
||||
|
||||
template <class _Ty, bool = is_trivially_destructible_v<_Ty>>
|
||||
struct _Optional_destruct_base { // either contains a value of _Ty or is empty (trivial destructor)
|
||||
union {
|
||||
|
|
402
stl/inc/ranges
402
stl/inc/ranges
|
@ -12,6 +12,9 @@
|
|||
#pragma message("The contents of <ranges> are available only with C++20 concepts support.")
|
||||
#else // ^^^ !defined(__cpp_lib_concepts) / defined(__cpp_lib_concepts) vvv
|
||||
#include <iterator>
|
||||
#if 1 // TRANSITION, VSO-1174090
|
||||
#include <optional>
|
||||
#endif // TRANSITION, VSO-1174090
|
||||
|
||||
#pragma pack(push, _CRT_PACKING)
|
||||
#pragma warning(push, _STL_WARNING_LEVEL)
|
||||
|
@ -22,7 +25,7 @@ _STL_DISABLE_CLANG_WARNINGS
|
|||
|
||||
_STD_BEGIN
|
||||
namespace ranges {
|
||||
// Much machinery defined in <xutility>
|
||||
// MUCH machinery defined in <xutility>
|
||||
|
||||
// clang-format off
|
||||
// CONCEPT ranges::viewable_range
|
||||
|
@ -30,6 +33,401 @@ namespace ranges {
|
|||
concept viewable_range = range<_Rng>
|
||||
&& (borrowed_range<_Rng> || view<remove_cvref_t<_Rng>>);
|
||||
|
||||
template <class _Ty>
|
||||
concept _Copy_constructible_object = copy_constructible<_Ty> && is_object_v<_Ty>;
|
||||
// clang-format on
|
||||
|
||||
// CLASS TEMPLATE ranges::_Semiregular_box
|
||||
#if 0 // TRANSITION, VSO-1174090
|
||||
template <_Copy_constructible_object _Ty>
|
||||
class _Semiregular_box {
|
||||
public:
|
||||
constexpr _Semiregular_box() noexcept : _Dummy{}, _Engaged{false} {}
|
||||
constexpr _Semiregular_box() noexcept(
|
||||
is_nothrow_default_constructible_v<_Ty>) requires default_initializable<_Ty>
|
||||
: _Val(), _Engaged{true} {}
|
||||
|
||||
template <class... _Types>
|
||||
constexpr _Semiregular_box(in_place_t, _Types&&... _Args) noexcept(
|
||||
is_nothrow_constructible_v<_Ty, _Types...>) // strengthened
|
||||
: _Val(_STD forward<_Types>(_Args)...), _Engaged{true} {}
|
||||
|
||||
~_Semiregular_box() requires is_trivially_destructible_v<_Ty> = default;
|
||||
|
||||
~_Semiregular_box() {
|
||||
if (_Engaged) {
|
||||
_Val.~_Ty();
|
||||
}
|
||||
}
|
||||
|
||||
_Semiregular_box(const _Semiregular_box&) requires is_trivially_copy_constructible_v<_Ty> = default;
|
||||
_Semiregular_box(const _Semiregular_box& _That) : _Engaged{_That._Engaged} {
|
||||
if (_That._Engaged) {
|
||||
_Construct_in_place(_Val, _That._Val);
|
||||
}
|
||||
}
|
||||
|
||||
_Semiregular_box(_Semiregular_box&&) requires is_trivially_move_constructible_v<_Ty> = default;
|
||||
_Semiregular_box(_Semiregular_box&& _That) : _Engaged{_That._Engaged} {
|
||||
if (_That._Engaged) {
|
||||
_Construct_in_place(_Val, _STD move(_That._Val));
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
_Semiregular_box& operator=(const _Semiregular_box&) noexcept
|
||||
requires copyable<_Ty> && is_trivially_copy_assignable_v<_Ty> = default;
|
||||
// clang-format on
|
||||
|
||||
_Semiregular_box& operator=(const _Semiregular_box& _That) noexcept(is_nothrow_copy_constructible_v<_Ty>&&
|
||||
is_nothrow_copy_assignable_v<_Ty>) /* strengthened */ requires copyable<_Ty> {
|
||||
if (_Engaged) {
|
||||
if (_That._Engaged) {
|
||||
_Val = _That._Val;
|
||||
} else {
|
||||
_Val.~_Ty();
|
||||
_Engaged = false;
|
||||
}
|
||||
} else {
|
||||
if (_That._Engaged) {
|
||||
_Construct_in_place(_Val, _That._Val);
|
||||
_Engaged = true;
|
||||
} else {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
_Semiregular_box& operator=(const _Semiregular_box& _That) noexcept(is_nothrow_copy_constructible_v<_Ty>) {
|
||||
if (_STD addressof(_That) != this) {
|
||||
if (_Engaged) {
|
||||
_Val.~_Ty();
|
||||
_Engaged = false;
|
||||
}
|
||||
|
||||
if (_That._Engaged) {
|
||||
_Construct_in_place(_Val, _That._Val);
|
||||
_Engaged = true;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
_Semiregular_box& operator=(_Semiregular_box&&) noexcept
|
||||
requires movable<_Ty> && is_trivially_move_assignable_v<_Ty> = default;
|
||||
// clang-format on
|
||||
|
||||
_Semiregular_box& operator=(_Semiregular_box&& _That) noexcept(is_nothrow_move_constructible_v<_Ty>&&
|
||||
is_nothrow_move_assignable_v<_Ty>) /* strengthened */ requires movable<_Ty> {
|
||||
if (_Engaged) {
|
||||
if (_That._Engaged) {
|
||||
_Val = _STD move(_That._Val);
|
||||
} else {
|
||||
_Val.~_Ty();
|
||||
_Engaged = false;
|
||||
}
|
||||
} else {
|
||||
if (_That._Engaged) {
|
||||
_Construct_in_place(_Val, _STD move(_That._Val));
|
||||
_Engaged = true;
|
||||
} else {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
_Semiregular_box& operator=(_Semiregular_box&& _That) noexcept(is_nothrow_move_constructible_v<_Ty>) {
|
||||
if (_Engaged) {
|
||||
_Val.~_Ty();
|
||||
_Engaged = false;
|
||||
}
|
||||
|
||||
if (_That._Engaged) {
|
||||
_Construct_in_place(_Val, _STD move(_That._Val));
|
||||
_Engaged = true;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const noexcept {
|
||||
return _Engaged;
|
||||
}
|
||||
|
||||
_NODISCARD constexpr _Ty& operator*() noexcept {
|
||||
_STL_INTERNAL_CHECK(_Engaged);
|
||||
return _Val;
|
||||
}
|
||||
_NODISCARD constexpr const _Ty& operator*() const noexcept {
|
||||
_STL_INTERNAL_CHECK(_Engaged);
|
||||
return _Val;
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
_Nontrivial_dummy_type _Dummy;
|
||||
_Ty _Val;
|
||||
};
|
||||
bool _Engaged;
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
template <_Copy_constructible_object _Ty>
|
||||
requires default_initializable<_Ty>
|
||||
&& (copyable<_Ty>
|
||||
|| (is_nothrow_copy_constructible_v<_Ty>
|
||||
&& (movable<_Ty> || is_nothrow_move_constructible_v<_Ty>)))
|
||||
class _Semiregular_box<_Ty> {
|
||||
// clang-format on
|
||||
public:
|
||||
_Semiregular_box() = default;
|
||||
|
||||
template <class... _Types>
|
||||
constexpr _Semiregular_box(in_place_t, _Types&&... _Args) noexcept(
|
||||
is_nothrow_constructible_v<_Ty, _Types...>) // strengthened
|
||||
: _Val(_STD forward<_Types>(_Args)...) {}
|
||||
|
||||
_Semiregular_box(const _Semiregular_box&) = default;
|
||||
_Semiregular_box(_Semiregular_box&&) = default;
|
||||
_Semiregular_box& operator=(const _Semiregular_box&) requires copyable<_Ty> = default;
|
||||
_Semiregular_box& operator=(_Semiregular_box&&) requires movable<_Ty> = default;
|
||||
|
||||
_Semiregular_box& operator=(const _Semiregular_box& _That) noexcept {
|
||||
if (_STD addressof(_That) != this) {
|
||||
_Val.~_Ty();
|
||||
_Construct_in_place(_Val, _That._Val);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
_Semiregular_box& operator=(_Semiregular_box&& _That) noexcept {
|
||||
if (_STD addressof(_That) != this) {
|
||||
_Val.~_Ty();
|
||||
_Construct_in_place(_Val, _STD move(_That._Val));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
_NODISCARD constexpr _Ty& operator*() noexcept {
|
||||
return _Val;
|
||||
}
|
||||
_NODISCARD constexpr const _Ty& operator*() const noexcept {
|
||||
return _Val;
|
||||
}
|
||||
|
||||
private:
|
||||
/* [[no_unique_address]] */ _Ty _Val = _Ty();
|
||||
};
|
||||
#else // ^^^ no workaround / workaround vvv
|
||||
template <class _Ty>
|
||||
class _Semiregular_box_copy : public optional<_Ty> {
|
||||
public:
|
||||
using optional<_Ty>::optional;
|
||||
|
||||
_Semiregular_box_copy() = default;
|
||||
_Semiregular_box_copy(const _Semiregular_box_copy&) = default;
|
||||
_Semiregular_box_copy(_Semiregular_box_copy&&) = default;
|
||||
_Semiregular_box_copy& operator=(_Semiregular_box_copy&&) = default;
|
||||
|
||||
_Semiregular_box_copy& operator=(const _Semiregular_box_copy& _That) noexcept(
|
||||
is_nothrow_copy_constructible_v<_Ty>) {
|
||||
if (_STD addressof(_That) != this) {
|
||||
optional<_Ty>::reset();
|
||||
if (_That) {
|
||||
optional<_Ty>::emplace(*_That);
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <class _Ty>
|
||||
using _Choose_semiregular_box_copy =
|
||||
conditional_t<assignable_from<_Ty&, const _Ty&>, optional<_Ty>, _Semiregular_box_copy<_Ty>>;
|
||||
|
||||
template <class _Ty>
|
||||
class _Semiregular_box_move : public _Choose_semiregular_box_copy<_Ty> {
|
||||
public:
|
||||
using _Choose_semiregular_box_copy<_Ty>::_Choose_semiregular_box_copy;
|
||||
|
||||
_Semiregular_box_move() = default;
|
||||
_Semiregular_box_move(const _Semiregular_box_move&) = default;
|
||||
_Semiregular_box_move(_Semiregular_box_move&&) = default;
|
||||
_Semiregular_box_move& operator=(const _Semiregular_box_move&) = default;
|
||||
|
||||
_Semiregular_box_move& operator=(_Semiregular_box_move&& _That) noexcept(is_nothrow_move_constructible_v<_Ty>) {
|
||||
if (_STD addressof(_That) != this) {
|
||||
optional<_Ty>::reset();
|
||||
if (_That) {
|
||||
optional<_Ty>::emplace(_STD move(*_That));
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <class _Ty>
|
||||
using _Choose_semiregular_box_move =
|
||||
conditional_t<assignable_from<_Ty&, _Ty>, _Choose_semiregular_box_copy<_Ty>, _Semiregular_box_move<_Ty>>;
|
||||
|
||||
template <_Copy_constructible_object _Ty>
|
||||
class _Semiregular_box : public _Choose_semiregular_box_move<_Ty> {
|
||||
public:
|
||||
constexpr _Semiregular_box() noexcept {}
|
||||
constexpr _Semiregular_box() noexcept(
|
||||
is_nothrow_default_constructible_v<_Ty>) requires default_initializable<_Ty>
|
||||
: _Choose_semiregular_box_move<_Ty>{in_place} {}
|
||||
|
||||
template <class... _Types>
|
||||
constexpr _Semiregular_box(in_place_t, _Types&&... _Args) noexcept(
|
||||
is_nothrow_constructible_v<_Ty, _Types...>) // strengthened
|
||||
: _Choose_semiregular_box_move<_Ty>{in_place, _STD forward<_Types>(_Args)...} {}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
template <_Copy_constructible_object _Ty>
|
||||
requires default_initializable<_Ty> && copyable<_Ty>
|
||||
class _Semiregular_box<_Ty> {
|
||||
// clang-format on
|
||||
public:
|
||||
_Semiregular_box() = default;
|
||||
|
||||
template <class... _Types>
|
||||
constexpr _Semiregular_box(in_place_t, _Types&&... _Args) noexcept(
|
||||
is_nothrow_constructible_v<_Ty, _Types...>) // strengthened
|
||||
: _Val(_STD forward<_Types>(_Args)...) {}
|
||||
|
||||
constexpr explicit operator bool() const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
_NODISCARD constexpr _Ty& operator*() noexcept {
|
||||
return _Val;
|
||||
}
|
||||
_NODISCARD constexpr const _Ty& operator*() const noexcept {
|
||||
return _Val;
|
||||
}
|
||||
|
||||
private:
|
||||
/* [[no_unique_address]] */ _Ty _Val = _Ty();
|
||||
};
|
||||
#endif // TRANSITION, VSO-1174090
|
||||
|
||||
// CLASS TEMPLATE ranges::empty_view
|
||||
// clang-format off
|
||||
template <class _Ty>
|
||||
requires is_object_v<_Ty>
|
||||
class empty_view : public view_interface<empty_view<_Ty>> {
|
||||
// clang-format on
|
||||
public:
|
||||
_NODISCARD static constexpr _Ty* begin() noexcept {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_NODISCARD static constexpr _Ty* end() noexcept {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_NODISCARD static constexpr _Ty* data() noexcept {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_NODISCARD static constexpr size_t size() noexcept {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_NODISCARD static constexpr bool empty() noexcept {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
namespace views {
|
||||
// VARIABLE TEMPLATE views::empty
|
||||
template <class _Ty>
|
||||
inline constexpr empty_view<_Ty> empty;
|
||||
} // namespace views
|
||||
|
||||
// CLASS TEMPLATE ranges::single_view
|
||||
// clang-format off
|
||||
template <copy_constructible _Ty>
|
||||
requires is_object_v<_Ty>
|
||||
class single_view : public view_interface<single_view<_Ty>> {
|
||||
// clang-format on
|
||||
public:
|
||||
single_view() = default;
|
||||
constexpr explicit single_view(const _Ty& _Val_) noexcept(is_nothrow_copy_constructible_v<_Ty>) // strengthened
|
||||
: _Val{in_place, _Val_} {}
|
||||
constexpr explicit single_view(_Ty&& _Val_) noexcept(is_nothrow_move_constructible_v<_Ty>) // strengthened
|
||||
: _Val{in_place, _STD move(_Val_)} {}
|
||||
|
||||
// clang-format off
|
||||
template <class... _Types>
|
||||
requires constructible_from<_Ty, _Types...>
|
||||
constexpr explicit single_view(in_place_t, _Types&&... _Args) noexcept( // explicit per LWG-3428
|
||||
is_nothrow_constructible_v<_Ty, _Types...>) // strengthened
|
||||
// clang-format on
|
||||
: _Val{in_place, _STD forward<_Types>(_Args)...} {}
|
||||
|
||||
_NODISCARD constexpr _Ty* begin() noexcept {
|
||||
return data();
|
||||
}
|
||||
_NODISCARD constexpr const _Ty* begin() const noexcept {
|
||||
return data();
|
||||
}
|
||||
|
||||
_NODISCARD constexpr _Ty* end() noexcept {
|
||||
return data() + 1;
|
||||
}
|
||||
_NODISCARD constexpr const _Ty* end() const noexcept {
|
||||
return data() + 1;
|
||||
}
|
||||
|
||||
_NODISCARD static constexpr size_t size() noexcept {
|
||||
return 1;
|
||||
}
|
||||
|
||||
_NODISCARD constexpr _Ty* data() noexcept {
|
||||
return _STD addressof(*_Val);
|
||||
}
|
||||
_NODISCARD constexpr const _Ty* data() const noexcept {
|
||||
return _STD addressof(*_Val);
|
||||
}
|
||||
|
||||
private:
|
||||
/* [[no_unique_address]] */ _Semiregular_box<_Ty> _Val{};
|
||||
};
|
||||
|
||||
namespace views {
|
||||
// VARIABLE views::single
|
||||
struct _Single_fn {
|
||||
// clang-format off
|
||||
template <class _Ty>
|
||||
_NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(
|
||||
noexcept(single_view{static_cast<_Ty&&>(_Val)})) requires requires {
|
||||
single_view{static_cast<_Ty&&>(_Val)};
|
||||
} {
|
||||
return single_view{static_cast<_Ty&&>(_Val)};
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
inline constexpr _Single_fn single;
|
||||
} // namespace views
|
||||
|
||||
// CLASS TEMPLATE ranges::ref_view
|
||||
// clang-format off
|
||||
template <range _Rng>
|
||||
|
@ -90,6 +488,8 @@ namespace ranges {
|
|||
inline constexpr bool enable_borrowed_range<ref_view<_Rng>> = true;
|
||||
} // namespace ranges
|
||||
|
||||
namespace views = ranges::views;
|
||||
|
||||
_STD_END
|
||||
|
||||
#pragma pop_macro("new")
|
||||
|
|
|
@ -5963,6 +5963,15 @@ template <class _Ty, enable_if_t<is_floating_point_v<_Ty>, int> = 0>
|
|||
_NODISCARD _CONSTEXPR_BIT_CAST bool _Is_finite(const _Ty _Xx) { // constexpr isfinite()
|
||||
return _Float_abs_bits(_Xx) < _Float_traits<_Ty>::_Exponent_mask;
|
||||
}
|
||||
|
||||
// STRUCT _Nontrivial_dummy_type
|
||||
struct _Nontrivial_dummy_type {
|
||||
constexpr _Nontrivial_dummy_type() noexcept {
|
||||
// This default constructor is user-provided to avoid zero-initialization when objects are value-initialized.
|
||||
}
|
||||
};
|
||||
_STL_INTERNAL_STATIC_ASSERT(!is_trivially_default_constructible_v<_Nontrivial_dummy_type>);
|
||||
|
||||
_STD_END
|
||||
#undef _CONSTEXPR_BIT_CAST
|
||||
#pragma pop_macro("new")
|
||||
|
|
|
@ -317,6 +317,8 @@ tests\P0896R4_ranges_ref_view
|
|||
tests\P0896R4_ranges_subrange
|
||||
tests\P0896R4_ranges_test_machinery
|
||||
tests\P0896R4_ranges_to_address
|
||||
tests\P0896R4_views_empty
|
||||
tests\P0896R4_views_single
|
||||
tests\P0898R3_concepts
|
||||
tests\P0898R3_identity
|
||||
tests\P0912R5_coroutine
|
||||
|
|
|
@ -124,6 +124,8 @@ STATIC_ASSERT(test_cpo(ranges::empty));
|
|||
STATIC_ASSERT(test_cpo(ranges::data));
|
||||
STATIC_ASSERT(test_cpo(ranges::cdata));
|
||||
|
||||
STATIC_ASSERT(test_cpo(ranges::views::single));
|
||||
|
||||
void test_cpo_ambiguity() {
|
||||
using namespace std::ranges;
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <ranges>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct not_constructible {
|
||||
not_constructible() = delete;
|
||||
~not_constructible() = delete;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
constexpr bool test_one_type() {
|
||||
// validate type properties
|
||||
using R = ranges::empty_view<T>;
|
||||
static_assert(ranges::view<R> && ranges::contiguous_range<R> && ranges::sized_range<R> && ranges::common_range<R>);
|
||||
static_assert(same_as<const R, decltype(views::empty<T>)>);
|
||||
auto& r = views::empty<T>;
|
||||
|
||||
// validate member size
|
||||
static_assert(same_as<decltype(R::size()), size_t>);
|
||||
static_assert(R::size() == 0);
|
||||
static_assert(noexcept(R::size()));
|
||||
static_assert(noexcept(ranges::size(r)));
|
||||
|
||||
// validate members begin, data, and end
|
||||
static_assert(same_as<decltype(R::data()), T*>);
|
||||
static_assert(R::data() == nullptr);
|
||||
static_assert(noexcept(R::data()));
|
||||
static_assert(noexcept(ranges::data(r)));
|
||||
|
||||
static_assert(same_as<decltype(R::begin()), T*>);
|
||||
static_assert(R::begin() == nullptr);
|
||||
static_assert(noexcept(R::begin()));
|
||||
static_assert(noexcept(ranges::begin(r)));
|
||||
|
||||
static_assert(same_as<decltype(R::end()), T*>);
|
||||
static_assert(R::end() == nullptr);
|
||||
static_assert(noexcept(R::end()));
|
||||
static_assert(noexcept(ranges::end(r)));
|
||||
|
||||
// validate member empty
|
||||
static_assert(same_as<decltype(R::empty()), bool>);
|
||||
static_assert(R::empty() == true);
|
||||
static_assert(noexcept(R::empty()));
|
||||
static_assert(noexcept(ranges::empty(r)));
|
||||
|
||||
// validate members inherited from view_interface
|
||||
assert(!r);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
static_assert(test_one_type<int>());
|
||||
test_one_type<int>();
|
||||
static_assert(test_one_type<string>());
|
||||
test_one_type<string>();
|
||||
static_assert(test_one_type<not_constructible>());
|
||||
test_one_type<not_constructible>();
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,144 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <ranges>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
using namespace std;
|
||||
|
||||
template <class>
|
||||
constexpr bool always_false = false;
|
||||
|
||||
struct only_copy_constructible {
|
||||
int val;
|
||||
|
||||
constexpr explicit only_copy_constructible(int i) noexcept : val{i} {}
|
||||
only_copy_constructible(const only_copy_constructible&) = default;
|
||||
only_copy_constructible(only_copy_constructible&& that) : val{exchange(that.val, -1)} {}
|
||||
|
||||
bool operator==(const only_copy_constructible&) const = default;
|
||||
|
||||
template <class T = void>
|
||||
auto operator&() const {
|
||||
static_assert(always_false<T>);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
auto operator,(U&&) const {
|
||||
static_assert(always_false<U>);
|
||||
}
|
||||
};
|
||||
|
||||
struct literal_class {
|
||||
int value;
|
||||
|
||||
literal_class() = default;
|
||||
constexpr explicit literal_class(int i) noexcept : value{i} {}
|
||||
|
||||
bool operator==(const literal_class&) const = default;
|
||||
};
|
||||
|
||||
template <class T, class... Args>
|
||||
constexpr bool test_one_type(T value, Args&&... args) {
|
||||
// validate type properties
|
||||
using R = ranges::single_view<T>;
|
||||
static_assert(ranges::view<R> && ranges::contiguous_range<R> && ranges::sized_range<R> && ranges::common_range<R>);
|
||||
|
||||
// validate CTAD and const T& constructor
|
||||
same_as<R> auto r0 = ranges::single_view{value};
|
||||
const R& cr0 = r0;
|
||||
|
||||
// validate member size
|
||||
static_assert(same_as<decltype(R::size()), size_t>);
|
||||
static_assert(R::size() == 1);
|
||||
static_assert(noexcept(R::size()));
|
||||
static_assert(noexcept(ranges::size(r0)));
|
||||
static_assert(noexcept(ranges::size(cr0)));
|
||||
|
||||
// validate member data
|
||||
const same_as<T*> auto ptr = r0.data();
|
||||
assert(ptr != nullptr);
|
||||
assert(ptr != addressof(value));
|
||||
static_assert(noexcept(r0.data()));
|
||||
static_assert(noexcept(ranges::data(r0)));
|
||||
|
||||
const same_as<const T*> auto cptr = cr0.data();
|
||||
assert(cptr == ptr);
|
||||
static_assert(noexcept(cr0.data()));
|
||||
static_assert(noexcept(ranges::data(cr0)));
|
||||
|
||||
// validate members begin and end
|
||||
static_assert(same_as<decltype(r0.begin()), T*>);
|
||||
assert(*r0.begin() == value);
|
||||
assert(r0.begin() == ptr);
|
||||
static_assert(noexcept(r0.begin()));
|
||||
static_assert(noexcept(ranges::begin(r0)));
|
||||
|
||||
static_assert(same_as<decltype(r0.end()), T*>);
|
||||
assert(r0.end() == ptr + 1);
|
||||
static_assert(noexcept(r0.end()));
|
||||
static_assert(noexcept(ranges::end(r0)));
|
||||
|
||||
static_assert(same_as<decltype(cr0.begin()), const T*>);
|
||||
assert(*cr0.begin() == value);
|
||||
assert(cr0.begin() == cptr);
|
||||
static_assert(noexcept(cr0.begin()));
|
||||
static_assert(noexcept(ranges::begin(cr0)));
|
||||
|
||||
static_assert(same_as<decltype(cr0.end()), const T*>);
|
||||
assert(cr0.end() == cptr + 1);
|
||||
static_assert(noexcept(cr0.end()));
|
||||
static_assert(noexcept(ranges::end(cr0)));
|
||||
|
||||
// validate CTAD and T&& constructor
|
||||
const same_as<R> auto cr1 = ranges::single_view{move(value)};
|
||||
assert(cr1.data() != nullptr);
|
||||
assert(cr1.data() != addressof(value));
|
||||
assert(cr1.data() != cr0.data());
|
||||
assert(*cr1.data() == *cr0.data());
|
||||
|
||||
// validate in_place constructor
|
||||
const same_as<R> auto cr2 = ranges::single_view<T>{in_place, forward<Args>(args)...};
|
||||
assert(cr2.data() != nullptr);
|
||||
assert(*cr2.data() == *cr1.data());
|
||||
static_assert(
|
||||
noexcept(R{in_place, forward<Args>(args)...}) == is_nothrow_constructible_v<T, Args...>); // strengthened
|
||||
|
||||
// validate CPO [lvalue]
|
||||
auto value2 = *cr2.data();
|
||||
const same_as<R> auto cr3 = views::single(value2);
|
||||
assert(cr3.data() != nullptr);
|
||||
assert(cr3.data() != addressof(value2));
|
||||
assert(*cr3.data() == *cr2.data());
|
||||
static_assert(noexcept(views::single(value)) == is_nothrow_copy_constructible_v<T>); // strengthened
|
||||
|
||||
// validate CPO [rvalue]
|
||||
const same_as<R> auto cr4 = views::single(move(value2));
|
||||
assert(cr4.data() != nullptr);
|
||||
assert(cr4.data() != addressof(value2));
|
||||
assert(*cr4.data() == *cr3.data());
|
||||
static_assert(noexcept(views::single(move(value))) == is_nothrow_move_constructible_v<T>); // strengthened
|
||||
|
||||
// validate members inherited from view_interface
|
||||
assert(!cr0.empty());
|
||||
assert(cr0);
|
||||
assert(addressof(cr0.front()) == ptr);
|
||||
assert(addressof(cr0.back()) == ptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
static_assert(test_one_type(42, 42));
|
||||
test_one_type(42, 42);
|
||||
|
||||
static_assert(test_one_type(literal_class{42}, 42));
|
||||
test_one_type(literal_class{42}, 42);
|
||||
|
||||
test_one_type(only_copy_constructible{42}, 42);
|
||||
test_one_type(string{"Hello, World!"}, "Hello, World!");
|
||||
}
|
Загрузка…
Ссылка в новой задаче