diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -78,7 +78,7 @@ "`P2465R3 `__","LWG","Standard Library Modules ``std`` and ``std.compat``","July 2022","","" "`P2467R1 `__","LWG","Support exclusive mode for ``fstreams``","July 2022","","" "`P2474R2 `__","LWG","``views::repeat``","July 2022","","","|ranges|" -"`P2494R2 `__","LWG","Relaxing range adaptors to allow for move only types","July 2022","","","|ranges|" +"`P2494R2 `__","LWG","Relaxing range adaptors to allow for move only types","July 2022","|Complete|","17.0","|ranges|" "`P2499R0 `__","LWG","``string_view`` range constructor should be ``explicit``","July 2022","|Complete|","16.0","|ranges|" "`P2502R2 `__","LWG","``std::generator``: Synchronous Coroutine Generator for Ranges","July 2022","","","|ranges|" "`P2508R1 `__","LWG","Exposing ``std::basic-format-string``","July 2022","|Complete|","15.0" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -597,7 +597,6 @@ __ranges/common_view.h __ranges/concepts.h __ranges/container_compatible_range.h - __ranges/copyable_box.h __ranges/counted.h __ranges/dangling.h __ranges/data.h @@ -614,6 +613,7 @@ __ranges/istream_view.h __ranges/join_view.h __ranges/lazy_split_view.h + __ranges/movable_box.h __ranges/non_propagating_cache.h __ranges/owning_view.h __ranges/range_adaptor.h diff --git a/libcxx/include/__ranges/copyable_box.h b/libcxx/include/__ranges/copyable_box.h deleted file mode 100644 --- a/libcxx/include/__ranges/copyable_box.h +++ /dev/null @@ -1,182 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef _LIBCPP___RANGES_COPYABLE_BOX_H -#define _LIBCPP___RANGES_COPYABLE_BOX_H - -#include <__concepts/constructible.h> -#include <__concepts/copyable.h> -#include <__concepts/movable.h> -#include <__config> -#include <__memory/addressof.h> -#include <__memory/construct_at.h> -#include <__type_traits/is_nothrow_constructible.h> -#include <__type_traits/is_nothrow_copy_constructible.h> -#include <__type_traits/is_nothrow_default_constructible.h> -#include <__utility/move.h> -#include - -#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -#endif - -_LIBCPP_BEGIN_NAMESPACE_STD - -#if _LIBCPP_STD_VER >= 20 - -// __copyable_box allows turning a type that is copy-constructible (but maybe not copy-assignable) into -// a type that is both copy-constructible and copy-assignable. It does that by introducing an empty state -// and basically doing destroy-then-copy-construct in the assignment operator. The empty state is necessary -// to handle the case where the copy construction fails after destroying the object. -// -// In some cases, we can completely avoid the use of an empty state; we provide a specialization of -// __copyable_box that does this, see below for the details. - -template -concept __copy_constructible_object = copy_constructible<_Tp> && is_object_v<_Tp>; - -namespace ranges { - // Primary template - uses std::optional and introduces an empty state in case assignment fails. - template<__copy_constructible_object _Tp> - class __copyable_box { - _LIBCPP_NO_UNIQUE_ADDRESS optional<_Tp> __val_; - - public: - template - requires is_constructible_v<_Tp, _Args...> - _LIBCPP_HIDE_FROM_ABI - constexpr explicit __copyable_box(in_place_t, _Args&& ...__args) - noexcept(is_nothrow_constructible_v<_Tp, _Args...>) - : __val_(in_place, std::forward<_Args>(__args)...) - { } - - _LIBCPP_HIDE_FROM_ABI - constexpr __copyable_box() noexcept(is_nothrow_default_constructible_v<_Tp>) - requires default_initializable<_Tp> - : __val_(in_place) - { } - - _LIBCPP_HIDE_FROM_ABI __copyable_box(__copyable_box const&) = default; - _LIBCPP_HIDE_FROM_ABI __copyable_box(__copyable_box&&) = default; - - _LIBCPP_HIDE_FROM_ABI - constexpr __copyable_box& operator=(__copyable_box const& __other) - noexcept(is_nothrow_copy_constructible_v<_Tp>) - { - if (this != std::addressof(__other)) { - if (__other.__has_value()) __val_.emplace(*__other); - else __val_.reset(); - } - return *this; - } - - _LIBCPP_HIDE_FROM_ABI - __copyable_box& operator=(__copyable_box&&) requires movable<_Tp> = default; - - _LIBCPP_HIDE_FROM_ABI - constexpr __copyable_box& operator=(__copyable_box&& __other) - noexcept(is_nothrow_move_constructible_v<_Tp>) - { - if (this != std::addressof(__other)) { - if (__other.__has_value()) __val_.emplace(std::move(*__other)); - else __val_.reset(); - } - return *this; - } - - _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& operator*() const noexcept { return *__val_; } - _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() noexcept { return *__val_; } - - _LIBCPP_HIDE_FROM_ABI constexpr const _Tp *operator->() const noexcept { return __val_.operator->(); } - _LIBCPP_HIDE_FROM_ABI constexpr _Tp *operator->() noexcept { return __val_.operator->(); } - - _LIBCPP_HIDE_FROM_ABI constexpr bool __has_value() const noexcept { return __val_.has_value(); } - }; - - // This partial specialization implements an optimization for when we know we don't need to store - // an empty state to represent failure to perform an assignment. For copy-assignment, this happens: - // - // 1. If the type is copyable (which includes copy-assignment), we can use the type's own assignment operator - // directly and avoid using std::optional. - // 2. If the type is not copyable, but it is nothrow-copy-constructible, then we can implement assignment as - // destroy-and-then-construct and we know it will never fail, so we don't need an empty state. - // - // The exact same reasoning can be applied for move-assignment, with copyable replaced by movable and - // nothrow-copy-constructible replaced by nothrow-move-constructible. This specialization is enabled - // whenever we can apply any of these optimizations for both the copy assignment and the move assignment - // operator. - template - concept __doesnt_need_empty_state_for_copy = copyable<_Tp> || is_nothrow_copy_constructible_v<_Tp>; - - template - concept __doesnt_need_empty_state_for_move = movable<_Tp> || is_nothrow_move_constructible_v<_Tp>; - - template<__copy_constructible_object _Tp> - requires __doesnt_need_empty_state_for_copy<_Tp> && __doesnt_need_empty_state_for_move<_Tp> - class __copyable_box<_Tp> { - _LIBCPP_NO_UNIQUE_ADDRESS _Tp __val_; - - public: - template - requires is_constructible_v<_Tp, _Args...> - _LIBCPP_HIDE_FROM_ABI - constexpr explicit __copyable_box(in_place_t, _Args&& ...__args) - noexcept(is_nothrow_constructible_v<_Tp, _Args...>) - : __val_(std::forward<_Args>(__args)...) - { } - - _LIBCPP_HIDE_FROM_ABI - constexpr __copyable_box() noexcept(is_nothrow_default_constructible_v<_Tp>) - requires default_initializable<_Tp> - : __val_() - { } - - _LIBCPP_HIDE_FROM_ABI __copyable_box(__copyable_box const&) = default; - _LIBCPP_HIDE_FROM_ABI __copyable_box(__copyable_box&&) = default; - - // Implementation of assignment operators in case we perform optimization (1) - _LIBCPP_HIDE_FROM_ABI __copyable_box& operator=(__copyable_box const&) requires copyable<_Tp> = default; - _LIBCPP_HIDE_FROM_ABI __copyable_box& operator=(__copyable_box&&) requires movable<_Tp> = default; - - // Implementation of assignment operators in case we perform optimization (2) - _LIBCPP_HIDE_FROM_ABI - constexpr __copyable_box& operator=(__copyable_box const& __other) noexcept { - static_assert(is_nothrow_copy_constructible_v<_Tp>); - if (this != std::addressof(__other)) { - std::destroy_at(std::addressof(__val_)); - std::construct_at(std::addressof(__val_), __other.__val_); - } - return *this; - } - - _LIBCPP_HIDE_FROM_ABI - constexpr __copyable_box& operator=(__copyable_box&& __other) noexcept { - static_assert(is_nothrow_move_constructible_v<_Tp>); - if (this != std::addressof(__other)) { - std::destroy_at(std::addressof(__val_)); - std::construct_at(std::addressof(__val_), std::move(__other.__val_)); - } - return *this; - } - - _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& operator*() const noexcept { return __val_; } - _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() noexcept { return __val_; } - - _LIBCPP_HIDE_FROM_ABI constexpr const _Tp *operator->() const noexcept { return std::addressof(__val_); } - _LIBCPP_HIDE_FROM_ABI constexpr _Tp *operator->() noexcept { return std::addressof(__val_); } - - _LIBCPP_HIDE_FROM_ABI constexpr bool __has_value() const noexcept { return true; } - }; -} // namespace ranges - -#endif // _LIBCPP_STD_VER >= 20 - -_LIBCPP_END_NAMESPACE_STD - -#endif // _LIBCPP___RANGES_COPYABLE_BOX_H diff --git a/libcxx/include/__ranges/drop_while_view.h b/libcxx/include/__ranges/drop_while_view.h --- a/libcxx/include/__ranges/drop_while_view.h +++ b/libcxx/include/__ranges/drop_while_view.h @@ -20,8 +20,8 @@ #include <__ranges/access.h> #include <__ranges/all.h> #include <__ranges/concepts.h> -#include <__ranges/copyable_box.h> #include <__ranges/enable_borrowed_range.h> +#include <__ranges/movable_box.h> #include <__ranges/non_propagating_cache.h> #include <__ranges/range_adaptor.h> #include <__ranges/view_interface.h> @@ -82,7 +82,7 @@ private: _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View(); - _LIBCPP_NO_UNIQUE_ADDRESS __copyable_box<_Pred> __pred_; + _LIBCPP_NO_UNIQUE_ADDRESS __movable_box<_Pred> __pred_; static constexpr bool _UseCache = forward_range<_View>; using _Cache = _If<_UseCache, __non_propagating_cache>, __empty_cache>; diff --git a/libcxx/include/__ranges/filter_view.h b/libcxx/include/__ranges/filter_view.h --- a/libcxx/include/__ranges/filter_view.h +++ b/libcxx/include/__ranges/filter_view.h @@ -28,7 +28,7 @@ #include <__ranges/access.h> #include <__ranges/all.h> #include <__ranges/concepts.h> -#include <__ranges/copyable_box.h> +#include <__ranges/movable_box.h> #include <__ranges/non_propagating_cache.h> #include <__ranges/range_adaptor.h> #include <__ranges/view_interface.h> @@ -53,7 +53,7 @@ requires view<_View> && is_object_v<_Pred> class filter_view : public view_interface> { _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View(); - _LIBCPP_NO_UNIQUE_ADDRESS __copyable_box<_Pred> __pred_; + _LIBCPP_NO_UNIQUE_ADDRESS __movable_box<_Pred> __pred_; // We cache the result of begin() to allow providing an amortized O(1) begin() whenever // the underlying range is at least a forward_range. diff --git a/libcxx/include/__ranges/iota_view.h b/libcxx/include/__ranges/iota_view.h --- a/libcxx/include/__ranges/iota_view.h +++ b/libcxx/include/__ranges/iota_view.h @@ -27,7 +27,6 @@ #include <__iterator/incrementable_traits.h> #include <__iterator/iterator_traits.h> #include <__iterator/unreachable_sentinel.h> -#include <__ranges/copyable_box.h> #include <__ranges/enable_borrowed_range.h> #include <__ranges/view_interface.h> #include <__type_traits/conditional.h> diff --git a/libcxx/include/__ranges/movable_box.h b/libcxx/include/__ranges/movable_box.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/movable_box.h @@ -0,0 +1,191 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___RANGES_MOVABLE_BOX_H +#define _LIBCPP___RANGES_MOVABLE_BOX_H + +#include <__concepts/constructible.h> +#include <__concepts/copyable.h> +#include <__concepts/movable.h> +#include <__config> +#include <__memory/addressof.h> +#include <__memory/construct_at.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_nothrow_copy_constructible.h> +#include <__type_traits/is_nothrow_default_constructible.h> +#include <__utility/move.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// __movable_box allows turning a type that is copy-constructible (but maybe not copy-assignable) into +// a type that is both copy-constructible and copy-assignable. It does that by introducing an empty state +// and basically doing destroy-then-copy-construct in the assignment operator. The empty state is necessary +// to handle the case where the copy construction fails after destroying the object. +// +// In some cases, we can completely avoid the use of an empty state; we provide a specialization of +// __movable_box that does this, see below for the details. + +// clang-format off +template +concept __movable_box_object = +#if _LIBCPP_STD_VER >= 23 + move_constructible<_Tp> +#else + copy_constructible<_Tp> +#endif + && is_object_v<_Tp>; +// clang-format on + +namespace ranges { +// Primary template - uses std::optional and introduces an empty state in case assignment fails. +template <__movable_box_object _Tp> +class __movable_box { + _LIBCPP_NO_UNIQUE_ADDRESS optional<_Tp> __val_; + +public: + template + requires is_constructible_v<_Tp, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr explicit __movable_box(in_place_t, _Args&&... __args) noexcept( + is_nothrow_constructible_v<_Tp, _Args...>) + : __val_(in_place, std::forward<_Args>(__args)...) {} + + _LIBCPP_HIDE_FROM_ABI constexpr __movable_box() noexcept(is_nothrow_default_constructible_v<_Tp>) + requires default_initializable<_Tp> + : __val_(in_place) {} + + _LIBCPP_HIDE_FROM_ABI __movable_box(__movable_box const&) = default; + _LIBCPP_HIDE_FROM_ABI __movable_box(__movable_box&&) = default; + + _LIBCPP_HIDE_FROM_ABI constexpr __movable_box& + operator=(__movable_box const& __other) noexcept(is_nothrow_copy_constructible_v<_Tp>) + requires copy_constructible<_Tp> + { + if (this != std::addressof(__other)) { + if (__other.__has_value()) + __val_.emplace(*__other); + else + __val_.reset(); + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI __movable_box& operator=(__movable_box&&) + requires movable<_Tp> + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr __movable_box& + operator=(__movable_box&& __other) noexcept(is_nothrow_move_constructible_v<_Tp>) { + if (this != std::addressof(__other)) { + if (__other.__has_value()) + __val_.emplace(std::move(*__other)); + else + __val_.reset(); + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& operator*() const noexcept { return *__val_; } + _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() noexcept { return *__val_; } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp* operator->() const noexcept { return __val_.operator->(); } + _LIBCPP_HIDE_FROM_ABI constexpr _Tp* operator->() noexcept { return __val_.operator->(); } + + _LIBCPP_HIDE_FROM_ABI constexpr bool __has_value() const noexcept { return __val_.has_value(); } +}; + +// This partial specialization implements an optimization for when we know we don't need to store +// an empty state to represent failure to perform an assignment. For copy-assignment, this happens: +// +// 1. If the type is copyable (which includes copy-assignment), we can use the type's own assignment operator +// directly and avoid using std::optional. +// 2. If the type is not copyable, but it is nothrow-copy-constructible, then we can implement assignment as +// destroy-and-then-construct and we know it will never fail, so we don't need an empty state. +// +// The exact same reasoning can be applied for move-assignment, with copyable replaced by movable and +// nothrow-copy-constructible replaced by nothrow-move-constructible. This specialization is enabled +// whenever we can apply any of these optimizations for both the copy assignment and the move assignment +// operator. +template +concept __doesnt_need_empty_state = + (copy_constructible<_Tp> + // 1. If copy_constructible is true, movable-box should store only a T if either T models + // copyable, or is_nothrow_move_constructible_v && is_nothrow_copy_constructible_v is true. + ? copyable<_Tp> || (is_nothrow_move_constructible_v<_Tp> && is_nothrow_copy_constructible_v<_Tp>) + // 2. Otherwise, movable-box should store only a T if either T models movable or + // is_nothrow_move_constructible_v is true. + : movable<_Tp> || is_nothrow_move_constructible_v<_Tp>); + +template <__movable_box_object _Tp> + requires __doesnt_need_empty_state<_Tp> +class __movable_box<_Tp> { + _LIBCPP_NO_UNIQUE_ADDRESS _Tp __val_; + +public: + template + requires is_constructible_v<_Tp, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr explicit __movable_box(in_place_t, _Args&&... __args) noexcept( + is_nothrow_constructible_v<_Tp, _Args...>) + : __val_(std::forward<_Args>(__args)...) {} + + _LIBCPP_HIDE_FROM_ABI constexpr __movable_box() noexcept(is_nothrow_default_constructible_v<_Tp>) + requires default_initializable<_Tp> + : __val_() {} + + _LIBCPP_HIDE_FROM_ABI __movable_box(__movable_box const&) = default; + _LIBCPP_HIDE_FROM_ABI __movable_box(__movable_box&&) = default; + + // Implementation of assignment operators in case we perform optimization (1) + _LIBCPP_HIDE_FROM_ABI __movable_box& operator=(__movable_box const&) + requires copyable<_Tp> + = default; + _LIBCPP_HIDE_FROM_ABI __movable_box& operator=(__movable_box&&) + requires movable<_Tp> + = default; + + // Implementation of assignment operators in case we perform optimization (2) + _LIBCPP_HIDE_FROM_ABI constexpr __movable_box& operator=(__movable_box const& __other) noexcept { + static_assert(is_nothrow_copy_constructible_v<_Tp>); + if (this != std::addressof(__other)) { + std::destroy_at(std::addressof(__val_)); + std::construct_at(std::addressof(__val_), __other.__val_); + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __movable_box& operator=(__movable_box&& __other) noexcept { + static_assert(is_nothrow_move_constructible_v<_Tp>); + if (this != std::addressof(__other)) { + std::destroy_at(std::addressof(__val_)); + std::construct_at(std::addressof(__val_), std::move(__other.__val_)); + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& operator*() const noexcept { return __val_; } + _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() noexcept { return __val_; } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp* operator->() const noexcept { return std::addressof(__val_); } + _LIBCPP_HIDE_FROM_ABI constexpr _Tp* operator->() noexcept { return std::addressof(__val_); } + + _LIBCPP_HIDE_FROM_ABI constexpr bool __has_value() const noexcept { return true; } +}; +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___RANGES_MOVABLE_BOX_H diff --git a/libcxx/include/__ranges/single_view.h b/libcxx/include/__ranges/single_view.h --- a/libcxx/include/__ranges/single_view.h +++ b/libcxx/include/__ranges/single_view.h @@ -12,7 +12,7 @@ #include <__concepts/constructible.h> #include <__config> -#include <__ranges/copyable_box.h> +#include <__ranges/movable_box.h> #include <__ranges/range_adaptor.h> #include <__ranges/view_interface.h> #include <__type_traits/decay.h> @@ -31,48 +31,41 @@ #if _LIBCPP_STD_VER >= 20 namespace ranges { - template - requires is_object_v<_Tp> - class single_view : public view_interface> { - __copyable_box<_Tp> __value_; +template + requires is_object_v<_Tp> +class single_view : public view_interface> { + __movable_box<_Tp> __value_; - public: - _LIBCPP_HIDE_FROM_ABI - single_view() requires default_initializable<_Tp> = default; +public: + _LIBCPP_HIDE_FROM_ABI single_view() + requires default_initializable<_Tp> + = default; - _LIBCPP_HIDE_FROM_ABI - constexpr explicit single_view(const _Tp& __t) : __value_(in_place, __t) {} + _LIBCPP_HIDE_FROM_ABI constexpr explicit single_view(const _Tp& __t) + requires copy_constructible<_Tp> + : __value_(in_place, __t) {} - _LIBCPP_HIDE_FROM_ABI - constexpr explicit single_view(_Tp&& __t) : __value_(in_place, std::move(__t)) {} + _LIBCPP_HIDE_FROM_ABI constexpr explicit single_view(_Tp&& __t) : __value_(in_place, std::move(__t)) {} - template - requires constructible_from<_Tp, _Args...> - _LIBCPP_HIDE_FROM_ABI - constexpr explicit single_view(in_place_t, _Args&&... __args) + template + requires constructible_from<_Tp, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr explicit single_view(in_place_t, _Args&&... __args) : __value_{in_place, std::forward<_Args>(__args)...} {} - _LIBCPP_HIDE_FROM_ABI - constexpr _Tp* begin() noexcept { return data(); } + _LIBCPP_HIDE_FROM_ABI constexpr _Tp* begin() noexcept { return data(); } - _LIBCPP_HIDE_FROM_ABI - constexpr const _Tp* begin() const noexcept { return data(); } + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp* begin() const noexcept { return data(); } - _LIBCPP_HIDE_FROM_ABI - constexpr _Tp* end() noexcept { return data() + 1; } + _LIBCPP_HIDE_FROM_ABI constexpr _Tp* end() noexcept { return data() + 1; } - _LIBCPP_HIDE_FROM_ABI - constexpr const _Tp* end() const noexcept { return data() + 1; } + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp* end() const noexcept { return data() + 1; } - _LIBCPP_HIDE_FROM_ABI - static constexpr size_t size() noexcept { return 1; } + _LIBCPP_HIDE_FROM_ABI static constexpr size_t size() noexcept { return 1; } - _LIBCPP_HIDE_FROM_ABI - constexpr _Tp* data() noexcept { return __value_.operator->(); } + _LIBCPP_HIDE_FROM_ABI constexpr _Tp* data() noexcept { return __value_.operator->(); } - _LIBCPP_HIDE_FROM_ABI - constexpr const _Tp* data() const noexcept { return __value_.operator->(); } - }; + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp* data() const noexcept { return __value_.operator->(); } +}; template single_view(_Tp) -> single_view<_Tp>; diff --git a/libcxx/include/__ranges/take_while_view.h b/libcxx/include/__ranges/take_while_view.h --- a/libcxx/include/__ranges/take_while_view.h +++ b/libcxx/include/__ranges/take_while_view.h @@ -20,7 +20,7 @@ #include <__ranges/access.h> #include <__ranges/all.h> #include <__ranges/concepts.h> -#include <__ranges/copyable_box.h> +#include <__ranges/movable_box.h> #include <__ranges/range_adaptor.h> #include <__ranges/view_interface.h> #include <__type_traits/decay.h> @@ -60,7 +60,7 @@ class __sentinel; _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View(); - _LIBCPP_NO_UNIQUE_ADDRESS __copyable_box<_Pred> __pred_; + _LIBCPP_NO_UNIQUE_ADDRESS __movable_box<_Pred> __pred_; public: _LIBCPP_HIDE_FROM_ABI take_while_view() diff --git a/libcxx/include/__ranges/transform_view.h b/libcxx/include/__ranges/transform_view.h --- a/libcxx/include/__ranges/transform_view.h +++ b/libcxx/include/__ranges/transform_view.h @@ -26,8 +26,8 @@ #include <__ranges/access.h> #include <__ranges/all.h> #include <__ranges/concepts.h> -#include <__ranges/copyable_box.h> #include <__ranges/empty.h> +#include <__ranges/movable_box.h> #include <__ranges/range_adaptor.h> #include <__ranges/size.h> #include <__ranges/view_interface.h> @@ -62,13 +62,13 @@ regular_invocable<_Fn&, range_reference_t<_View>> && __can_reference>>; -template +template requires __transform_view_constraints<_View, _Fn> class transform_view : public view_interface> { template class __iterator; template class __sentinel; - _LIBCPP_NO_UNIQUE_ADDRESS __copyable_box<_Fn> __func_; + _LIBCPP_NO_UNIQUE_ADDRESS __movable_box<_Fn> __func_; _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View(); public: @@ -161,7 +161,7 @@ >; }; -template +template requires __transform_view_constraints<_View, _Fn> template class transform_view<_View, _Fn>::__iterator @@ -357,7 +357,7 @@ } }; -template +template requires __transform_view_constraints<_View, _Fn> template class transform_view<_View, _Fn>::__sentinel { diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1350,7 +1350,6 @@ module common_view { private header "__ranges/common_view.h" } module concepts { private header "__ranges/concepts.h" } module container_compatible_range { private header "__ranges/container_compatible_range.h" } - module copyable_box { private header "__ranges/copyable_box.h" } module counted { private header "__ranges/counted.h" export span @@ -1373,6 +1372,7 @@ } module join_view { private header "__ranges/join_view.h" } module lazy_split_view { private header "__ranges/lazy_split_view.h" } + module movable_box { private header "__ranges/movable_box.h" } module non_propagating_cache { private header "__ranges/non_propagating_cache.h" } module owning_view { private header "__ranges/owning_view.h" } module range_adaptor { private header "__ranges/range_adaptor.h" } diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -593,7 +593,6 @@ #include <__ranges/common_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/common_view.h'}} #include <__ranges/concepts.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/concepts.h'}} #include <__ranges/container_compatible_range.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/container_compatible_range.h'}} -#include <__ranges/copyable_box.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/copyable_box.h'}} #include <__ranges/counted.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/counted.h'}} #include <__ranges/dangling.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/dangling.h'}} #include <__ranges/data.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/data.h'}} @@ -610,6 +609,7 @@ #include <__ranges/istream_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/istream_view.h'}} #include <__ranges/join_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/join_view.h'}} #include <__ranges/lazy_split_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/lazy_split_view.h'}} +#include <__ranges/movable_box.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/movable_box.h'}} #include <__ranges/non_propagating_cache.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/non_propagating_cache.h'}} #include <__ranges/owning_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/owning_view.h'}} #include <__ranges/range_adaptor.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/range_adaptor.h'}} diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/properties.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/properties.compile.pass.cpp deleted file mode 100644 --- a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/properties.compile.pass.cpp +++ /dev/null @@ -1,45 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// Test various properties of - -#include - -#include - -#include "types.h" - -template -constexpr bool valid_copyable_box = requires { - typename std::ranges::__copyable_box; -}; - -struct NotCopyConstructible { - NotCopyConstructible() = default; - NotCopyConstructible(NotCopyConstructible&&) = default; - NotCopyConstructible(NotCopyConstructible const&) = delete; - NotCopyConstructible& operator=(NotCopyConstructible&&) = default; - NotCopyConstructible& operator=(NotCopyConstructible const&) = default; -}; - -static_assert(!valid_copyable_box); // not an object type -static_assert(!valid_copyable_box); // not an object type -static_assert(!valid_copyable_box); - -// primary template -static_assert(sizeof(std::ranges::__copyable_box) == sizeof(std::optional)); - -// optimization #1 -static_assert(sizeof(std::ranges::__copyable_box) == sizeof(Copyable)); -static_assert(alignof(std::ranges::__copyable_box) == alignof(Copyable)); - -// optimization #2 -static_assert(sizeof(std::ranges::__copyable_box) == sizeof(NothrowCopyConstructible)); -static_assert(alignof(std::ranges::__copyable_box) == alignof(NothrowCopyConstructible)); diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/arrow.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/arrow.pass.cpp rename from libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/arrow.pass.cpp rename to libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/arrow.pass.cpp --- a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/arrow.pass.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/arrow.pass.cpp @@ -19,11 +19,11 @@ #include "types.h" -template +template constexpr void check() { // non-const version { - std::ranges::__copyable_box x(std::in_place, 10); + std::ranges::__movable_box x(std::in_place, 10); T* result = x.operator->(); static_assert(noexcept(x.operator->())); assert(result->value == 10); @@ -32,7 +32,7 @@ // const version { - std::ranges::__copyable_box const x(std::in_place, 10); + std::ranges::__movable_box const x(std::in_place, 10); const T* result = x.operator->(); static_assert(noexcept(x.operator->())); assert(result->value == 10); @@ -41,8 +41,8 @@ } constexpr bool test() { - check(); // primary template - check(); // optimization #1 + check(); // primary template + check(); // optimization #1 check(); // optimization #2 return true; } diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/assign.copy.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/assign.copy.pass.cpp rename from libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/assign.copy.pass.cpp rename to libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/assign.copy.pass.cpp --- a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/assign.copy.pass.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/assign.copy.pass.cpp @@ -24,8 +24,8 @@ constexpr bool test() { // Test the primary template { - using Box = std::ranges::__copyable_box; - static_assert( std::is_copy_assignable_v); + using Box = std::ranges::__movable_box; + static_assert(std::is_copy_assignable_v); static_assert(!std::is_nothrow_copy_assignable_v); { @@ -51,8 +51,8 @@ // Test optimization #1 for copy-assignment { - using Box = std::ranges::__copyable_box; - static_assert( std::is_copy_assignable_v); + using Box = std::ranges::__movable_box; + static_assert(std::is_copy_assignable_v); static_assert(!std::is_nothrow_copy_assignable_v); { @@ -80,7 +80,7 @@ // Test optimization #2 for copy-assignment { - using Box = std::ranges::__copyable_box; + using Box = std::ranges::__movable_box; static_assert(std::is_copy_assignable_v); static_assert(std::is_nothrow_copy_assignable_v); @@ -112,7 +112,7 @@ // through throwing an exception. #if !defined(TEST_HAS_NO_EXCEPTIONS) void test_empty_state() { - using Box = std::ranges::__copyable_box; + using Box = std::ranges::__movable_box; // assign non-empty to empty { @@ -137,7 +137,7 @@ } // assign empty to empty { - Box x = create_empty_box(); + Box x = create_empty_box(); Box const y = create_empty_box(); Box& result = (x = y); @@ -147,7 +147,7 @@ } // check self-assignment in empty case { - Box x = create_empty_box(); + Box x = create_empty_box(); Box& result = (x = x); assert(&result == &x); diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/assign.move.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/assign.move.pass.cpp rename from libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/assign.move.pass.cpp rename to libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/assign.move.pass.cpp --- a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/assign.move.pass.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/assign.move.pass.cpp @@ -24,8 +24,8 @@ constexpr bool test() { // Test the primary template { - using Box = std::ranges::__copyable_box; - static_assert( std::is_move_assignable_v); + using Box = std::ranges::__movable_box; + static_assert(std::is_move_assignable_v); static_assert(!std::is_nothrow_move_assignable_v); { @@ -51,9 +51,10 @@ // Make sure that we use the native move assignment in the primary template if we can. { - using Box = std::ranges::__copyable_box; + using Box = std::ranges::__movable_box; static_assert(std::is_move_assignable_v); - static_assert(std::is_nothrow_move_assignable_v == std::is_nothrow_move_assignable_v); + static_assert( + std::is_nothrow_move_assignable_v == std::is_nothrow_move_assignable_v); { Box x(std::in_place, 5); @@ -80,8 +81,8 @@ // Test optimization #1 for move assignment { - using Box = std::ranges::__copyable_box; - static_assert( std::is_move_assignable_v); + using Box = std::ranges::__movable_box; + static_assert(std::is_move_assignable_v); static_assert(!std::is_nothrow_move_assignable_v); { @@ -109,9 +110,10 @@ // Test optimization #1 for move assignment with a type that uses optimization #2 for copy assignment { - using Box = std::ranges::__copyable_box; + using Box = std::ranges::__movable_box; static_assert(std::is_move_assignable_v); - static_assert(std::is_nothrow_move_assignable_v == std::is_nothrow_move_assignable_v); + static_assert( + std::is_nothrow_move_assignable_v == std::is_nothrow_move_assignable_v); { Box x(std::in_place, 5); @@ -138,7 +140,7 @@ // Test optimization #2 for move assignment { - using Box = std::ranges::__copyable_box; + using Box = std::ranges::__movable_box; static_assert(std::is_move_assignable_v); static_assert(std::is_nothrow_move_assignable_v); @@ -170,7 +172,7 @@ // through throwing an exception. #if !defined(TEST_HAS_NO_EXCEPTIONS) void test_empty_state() { - using Box = std::ranges::__copyable_box; + using Box = std::ranges::__movable_box; // assign non-empty to empty { @@ -186,7 +188,7 @@ // assign empty to non-empty { Box x(std::in_place, 5); - Box y = create_empty_box(); + Box y = create_empty_box(); Box& result = (x = std::move(y)); assert(&result == &x); @@ -195,8 +197,8 @@ } // assign empty to empty { - Box x = create_empty_box(); - Box y = create_empty_box(); + Box x = create_empty_box(); + Box y = create_empty_box(); Box& result = (x = std::move(y)); assert(&result == &x); @@ -205,7 +207,7 @@ } // check self-assignment in empty case { - Box x = create_empty_box(); + Box x = create_empty_box(); Box& result = (x = std::move(x)); assert(&result == &x); diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/ctor.default.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/ctor.default.pass.cpp rename from libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/ctor.default.pass.cpp rename to libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/ctor.default.pass.cpp --- a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/ctor.default.pass.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/ctor.default.pass.cpp @@ -18,19 +18,19 @@ #include "types.h" -template -using Box = std::ranges::__copyable_box; +template +using Box = std::ranges::__movable_box; struct NoDefault { NoDefault() = delete; }; static_assert(!std::is_default_constructible_v>); -template +template struct DefaultNoexcept { DefaultNoexcept() noexcept(Noexcept); }; -static_assert( std::is_nothrow_default_constructible_v>>); +static_assert(std::is_nothrow_default_constructible_v>>); static_assert(!std::is_nothrow_default_constructible_v>>); constexpr bool test() { diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/ctor.in_place.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/ctor.in_place.pass.cpp rename from libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/ctor.in_place.pass.cpp rename to libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/ctor.in_place.pass.cpp --- a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/ctor.in_place.pass.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/ctor.in_place.pass.cpp @@ -19,9 +19,9 @@ #include "types.h" -struct UnknownType { }; +struct UnknownType {}; -template +template struct NothrowConstructible { explicit NothrowConstructible(int) noexcept(Noexcept); }; @@ -29,7 +29,7 @@ constexpr bool test() { // Test the primary template { - using Box = std::ranges::__copyable_box; + using Box = std::ranges::__movable_box; Box x(std::in_place, 5); assert((*x).value == 5); @@ -38,7 +38,7 @@ // Test optimization #1 { - using Box = std::ranges::__copyable_box; + using Box = std::ranges::__movable_box; Box x(std::in_place, 5); assert((*x).value == 5); @@ -47,15 +47,17 @@ // Test optimization #2 { - using Box = std::ranges::__copyable_box; + using Box = std::ranges::__movable_box; Box x(std::in_place, 5); assert((*x).value == 5); static_assert(!std::is_constructible_v); } - static_assert( std::is_nothrow_constructible_v>, std::in_place_t, int>); - static_assert(!std::is_nothrow_constructible_v>, std::in_place_t, int>); + static_assert( + std::is_nothrow_constructible_v>, std::in_place_t, int>); + static_assert( + !std::is_nothrow_constructible_v>, std::in_place_t, int>); return true; } diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/deref.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/deref.pass.cpp rename from libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/deref.pass.cpp rename to libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/deref.pass.cpp --- a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/deref.pass.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/deref.pass.cpp @@ -19,11 +19,11 @@ #include "types.h" -template +template constexpr void check() { // non-const version { - std::ranges::__copyable_box x(std::in_place, 10); + std::ranges::__movable_box x(std::in_place, 10); T& result = *x; static_assert(noexcept(*x)); assert(result.value == 10); @@ -31,7 +31,7 @@ // const version { - std::ranges::__copyable_box const x(std::in_place, 10); + std::ranges::__movable_box const x(std::in_place, 10); T const& result = *x; static_assert(noexcept(*x)); assert(result.value == 10); @@ -39,8 +39,8 @@ } constexpr bool test() { - check(); // primary template - check(); // optimization #1 + check(); // primary template + check(); // optimization #1 check(); // optimization #2 return true; } diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/has_value.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/has_value.pass.cpp rename from libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/has_value.pass.cpp rename to libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/has_value.pass.cpp --- a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/has_value.pass.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/has_value.pass.cpp @@ -18,15 +18,15 @@ #include "types.h" -template +template constexpr void check() { - std::ranges::__copyable_box const x(std::in_place, 10); + std::ranges::__movable_box const x(std::in_place, 10); assert(x.__has_value()); } constexpr bool test() { - check(); // primary template - check(); // optimization #1 + check(); // primary template + check(); // optimization #1 check(); // optimization #2 return true; } @@ -39,7 +39,7 @@ // through throwing an exception. #if !defined(TEST_HAS_NO_EXCEPTIONS) { - std::ranges::__copyable_box x = create_empty_box(); + std::ranges::__movable_box x = create_empty_box(); assert(!x.__has_value()); } #endif diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/no_unique_address.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/no_unique_address.pass.cpp rename from libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/no_unique_address.pass.cpp rename to libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/no_unique_address.pass.cpp --- a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/no_unique_address.pass.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/no_unique_address.pass.cpp @@ -16,19 +16,19 @@ #include bool copied = false; -bool moved = false; +bool moved = false; struct Empty { - Empty() noexcept { } + Empty() noexcept {} Empty(Empty const&) noexcept { copied = true; } Empty(Empty&&) noexcept { moved = true; } Empty& operator=(Empty const&) = delete; - Empty& operator=(Empty&&) = delete; + Empty& operator=(Empty&&) = delete; }; -using Box = std::ranges::__copyable_box; +using Box = std::ranges::__movable_box; -struct Inherit : Box { }; +struct Inherit : Box {}; struct Hold : Box { [[no_unique_address]] Inherit member; @@ -37,7 +37,7 @@ int main(int, char**) { Hold box; - Box& base = static_cast(box); + Box& base = static_cast(box); Box& member = static_cast(box.member); // Despite [[no_unique_address]], the two objects have the same type so they diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/properties.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/properties.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/properties.compile.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// Test various properties of + +#include + +#include + +#include "types.h" +#include "MoveOnly.h" + +template +constexpr bool valid_movable_box = requires { typename std::ranges::__movable_box; }; + +struct NotCopyConstructible { + NotCopyConstructible() = default; + NotCopyConstructible(NotCopyConstructible&&) = default; + NotCopyConstructible(NotCopyConstructible const&) = delete; + NotCopyConstructible& operator=(NotCopyConstructible&&) = default; + NotCopyConstructible& operator=(NotCopyConstructible const&) = default; +}; + +struct NotMoveConstructible { + NotMoveConstructible() = default; + NotMoveConstructible(NotMoveConstructible&&) = delete; + NotMoveConstructible& operator=(NotMoveConstructible&&) = delete; +}; + +static_assert(!valid_movable_box); // not an object type +static_assert(!valid_movable_box); // not an object type +static_assert(!valid_movable_box); +static_assert(valid_movable_box); +static_assert(valid_movable_box); + +// primary template +static_assert(sizeof(std::ranges::__movable_box) == sizeof(std::optional)); +static_assert(sizeof(std::ranges::__movable_box) == sizeof(std::optional)); + +// optimization #1 +static_assert(sizeof(std::ranges::__movable_box) == sizeof(Copyable)); +static_assert(alignof(std::ranges::__movable_box) == alignof(Copyable)); + +// optimization #2 +static_assert(sizeof(std::ranges::__movable_box) == sizeof(NothrowCopyConstructible)); +static_assert(alignof(std::ranges::__movable_box) == alignof(NothrowCopyConstructible)); diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/types.h b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/types.h rename from libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/types.h rename to libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/types.h --- a/libcxx/test/libcxx/ranges/range.adaptors/range.copy.wrap/types.h +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.move.wrap/types.h @@ -16,15 +16,15 @@ #include "test_macros.h" -// NOTE: These types are strongly tied to the implementation of __copyable_box. See the documentation -// in __copyable_box for the meaning of optimizations #1 and #2. +// NOTE: These types are strongly tied to the implementation of __movable_box. See the documentation +// in __movable_box for the meaning of optimizations #1 and #2. // Copy constructible, but neither copyable nor nothrow_copy/move_constructible. This uses the primary template. struct CopyConstructible { constexpr CopyConstructible() = default; - constexpr explicit CopyConstructible(int x) : value(x) { } + constexpr explicit CopyConstructible(int x) : value(x) {} CopyConstructible(CopyConstructible const&) noexcept(false) = default; - CopyConstructible& operator=(CopyConstructible const&) = delete; + CopyConstructible& operator=(CopyConstructible const&) = delete; int value = -1; }; @@ -33,105 +33,102 @@ static_assert(!std::movable); static_assert(!std::is_nothrow_move_constructible_v); - // Copy constructible and movable, but not copyable. This uses the primary template, however we're // still able to use the native move-assignment operator in this case. struct CopyConstructibleMovable { constexpr CopyConstructibleMovable() = default; - constexpr explicit CopyConstructibleMovable(int x) : value(x) { } + constexpr explicit CopyConstructibleMovable(int x) : value(x) {} CopyConstructibleMovable(CopyConstructibleMovable const&) noexcept(false) = default; - CopyConstructibleMovable(CopyConstructibleMovable&&) noexcept(false) = default; - CopyConstructibleMovable& operator=(CopyConstructibleMovable const&) = delete; + CopyConstructibleMovable(CopyConstructibleMovable&&) noexcept(false) = default; + CopyConstructibleMovable& operator=(CopyConstructibleMovable const&) = delete; constexpr CopyConstructibleMovable& operator=(CopyConstructibleMovable&& other) { - value = other.value; + value = other.value; did_move_assign = true; return *this; } - int value = -1; + int value = -1; bool did_move_assign = false; }; - // Copyable type that is not nothrow_copy/move_constructible. // This triggers optimization #1 for the copy assignment and the move assignment. struct Copyable { constexpr Copyable() = default; - constexpr explicit Copyable(int x) : value(x) { } + constexpr explicit Copyable(int x) : value(x) {} Copyable(Copyable const&) noexcept(false) = default; constexpr Copyable& operator=(Copyable const& other) noexcept(false) { - value = other.value; + value = other.value; did_copy_assign = true; return *this; } constexpr Copyable& operator=(Copyable&& other) noexcept(false) { - value = other.value; + value = other.value; did_move_assign = true; return *this; } - int value = -1; + int value = -1; bool did_copy_assign = false; bool did_move_assign = false; }; -static_assert( std::copyable); +static_assert(std::copyable); static_assert(!std::is_nothrow_copy_constructible_v); -static_assert( std::movable); +static_assert(std::movable); static_assert(!std::is_nothrow_move_constructible_v); - // Non-copyable type that is nothrow_copy_constructible and nothrow_move_constructible. // This triggers optimization #2 for the copy assignment and the move assignment. struct NothrowCopyConstructible { constexpr NothrowCopyConstructible() = default; - constexpr explicit NothrowCopyConstructible(int x) : value(x) { } - NothrowCopyConstructible(NothrowCopyConstructible const&) noexcept = default; - NothrowCopyConstructible(NothrowCopyConstructible&&) noexcept = default; + constexpr explicit NothrowCopyConstructible(int x) : value(x) {} + NothrowCopyConstructible(NothrowCopyConstructible const&) noexcept = default; + NothrowCopyConstructible(NothrowCopyConstructible&&) noexcept = default; NothrowCopyConstructible& operator=(NothrowCopyConstructible const&) = delete; int value = -1; }; static_assert(!std::copyable); -static_assert( std::is_nothrow_copy_constructible_v); +static_assert(std::is_nothrow_copy_constructible_v); static_assert(!std::movable); -static_assert( std::is_nothrow_move_constructible_v); - +static_assert(std::is_nothrow_move_constructible_v); // Non-copyable type that is nothrow_copy_constructible, and that is movable but NOT nothrow_move_constructible. // This triggers optimization #2 for the copy assignment, and optimization #1 for the move assignment. struct MovableNothrowCopyConstructible { constexpr MovableNothrowCopyConstructible() = default; - constexpr explicit MovableNothrowCopyConstructible(int x) : value(x) { } - MovableNothrowCopyConstructible(MovableNothrowCopyConstructible const&) noexcept = default; + constexpr explicit MovableNothrowCopyConstructible(int x) : value(x) {} + MovableNothrowCopyConstructible(MovableNothrowCopyConstructible const&) noexcept = default; MovableNothrowCopyConstructible(MovableNothrowCopyConstructible&&) noexcept(false) = default; constexpr MovableNothrowCopyConstructible& operator=(MovableNothrowCopyConstructible&& other) { - value = other.value; + value = other.value; did_move_assign = true; return *this; } - int value = -1; + int value = -1; bool did_move_assign = false; }; static_assert(!std::copyable); -static_assert( std::is_nothrow_copy_constructible_v); -static_assert( std::movable); +static_assert(std::is_nothrow_copy_constructible_v); +static_assert(std::movable); static_assert(!std::is_nothrow_move_constructible_v); - #if !defined(TEST_HAS_NO_EXCEPTIONS) // A type that we can make throw when copied from. This is used to create a // copyable-box in the empty state. static constexpr int THROW_WHEN_COPIED_FROM = 999; struct ThrowsOnCopy { constexpr ThrowsOnCopy() = default; - constexpr explicit ThrowsOnCopy(int x) : value(x) { } + constexpr explicit ThrowsOnCopy(int x) : value(x) {} ThrowsOnCopy(ThrowsOnCopy const& other) { - if (other.value == THROW_WHEN_COPIED_FROM) throw 0; - else value = other.value; + if (other.value == THROW_WHEN_COPIED_FROM) + throw 0; + else + value = other.value; } ThrowsOnCopy& operator=(ThrowsOnCopy const&) = delete; // prevent from being copyable @@ -142,9 +139,9 @@ // Creates an empty box. The only way to do that is to try assigning one box // to another and have that fail due to an exception when calling the copy // constructor. The assigned-to box will then be in the empty state. -inline std::ranges::__copyable_box create_empty_box() { - std::ranges::__copyable_box box1; - std::ranges::__copyable_box box2(std::in_place, THROW_WHEN_COPIED_FROM); +inline std::ranges::__movable_box create_empty_box() { + std::ranges::__movable_box box1; + std::ranges::__movable_box box2(std::in_place, THROW_WHEN_COPIED_FROM); try { box1 = box2; // throws during assignment, which is implemented as a call to the copy ctor } catch (...) { diff --git a/libcxx/test/std/ranges/range.factories/range.single.view/cpo.pass.cpp b/libcxx/test/std/ranges/range.factories/range.single.view/cpo.pass.cpp --- a/libcxx/test/std/ranges/range.factories/range.single.view/cpo.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.single.view/cpo.pass.cpp @@ -19,8 +19,8 @@ // Can't invoke without arguments. static_assert(!std::is_invocable_v); -// Can't invoke with a move-only type. -static_assert(!std::is_invocable_v); +// Invoke with a move-only type. +static_assert(std::is_invocable_v); constexpr bool test() { // Lvalue. diff --git a/libcxx/utils/data/ignore_format.txt b/libcxx/utils/data/ignore_format.txt --- a/libcxx/utils/data/ignore_format.txt +++ b/libcxx/utils/data/ignore_format.txt @@ -559,7 +559,6 @@ libcxx/include/__ranges/all.h libcxx/include/__ranges/common_view.h libcxx/include/__ranges/concepts.h -libcxx/include/__ranges/copyable_box.h libcxx/include/__ranges/counted.h libcxx/include/__ranges/data.h libcxx/include/__ranges/drop_view.h