mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-16 22:06:36 +00:00
[libc++][memory] P1132R8: out_ptr
- a scalable output pointer abstraction (#73618)
Differential Revision: https://reviews.llvm.org/D150525 Implements: - https://wg21.link/P1132R8 - `out_ptr` - a scalable output pointer abstraction - https://eel.is/c++draft/smartptr.adapt - 20.3.4 Smart pointer adaptors - https://wg21.link/LWG3734 - Inconsistency in `inout_ptr` and `out_ptr` for empty case - https://wg21.link/LWG3897- `inout_ptr` will not update raw pointer to 0 --------- Co-authored-by: Hristo Hristov <zingam@outlook.com>
This commit is contained in:
parent
1df2e0c344
commit
e475bb7ac3
@ -346,7 +346,7 @@ Status
|
||||
---------------------------------------------------------- -----------------
|
||||
``__cpp_lib_optional`` ``202110L``
|
||||
---------------------------------------------------------- -----------------
|
||||
``__cpp_lib_out_ptr`` *unimplemented*
|
||||
``__cpp_lib_out_ptr`` ``202106L``
|
||||
---------------------------------------------------------- -----------------
|
||||
``__cpp_lib_print`` ``202207L``
|
||||
---------------------------------------------------------- -----------------
|
||||
@ -450,7 +450,7 @@ Status
|
||||
---------------------------------------------------------- -----------------
|
||||
``__cpp_lib_optional_range_support`` *unimplemented*
|
||||
---------------------------------------------------------- -----------------
|
||||
``__cpp_lib_out_ptr`` *unimplemented*
|
||||
``__cpp_lib_out_ptr`` ``202311L``
|
||||
---------------------------------------------------------- -----------------
|
||||
``__cpp_lib_philox_engine`` *unimplemented*
|
||||
---------------------------------------------------------- -----------------
|
||||
|
@ -38,6 +38,7 @@ What's New in Libc++ 19.0.0?
|
||||
Implemented Papers
|
||||
------------------
|
||||
|
||||
- P1132R8 - ``out_ptr`` - a scalable output pointer abstraction
|
||||
- P2637R3 - Member ``visit``
|
||||
- P2652R2 - Disallow User Specialization of ``allocator_traits``
|
||||
- P2819R2 - Add ``tuple`` protocol to ``complex``
|
||||
|
@ -192,7 +192,7 @@
|
||||
"`3515 <https://wg21.link/LWG3515>`__","§[stacktrace.basic.nonmem]: ``operator<<`` should be less templatized", "November 2022","","",""
|
||||
"`3545 <https://wg21.link/LWG3545>`__","``std::pointer_traits`` should be SFINAE-friendly", "November 2022","|Complete|","18.0",""
|
||||
"`3569 <https://wg21.link/LWG3569>`__","``join_view`` fails to support ranges of ranges with non-default_initializable iterators", "November 2022","","","|ranges|"
|
||||
"`3594 <https://wg21.link/LWG3594>`__","``inout_ptr`` — inconsistent ``release()`` in destructor", "November 2022","","",""
|
||||
"`3594 <https://wg21.link/LWG3594>`__","``inout_ptr`` — inconsistent ``release()`` in destructor", "November 2022","|Complete|","19.0",""
|
||||
"`3597 <https://wg21.link/LWG3597>`__","Unsigned integer types don't model advanceable", "November 2022","","","|ranges|"
|
||||
"`3600 <https://wg21.link/LWG3600>`__","Making ``istream_iterator`` copy constructor trivial is an ABI break", "November 2022","","",""
|
||||
"`3629 <https://wg21.link/LWG3629>`__","``make_error_code`` and ``make_error_condition`` are customization points","November 2022","|Complete|","16.0",""
|
||||
@ -282,7 +282,7 @@
|
||||
"`3645 <https://wg21.link/LWG3645>`__","``resize_and_overwrite`` is overspecified to call its callback with lvalues","February 2023","|Complete|","14.0",""
|
||||
"`3655 <https://wg21.link/LWG3655>`__","The ``INVOKE`` operation and union types","February 2023","|Complete|","18.0",""
|
||||
"`3723 <https://wg21.link/LWG3723>`__","``priority_queue::push_range`` needs to ``append_range``","February 2023","","","|ranges|"
|
||||
"`3734 <https://wg21.link/LWG3734>`__","Inconsistency in ``inout_ptr`` and ``out_ptr`` for empty case","February 2023","","",""
|
||||
"`3734 <https://wg21.link/LWG3734>`__","Inconsistency in ``inout_ptr`` and ``out_ptr`` for empty case","February 2023","|Complete|","19.0",""
|
||||
"`3772 <https://wg21.link/LWG3772>`__","``repeat_view``'s ``piecewise`` constructor is missing Postconditions","February 2023","|Complete|","17.0","|ranges|"
|
||||
"`3786 <https://wg21.link/LWG3786>`__","Flat maps' deduction guide needs to default ``Allocator`` to be useful","February 2023","","",""
|
||||
"`3803 <https://wg21.link/LWG3803>`__","``flat_foo`` constructors taking ``KeyContainer`` lack ``KeyCompare`` parameter","February 2023","","",""
|
||||
|
Can't render this file because it has a wrong number of fields in line 2.
|
@ -13,7 +13,7 @@
|
||||
"","","","","","",""
|
||||
"`P0401R6 <https://wg21.link/P0401R6>`__","LWG","Providing size feedback in the Allocator interface","June 2021","|Complete|","15.0"
|
||||
"`P0448R4 <https://wg21.link/P0448R4>`__","LWG","A strstream replacement using span<charT> as buffer","June 2021","",""
|
||||
"`P1132R8 <https://wg21.link/P1132R8>`__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","",""
|
||||
"`P1132R8 <https://wg21.link/P1132R8>`__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","|Complete|","19.0"
|
||||
"`P1328R1 <https://wg21.link/P1328R1>`__","LWG","Making std::type_info::operator== constexpr","June 2021","|Complete|","17.0"
|
||||
"`P1425R4 <https://wg21.link/P1425R4>`__","LWG","Iterators pair constructors for stack and queue","June 2021","|Complete|","14.0","|ranges|"
|
||||
"`P1518R2 <https://wg21.link/P1518R2>`__","LWG","Stop overconstraining allocators in container deduction guides","June 2021","|Complete|","13.0"
|
||||
|
Can't render this file because it has a wrong number of fields in line 2.
|
@ -24,7 +24,7 @@
|
||||
"`3749 <https://wg21.link/LWG3749>`__","``common_iterator`` should handle integer-class difference types","Kona November 2023","","",""
|
||||
"`3809 <https://wg21.link/LWG3809>`__","Is ``std::subtract_with_carry_engine<uint16_t>`` supposed to work","Kona November 2023","","",""
|
||||
"`3892 <https://wg21.link/LWG3892>`__","Incorrect formatting of nested ranges and tuples","Kona November 2023","|Complete|","17.0","|format|"
|
||||
"`3897 <https://wg21.link/LWG3897>`__","``inout_ptr`` will not update raw pointer to 0","Kona November 2023","","",""
|
||||
"`3897 <https://wg21.link/LWG3897>`__","``inout_ptr`` will not update raw pointer to 0","Kona November 2023","|Complete|","19.0",""
|
||||
"`3946 <https://wg21.link/LWG3946>`__","The definition of ``const_iterator_t`` should be reworked","Kona November 2023","","",""
|
||||
"`3947 <https://wg21.link/LWG3947>`__","Unexpected constraints on ``adjacent_transform_view::base()``","Kona November 2023","","","|ranges|"
|
||||
"`3948 <https://wg21.link/LWG3948>`__","``possibly-const-range and as-const-pointer`` should be ``noexcept``","Kona November 2023","","","|ranges|"
|
||||
|
|
@ -533,6 +533,8 @@ set(files
|
||||
__memory/concepts.h
|
||||
__memory/construct_at.h
|
||||
__memory/destruct_n.h
|
||||
__memory/inout_ptr.h
|
||||
__memory/out_ptr.h
|
||||
__memory/pointer_traits.h
|
||||
__memory/ranges_construct_at.h
|
||||
__memory/ranges_uninitialized_algorithms.h
|
||||
|
@ -41,7 +41,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
|
||||
struct NAME<_Tp, __void_t<typename _Tp::PROPERTY > > : true_type {}
|
||||
|
||||
// __pointer
|
||||
_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_pointer, pointer);
|
||||
template <class _Tp,
|
||||
class _Alloc,
|
||||
class _RawAlloc = __libcpp_remove_reference_t<_Alloc>,
|
||||
|
109
libcxx/include/__memory/inout_ptr.h
Normal file
109
libcxx/include/__memory/inout_ptr.h
Normal file
@ -0,0 +1,109 @@
|
||||
// -*- 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___INOUT_PTR_H
|
||||
#define _LIBCPP___INOUT_PTR_H
|
||||
|
||||
#include <__config>
|
||||
#include <__memory/addressof.h>
|
||||
#include <__memory/pointer_traits.h>
|
||||
#include <__memory/shared_ptr.h>
|
||||
#include <__memory/unique_ptr.h>
|
||||
#include <__type_traits/is_same.h>
|
||||
#include <__type_traits/is_specialization.h>
|
||||
#include <__type_traits/is_void.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <__utility/move.h>
|
||||
#include <tuple>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_PUSH_MACROS
|
||||
#include <__undef_macros>
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
|
||||
template <class _Smart, class _Pointer, class... _Args>
|
||||
class _LIBCPP_TEMPLATE_VIS inout_ptr_t {
|
||||
static_assert(!__is_specialization_v<_Smart, shared_ptr>, "std::shared_ptr<> is not supported with std::inout_ptr.");
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI explicit inout_ptr_t(_Smart& __smart, _Args... __args)
|
||||
: __s_(__smart), __a_(std::forward<_Args>(__args)...), __p_([&__smart] {
|
||||
if constexpr (is_pointer_v<_Smart>) {
|
||||
return __smart;
|
||||
} else {
|
||||
return __smart.get();
|
||||
}
|
||||
}()) {
|
||||
if constexpr (requires { __s_.release(); }) {
|
||||
__s_.release();
|
||||
} else {
|
||||
__s_ = _Smart();
|
||||
}
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI inout_ptr_t(const inout_ptr_t&) = delete;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI ~inout_ptr_t() {
|
||||
// LWG-3897 inout_ptr will not update raw pointer to null
|
||||
if constexpr (!is_pointer_v<_Smart>) {
|
||||
if (!__p_) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
using _SP = __pointer_of_or_t<_Smart, _Pointer>;
|
||||
if constexpr (is_pointer_v<_Smart>) {
|
||||
std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
|
||||
std::move(__a_));
|
||||
} else if constexpr (__resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...>) {
|
||||
std::apply([&](auto&&... __args) { __s_.reset(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
|
||||
std::move(__a_));
|
||||
} else {
|
||||
static_assert(is_constructible_v<_Smart, _SP, _Args...>,
|
||||
"The smart pointer must be constructible from arguments of types _Smart, _Pointer, _Args...");
|
||||
std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
|
||||
std::move(__a_));
|
||||
}
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI operator _Pointer*() const noexcept { return std::addressof(const_cast<_Pointer&>(__p_)); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI operator void**() const noexcept
|
||||
requires(!is_same_v<_Pointer, void*>)
|
||||
{
|
||||
static_assert(is_pointer_v<_Pointer>, "The conversion to void** requires _Pointer to be a raw pointer.");
|
||||
|
||||
return reinterpret_cast<void**>(static_cast<_Pointer*>(*this));
|
||||
}
|
||||
|
||||
private:
|
||||
_Smart& __s_;
|
||||
tuple<_Args...> __a_;
|
||||
_Pointer __p_;
|
||||
};
|
||||
|
||||
template <class _Pointer = void, class _Smart, class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI auto inout_ptr(_Smart& __s, _Args&&... __args) {
|
||||
using _Ptr = conditional_t<is_void_v<_Pointer>, __pointer_of_t<_Smart>, _Pointer>;
|
||||
return std::inout_ptr_t<_Smart, _Ptr, _Args&&...>(__s, std::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
#endif // _LIBCPP_STD_VER >= 23
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
_LIBCPP_POP_MACROS
|
||||
|
||||
#endif // _LIBCPP___INOUT_PTR_H
|
101
libcxx/include/__memory/out_ptr.h
Normal file
101
libcxx/include/__memory/out_ptr.h
Normal file
@ -0,0 +1,101 @@
|
||||
// -*- 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___OUT_PTR_H
|
||||
#define _LIBCPP___OUT_PTR_H
|
||||
|
||||
#include <__config>
|
||||
#include <__memory/addressof.h>
|
||||
#include <__memory/pointer_traits.h>
|
||||
#include <__memory/shared_ptr.h>
|
||||
#include <__memory/unique_ptr.h>
|
||||
#include <__type_traits/is_specialization.h>
|
||||
#include <__type_traits/is_void.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <__utility/move.h>
|
||||
#include <tuple>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_PUSH_MACROS
|
||||
#include <__undef_macros>
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
|
||||
template <class _Smart, class _Pointer, class... _Args>
|
||||
class _LIBCPP_TEMPLATE_VIS out_ptr_t {
|
||||
static_assert(!__is_specialization_v<_Smart, shared_ptr> || sizeof...(_Args) > 0,
|
||||
"Using std::shared_ptr<> without a deleter in std::out_ptr is not supported.");
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI explicit out_ptr_t(_Smart& __smart, _Args... __args)
|
||||
: __s_(__smart), __a_(std::forward<_Args>(__args)...), __p_() {
|
||||
using _Ptr = decltype(__smart);
|
||||
if constexpr (__resettable_smart_pointer<_Ptr>) {
|
||||
__s_.reset();
|
||||
} else if constexpr (is_constructible_v<_Smart>) {
|
||||
__s_ = _Smart();
|
||||
} else {
|
||||
static_assert(__resettable_smart_pointer<_Ptr> || is_constructible_v<_Smart>,
|
||||
"The adapted pointer type must have a reset() member function or be default constructible.");
|
||||
}
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI out_ptr_t(const out_ptr_t&) = delete;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI ~out_ptr_t() {
|
||||
if (!__p_) {
|
||||
return;
|
||||
}
|
||||
|
||||
using _SP = __pointer_of_or_t<_Smart, _Pointer>;
|
||||
if constexpr (__resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...>) {
|
||||
std::apply([&](auto&&... __args) { __s_.reset(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
|
||||
std::move(__a_));
|
||||
} else {
|
||||
static_assert(is_constructible_v<_Smart, _SP, _Args...>,
|
||||
"The smart pointer must be constructible from arguments of types _Smart, _Pointer, _Args...");
|
||||
std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
|
||||
std::move(__a_));
|
||||
}
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI operator _Pointer*() const noexcept { return std::addressof(const_cast<_Pointer&>(__p_)); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI operator void**() const noexcept
|
||||
requires(!is_same_v<_Pointer, void*>)
|
||||
{
|
||||
static_assert(is_pointer_v<_Pointer>, "The conversion to void** requires _Pointer to be a raw pointer.");
|
||||
|
||||
return reinterpret_cast<void**>(static_cast<_Pointer*>(*this));
|
||||
}
|
||||
|
||||
private:
|
||||
_Smart& __s_;
|
||||
tuple<_Args...> __a_;
|
||||
_Pointer __p_ = _Pointer();
|
||||
};
|
||||
|
||||
template <class _Pointer = void, class _Smart, class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI auto out_ptr(_Smart& __s, _Args&&... __args) {
|
||||
using _Ptr = conditional_t<is_void_v<_Pointer>, __pointer_of_t<_Smart>, _Pointer>;
|
||||
return std::out_ptr_t<_Smart, _Ptr, _Args&&...>(__s, std::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
#endif // _LIBCPP_STD_VER >= 23
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
_LIBCPP_POP_MACROS
|
||||
|
||||
#endif // _LIBCPP___OUT_PTR_H
|
@ -20,19 +20,28 @@
|
||||
#include <__type_traits/is_void.h>
|
||||
#include <__type_traits/void_t.h>
|
||||
#include <__utility/declval.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <cstddef>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_PUSH_MACROS
|
||||
#include <__undef_macros>
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
template <class _Tp, class = void>
|
||||
struct __has_element_type : false_type {};
|
||||
// clang-format off
|
||||
#define _LIBCPP_CLASS_TRAITS_HAS_XXX(NAME, PROPERTY) \
|
||||
template <class _Tp, class = void> \
|
||||
struct NAME : false_type {}; \
|
||||
template <class _Tp> \
|
||||
struct NAME<_Tp, __void_t<typename _Tp::PROPERTY> > : true_type {}
|
||||
// clang-format on
|
||||
|
||||
template <class _Tp>
|
||||
struct __has_element_type<_Tp, __void_t<typename _Tp::element_type> > : true_type {};
|
||||
_LIBCPP_CLASS_TRAITS_HAS_XXX(__has_pointer, pointer);
|
||||
_LIBCPP_CLASS_TRAITS_HAS_XXX(__has_element_type, element_type);
|
||||
|
||||
template <class _Ptr, bool = __has_element_type<_Ptr>::value>
|
||||
struct __pointer_traits_element_type {};
|
||||
@ -240,6 +249,59 @@ to_address(const _Pointer& __p) noexcept -> decltype(std::__to_address(__p)) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
|
||||
template <class _Tp>
|
||||
struct __pointer_of {};
|
||||
|
||||
template <class _Tp>
|
||||
requires(__has_pointer<_Tp>::value)
|
||||
struct __pointer_of<_Tp> {
|
||||
using type = typename _Tp::pointer;
|
||||
};
|
||||
|
||||
template <class _Tp>
|
||||
requires(!__has_pointer<_Tp>::value && __has_element_type<_Tp>::value)
|
||||
struct __pointer_of<_Tp> {
|
||||
using type = typename _Tp::element_type*;
|
||||
};
|
||||
|
||||
template <class _Tp>
|
||||
requires(!__has_pointer<_Tp>::value && !__has_element_type<_Tp>::value &&
|
||||
__has_element_type<pointer_traits<_Tp>>::value)
|
||||
struct __pointer_of<_Tp> {
|
||||
using type = typename pointer_traits<_Tp>::element_type*;
|
||||
};
|
||||
|
||||
template <typename _Tp>
|
||||
using __pointer_of_t = typename __pointer_of<_Tp>::type;
|
||||
|
||||
template <class _Tp, class _Up>
|
||||
struct __pointer_of_or {
|
||||
using type _LIBCPP_NODEBUG = _Up;
|
||||
};
|
||||
|
||||
template <class _Tp, class _Up>
|
||||
requires requires { typename __pointer_of_t<_Tp>; }
|
||||
struct __pointer_of_or<_Tp, _Up> {
|
||||
using type _LIBCPP_NODEBUG = __pointer_of_t<_Tp>;
|
||||
};
|
||||
|
||||
template <typename _Tp, typename _Up>
|
||||
using __pointer_of_or_t = typename __pointer_of_or<_Tp, _Up>::type;
|
||||
|
||||
template <class _Smart>
|
||||
concept __resettable_smart_pointer = requires(_Smart __s) { __s.reset(); };
|
||||
|
||||
template <class _Smart, class _Pointer, class... _Args>
|
||||
concept __resettable_smart_pointer_with_args = requires(_Smart __s, _Pointer __p, _Args... __args) {
|
||||
__s.reset(static_cast<__pointer_of_or_t<_Smart, _Pointer>>(__p), std::forward<_Args>(__args)...);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
_LIBCPP_POP_MACROS
|
||||
|
||||
#endif // _LIBCPP___MEMORY_POINTER_TRAITS_H
|
||||
|
@ -911,6 +911,22 @@ void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
|
||||
template<size_t N, class T>
|
||||
[[nodiscard]] constexpr T* assume_aligned(T* ptr); // since C++20
|
||||
|
||||
// [out.ptr.t], class template out_ptr_t
|
||||
template<class Smart, class Pointer, class... Args>
|
||||
class out_ptr_t; // since c++23
|
||||
|
||||
// [out.ptr], function template out_ptr
|
||||
template<class Pointer = void, class Smart, class... Args>
|
||||
auto out_ptr(Smart& s, Args&&... args); // since c++23
|
||||
|
||||
// [inout.ptr.t], class template inout_ptr_t
|
||||
template<class Smart, class Pointer, class... Args>
|
||||
class inout_ptr_t; // since c++23
|
||||
|
||||
// [inout.ptr], function template inout_ptr
|
||||
template<class Pointer = void, class Smart, class... Args>
|
||||
auto inout_ptr(Smart& s, Args&&... args); // since c++23
|
||||
|
||||
} // std
|
||||
|
||||
*/
|
||||
@ -924,6 +940,8 @@ template<size_t N, class T>
|
||||
#include <__memory/allocator_arg_t.h>
|
||||
#include <__memory/allocator_traits.h>
|
||||
#include <__memory/auto_ptr.h>
|
||||
#include <__memory/inout_ptr.h>
|
||||
#include <__memory/out_ptr.h>
|
||||
#include <__memory/pointer_traits.h>
|
||||
#include <__memory/raw_storage_iterator.h>
|
||||
#include <__memory/shared_ptr.h>
|
||||
|
@ -1521,6 +1521,8 @@ module std_private_memory_concepts [system] {
|
||||
module std_private_memory_construct_at [system] { header "__memory/construct_at.h" }
|
||||
module std_private_memory_destruct_n [system] { header "__memory/destruct_n.h" }
|
||||
module std_private_memory_fwd [system] { header "__fwd/memory.h" }
|
||||
module std_private_memory_inout_ptr [system] { header "__memory/inout_ptr.h" }
|
||||
module std_private_memory_out_ptr [system] { header "__memory/out_ptr.h" }
|
||||
module std_private_memory_pointer_traits [system] { header "__memory/pointer_traits.h" }
|
||||
module std_private_memory_ranges_construct_at [system] { header "__memory/ranges_construct_at.h" }
|
||||
module std_private_memory_ranges_uninitialized_algorithms [system] {
|
||||
|
@ -477,7 +477,7 @@ __cpp_lib_void_t 201411L <type_traits>
|
||||
// # define __cpp_lib_move_only_function 202110L
|
||||
# undef __cpp_lib_optional
|
||||
# define __cpp_lib_optional 202110L
|
||||
// # define __cpp_lib_out_ptr 202106L
|
||||
# define __cpp_lib_out_ptr 202106L
|
||||
# define __cpp_lib_print 202207L
|
||||
// # define __cpp_lib_ranges_as_const 202207L
|
||||
# define __cpp_lib_ranges_as_rvalue 202207L
|
||||
@ -536,7 +536,7 @@ __cpp_lib_void_t 201411L <type_traits>
|
||||
# define __cpp_lib_mdspan 202406L
|
||||
// # define __cpp_lib_optional_range_support 202406L
|
||||
# undef __cpp_lib_out_ptr
|
||||
// # define __cpp_lib_out_ptr 202311L
|
||||
# define __cpp_lib_out_ptr 202311L
|
||||
// # define __cpp_lib_philox_engine 202406L
|
||||
// # define __cpp_lib_ranges_concat 202403L
|
||||
# define __cpp_lib_ratio 202306L
|
||||
|
@ -177,17 +177,19 @@ export namespace std {
|
||||
// [util.smartptr.atomic], atomic smart pointers
|
||||
// using std::atomic;
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
// [out.ptr.t], class template out_ptr_t
|
||||
// using std::out_ptr_t;
|
||||
using std::out_ptr_t;
|
||||
|
||||
// [out.ptr], function template out_ptr
|
||||
// using std::out_ptr;
|
||||
using std::out_ptr;
|
||||
|
||||
// [inout.ptr.t], class template inout_ptr_t
|
||||
// using std::inout_ptr_t;
|
||||
using std::inout_ptr_t;
|
||||
|
||||
// [inout.ptr], function template inout_ptr
|
||||
// using std::inout_ptr;
|
||||
using std::inout_ptr;
|
||||
#endif // _LIBCPP_STD_VER >= 23
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_THREADS
|
||||
// [depr.util.smartptr.shared.atomic]
|
||||
|
@ -485,17 +485,11 @@
|
||||
# error "__cpp_lib_make_unique should have the value 201304L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_out_ptr
|
||||
# error "__cpp_lib_out_ptr should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_out_ptr != 202106L
|
||||
# error "__cpp_lib_out_ptr should have the value 202106L in c++23"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_out_ptr
|
||||
# error "__cpp_lib_out_ptr should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_out_ptr
|
||||
# error "__cpp_lib_out_ptr should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_out_ptr != 202106L
|
||||
# error "__cpp_lib_out_ptr should have the value 202106L in c++23"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_ranges
|
||||
@ -622,17 +616,11 @@
|
||||
# error "__cpp_lib_make_unique should have the value 201304L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_out_ptr
|
||||
# error "__cpp_lib_out_ptr should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_out_ptr != 202311L
|
||||
# error "__cpp_lib_out_ptr should have the value 202311L in c++26"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_out_ptr
|
||||
# error "__cpp_lib_out_ptr should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_out_ptr
|
||||
# error "__cpp_lib_out_ptr should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_out_ptr != 202311L
|
||||
# error "__cpp_lib_out_ptr should have the value 202311L in c++26"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_ranges
|
||||
|
@ -5542,17 +5542,11 @@
|
||||
# error "__cpp_lib_optional_range_support should not be defined before c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_out_ptr
|
||||
# error "__cpp_lib_out_ptr should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_out_ptr != 202106L
|
||||
# error "__cpp_lib_out_ptr should have the value 202106L in c++23"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_out_ptr
|
||||
# error "__cpp_lib_out_ptr should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_out_ptr
|
||||
# error "__cpp_lib_out_ptr should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_out_ptr != 202106L
|
||||
# error "__cpp_lib_out_ptr should have the value 202106L in c++23"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
@ -7383,17 +7377,11 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_out_ptr
|
||||
# error "__cpp_lib_out_ptr should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_out_ptr != 202311L
|
||||
# error "__cpp_lib_out_ptr should have the value 202311L in c++26"
|
||||
# endif
|
||||
# else // _LIBCPP_VERSION
|
||||
# ifdef __cpp_lib_out_ptr
|
||||
# error "__cpp_lib_out_ptr should not be defined because it is unimplemented in libc++!"
|
||||
# endif
|
||||
# ifndef __cpp_lib_out_ptr
|
||||
# error "__cpp_lib_out_ptr should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_out_ptr != 202311L
|
||||
# error "__cpp_lib_out_ptr should have the value 202311L in c++26"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
|
@ -0,0 +1,206 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <memory>
|
||||
|
||||
// [inout.ptr], function template inout_ptr
|
||||
// template<class Pointer = void, class Smart, class... Args>
|
||||
// auto inout_ptr(Smart& s, Args&&... args); // since c++23
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
// Test updating the ownership of an `inout_ptr_t`-managed pointer for an API with a non-void pointer type.
|
||||
// The API returns a new valid object.
|
||||
void test_replace_int_p() {
|
||||
auto replace_int_p = [](int** pp) {
|
||||
assert(**pp == 90);
|
||||
|
||||
delete *pp;
|
||||
*pp = new int{84};
|
||||
};
|
||||
|
||||
// raw pointer
|
||||
{
|
||||
auto rPtr = new int{90};
|
||||
|
||||
replace_int_p(std::inout_ptr<int*>(rPtr));
|
||||
assert(*rPtr == 84);
|
||||
|
||||
delete rPtr;
|
||||
}
|
||||
|
||||
// std::unique_ptr
|
||||
{
|
||||
auto uPtr = std::make_unique<int>(90);
|
||||
|
||||
replace_int_p(std::inout_ptr(uPtr));
|
||||
assert(*uPtr == 84);
|
||||
}
|
||||
|
||||
{
|
||||
MoveOnlyDeleter<int> del;
|
||||
std::unique_ptr<int, MoveOnlyDeleter<int>> uPtr{new int{90}};
|
||||
|
||||
replace_int_p(std::inout_ptr(uPtr, std::move(del)));
|
||||
assert(*uPtr == 84);
|
||||
assert(uPtr.get_deleter().wasMoveInitilized == true);
|
||||
}
|
||||
|
||||
// pointer-like ConstructiblePtr
|
||||
{
|
||||
ConstructiblePtr<int> cPtr(new int{90});
|
||||
|
||||
replace_int_p(std::inout_ptr(cPtr));
|
||||
assert(cPtr == 84);
|
||||
}
|
||||
|
||||
// pointer-like ResettablePtr
|
||||
{
|
||||
ResettablePtr<int> rPtr(new int{90});
|
||||
|
||||
replace_int_p(std::inout_ptr(rPtr));
|
||||
assert(rPtr == 84);
|
||||
}
|
||||
|
||||
// pointer-like NonConstructiblePtr
|
||||
{
|
||||
NonConstructiblePtr<int> nPtr;
|
||||
nPtr.reset(new int{90});
|
||||
|
||||
replace_int_p(std::inout_ptr(nPtr));
|
||||
assert(nPtr == 84);
|
||||
}
|
||||
}
|
||||
|
||||
// Test updating the ownership of an `inout_ptr_t`-managed pointer for an API with a non-void pointer type.
|
||||
// The API returns `nullptr`.
|
||||
void test_replace_int_p_with_nullptr() {
|
||||
auto replace_int_p_with_nullptr = [](int** pp) -> void {
|
||||
assert(**pp == 90);
|
||||
|
||||
delete *pp;
|
||||
*pp = nullptr;
|
||||
};
|
||||
|
||||
// raw pointer
|
||||
{
|
||||
// LWG-3897 inout_ptr will not update raw pointer to null
|
||||
auto rPtr = new int{90};
|
||||
|
||||
replace_int_p_with_nullptr(std::inout_ptr<int*>(rPtr));
|
||||
assert(rPtr == nullptr);
|
||||
}
|
||||
|
||||
// std::unique_ptr
|
||||
{
|
||||
auto uPtr = std::make_unique<int>(90);
|
||||
|
||||
replace_int_p_with_nullptr(std::inout_ptr(uPtr));
|
||||
assert(uPtr == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Test updating the ownership of an `inout_ptr_t`-managed pointer for an API with a void pointer type.
|
||||
// The API returns a new valid object.
|
||||
void test_replace_int_void_p() {
|
||||
auto replace_int_void_p = [](void** pp) {
|
||||
assert(*(static_cast<int*>(*pp)) == 90);
|
||||
|
||||
delete static_cast<int*>(*pp);
|
||||
*pp = new int{84};
|
||||
};
|
||||
|
||||
// raw pointer
|
||||
{
|
||||
auto rPtr = new int{90};
|
||||
|
||||
replace_int_void_p(std::inout_ptr<int*>(rPtr));
|
||||
assert(*rPtr == 84);
|
||||
|
||||
delete rPtr;
|
||||
}
|
||||
|
||||
// std::unique_ptr
|
||||
{
|
||||
auto uPtr = std::make_unique<int>(90);
|
||||
|
||||
replace_int_void_p(std::inout_ptr(uPtr));
|
||||
assert(*uPtr == 84);
|
||||
}
|
||||
}
|
||||
|
||||
// Test updating the ownership of an `inout_ptr_t`-managed pointer for an API with a non-void pointer type.
|
||||
// The API returns `nullptr`.
|
||||
void test_replace_int_void_p_with_nullptr() {
|
||||
auto replace_int_void_p_with_nullptr = [](void** pp) {
|
||||
assert(*(static_cast<int*>(*pp)) == 90);
|
||||
|
||||
delete static_cast<int*>(*pp);
|
||||
*pp = nullptr;
|
||||
};
|
||||
|
||||
// raw pointer
|
||||
{
|
||||
auto rPtr = new int{90};
|
||||
|
||||
replace_int_void_p_with_nullptr(std::inout_ptr<int*>(rPtr));
|
||||
assert(rPtr == nullptr);
|
||||
}
|
||||
|
||||
// std::unique_ptr
|
||||
{
|
||||
auto uPtr = std::make_unique<int>(90);
|
||||
|
||||
replace_int_void_p_with_nullptr(std::inout_ptr(uPtr));
|
||||
assert(uPtr == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Test updating the ownership of an `inout_ptr_t`-managed pointer for an API with a void pointer type.
|
||||
// The API returns a new valid object.
|
||||
void test_replace_nullptr_with_int_p() {
|
||||
auto replace_nullptr_with_int_p = [](int** pp) {
|
||||
assert(*pp == nullptr);
|
||||
|
||||
*pp = new int{84};
|
||||
};
|
||||
|
||||
// raw pointer
|
||||
{
|
||||
int* rPtr = nullptr;
|
||||
|
||||
replace_nullptr_with_int_p(std::inout_ptr<int*>(rPtr));
|
||||
assert(*rPtr == 84);
|
||||
|
||||
delete rPtr;
|
||||
}
|
||||
|
||||
// std::unique_ptr
|
||||
{
|
||||
std::unique_ptr<int> uPtr;
|
||||
|
||||
replace_nullptr_with_int_p(std::inout_ptr(uPtr));
|
||||
assert(*uPtr == 84);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test_replace_int_p();
|
||||
test_replace_int_p_with_nullptr();
|
||||
test_replace_int_void_p();
|
||||
test_replace_int_void_p_with_nullptr();
|
||||
test_replace_nullptr_with_int_p();
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <memory>
|
||||
|
||||
// [inout.ptr], function template inout_ptr
|
||||
// template<class Pointer = void, class Smart, class... Args>
|
||||
// auto inout_ptr(Smart& s, Args&&... args); // since c++23
|
||||
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
int main(int, char**) {
|
||||
// `std::inout_ptr<>` does not support `std::shared_ptr<>`.
|
||||
{
|
||||
std::shared_ptr<int> sPtr;
|
||||
|
||||
// expected-error-re@*:* {{static assertion failed due to requirement {{.*}}std::shared_ptr<> is not supported}}
|
||||
std::ignore = std::inout_ptr(sPtr);
|
||||
// expected-error@*:* {{no matching conversion for functional-style cast from 'std::shared_ptr<int>' to 'std::inout_ptr_t<shared_ptr<int>, _Ptr>' (aka 'inout_ptr_t<std::shared_ptr<int>, int *>'}}
|
||||
std::ignore = std::inout_ptr<int*>(sPtr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <memory>
|
||||
|
||||
// [inout.ptr.t], class template inout_ptr_t
|
||||
// template<class Smart, class Pointer, class... Args>
|
||||
// class inout_ptr_t; // since c++23
|
||||
|
||||
// operator Pointer*() const noexcept;
|
||||
// operator void**() const noexcept;
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <memory>
|
||||
|
||||
int main(int, char**) {
|
||||
// operator Pointer*()
|
||||
{
|
||||
std::unique_ptr<int> uPtr = std::make_unique<int>(84);
|
||||
|
||||
const std::inout_ptr_t<std::unique_ptr<int>, int*> ioPtr{uPtr};
|
||||
|
||||
static_assert(noexcept(ioPtr.operator int**()));
|
||||
std::same_as<int**> decltype(auto) pPtr = ioPtr.operator int**();
|
||||
|
||||
assert(**pPtr == 84);
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_ptr<int, std::default_delete<int>> uPtr = std::make_unique<int>(84);
|
||||
|
||||
const std::inout_ptr_t<decltype(uPtr), int*, std::default_delete<int>> ioPtr{uPtr, std::default_delete<int>{}};
|
||||
|
||||
static_assert(noexcept(ioPtr.operator int**()));
|
||||
std::same_as<int**> decltype(auto) pPtr = ioPtr.operator int**();
|
||||
|
||||
assert(**pPtr == 84);
|
||||
}
|
||||
|
||||
// operator void**()
|
||||
{
|
||||
std::unique_ptr<int> uPtr = std::make_unique<int>(84);
|
||||
|
||||
const std::inout_ptr_t<std::unique_ptr<int>, void*> ioPtr{uPtr};
|
||||
|
||||
static_assert(noexcept(ioPtr.operator void**()));
|
||||
std::same_as<void**> decltype(auto) pPtr = ioPtr.operator void**();
|
||||
|
||||
assert(**reinterpret_cast<int**>(pPtr) == 84);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <memory>
|
||||
|
||||
// [inout.ptr.t], class template inout_ptr_t
|
||||
// template<class Smart, class Pointer, class... Args>
|
||||
// class inout_ptr_t; // since c++23
|
||||
|
||||
// explicit inout_ptr_t(Smart&, Args...);
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include "test_convertible.h"
|
||||
#include "../types.h"
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
std::unique_ptr<int> uPtr;
|
||||
|
||||
std::inout_ptr_t<std::unique_ptr<int>, int*>{uPtr};
|
||||
|
||||
static_assert(
|
||||
!test_convertible<std::inout_ptr_t<std::unique_ptr<int>, int*>>(), "This constructor must be explicit");
|
||||
|
||||
// Test the state of the pointer after construction. Complete tests are available in inout_ptr.general.pass.cpp.
|
||||
assert(uPtr == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
auto deleter = [](auto* p) { delete p; };
|
||||
std::unique_ptr<int, decltype(deleter)> uPtr;
|
||||
|
||||
std::inout_ptr_t<std::unique_ptr<int, decltype(deleter)>, int*>{uPtr};
|
||||
|
||||
static_assert(!test_convertible<std::inout_ptr_t<std::unique_ptr<int, decltype(deleter)>, int*>>(),
|
||||
"This constructor must be explicit");
|
||||
|
||||
// Test the state of the pointer after construction. Complete tests are available in inout_ptr.general.pass.cpp.
|
||||
assert(uPtr == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_ptr<int, MoveOnlyDeleter<int>> uPtr;
|
||||
|
||||
std::inout_ptr_t<decltype(uPtr), int*, MoveOnlyDeleter<int>>{uPtr, MoveOnlyDeleter<int>{}};
|
||||
|
||||
// Test the state of the pointer after construction. Complete tests are available in inout_ptr.general.pass.cpp.
|
||||
assert(uPtr == nullptr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <memory>
|
||||
|
||||
// [inout.ptr.t], class template inout_ptr_t
|
||||
// template<class Smart, class Pointer, class... Args>
|
||||
// class inout_ptr_t; // since c++23
|
||||
|
||||
#include <memory>
|
||||
|
||||
int main(int, char**) {
|
||||
// `std::inout_ptr<>` does not support `std::shared_ptr<>`.
|
||||
{
|
||||
std::shared_ptr<int> sPtr;
|
||||
|
||||
// expected-error-re@*:* {{static assertion failed due to requirement {{.*}}std::shared_ptr<> is not supported with std::inout_ptr.}}
|
||||
std::inout_ptr_t<std::shared_ptr<int>, int*>{sPtr};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,230 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <memory>
|
||||
|
||||
// [out.ptr], function template out_ptr
|
||||
// template<class Pointer = void, class Smart, class... Args>
|
||||
// auto out_ptr(Smart& s, Args&&... args); // since c++23
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
// Test updating an `out_ptr_t`-managed pointer for an API with a non-void pointer type.
|
||||
// The API returns a new valid object.
|
||||
void test_get_int_p() {
|
||||
auto get_int_p = [](int** pp) { *pp = new int{84}; };
|
||||
|
||||
// raw pointer
|
||||
{
|
||||
int* rPtr;
|
||||
|
||||
get_int_p(std::out_ptr<int*>(rPtr));
|
||||
assert(*rPtr == 84);
|
||||
|
||||
delete rPtr;
|
||||
}
|
||||
|
||||
// std::unique_ptr
|
||||
{
|
||||
std::unique_ptr<int> uPtr;
|
||||
|
||||
get_int_p(std::out_ptr(uPtr));
|
||||
assert(*uPtr == 84);
|
||||
}
|
||||
|
||||
{
|
||||
MoveOnlyDeleter<int> del;
|
||||
std::unique_ptr<int, MoveOnlyDeleter<int>> uPtr;
|
||||
|
||||
get_int_p(std::out_ptr(uPtr, std::move(del)));
|
||||
assert(*uPtr == 84);
|
||||
assert(uPtr.get_deleter().wasMoveInitilized == true);
|
||||
}
|
||||
|
||||
// std::shared_ptr
|
||||
{
|
||||
std::shared_ptr<int> sPtr;
|
||||
|
||||
get_int_p(std::out_ptr(sPtr, [](auto* p) {
|
||||
assert(*p == 84);
|
||||
|
||||
delete p;
|
||||
}));
|
||||
assert(*sPtr == 84);
|
||||
}
|
||||
|
||||
// pointer-like ConstructiblePtr
|
||||
{
|
||||
ConstructiblePtr<int> cPtr;
|
||||
|
||||
get_int_p(std::out_ptr(cPtr));
|
||||
assert(cPtr == 84);
|
||||
}
|
||||
|
||||
// pointer-like ResettablePtr
|
||||
{
|
||||
ResettablePtr<int> rPtr{nullptr};
|
||||
|
||||
get_int_p(std::out_ptr(rPtr));
|
||||
assert(rPtr == 84);
|
||||
}
|
||||
|
||||
// NonConstructiblePtr
|
||||
{
|
||||
NonConstructiblePtr<int> nPtr;
|
||||
|
||||
get_int_p(std::out_ptr(nPtr));
|
||||
assert(nPtr == 84);
|
||||
}
|
||||
}
|
||||
|
||||
// Test updating an `out_ptr_t`-managed pointer for an API with a non-void pointer type.
|
||||
// The API returns `nullptr`.
|
||||
void test_get_int_p_nullptr() {
|
||||
auto get_int_p_nullptr = [](int** pp) { *pp = nullptr; };
|
||||
// raw pointer
|
||||
{
|
||||
int* rPtr;
|
||||
|
||||
get_int_p_nullptr(std::out_ptr<int*>(rPtr));
|
||||
assert(rPtr == nullptr);
|
||||
|
||||
delete rPtr;
|
||||
}
|
||||
|
||||
// std::unique_ptr
|
||||
{
|
||||
std::unique_ptr<int> uPtr;
|
||||
|
||||
get_int_p_nullptr(std::out_ptr(uPtr));
|
||||
assert(uPtr == nullptr);
|
||||
}
|
||||
|
||||
// std::shared_ptr
|
||||
{
|
||||
std::shared_ptr<int> sPtr;
|
||||
|
||||
get_int_p_nullptr(std::out_ptr(sPtr, [](auto* p) {
|
||||
assert(p == nullptr);
|
||||
|
||||
delete p;
|
||||
}));
|
||||
assert(sPtr == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Test updating an `out_ptr_t`-managed pointer for an API with a void pointer type.
|
||||
// The API returns a new valid object.
|
||||
void test_get_int_void_p() {
|
||||
auto get_int_void_p = [](void** pp) { *(reinterpret_cast<int**>(pp)) = new int{84}; };
|
||||
|
||||
// raw pointer
|
||||
{
|
||||
int* rPtr;
|
||||
|
||||
get_int_void_p(std::out_ptr(rPtr));
|
||||
assert(*rPtr == 84);
|
||||
|
||||
delete rPtr;
|
||||
}
|
||||
|
||||
// std::unique_ptr
|
||||
{
|
||||
std::unique_ptr<int> uPtr;
|
||||
|
||||
get_int_void_p(std::out_ptr(uPtr));
|
||||
assert(*uPtr == 84);
|
||||
}
|
||||
|
||||
// std::shared_ptr
|
||||
{
|
||||
std::shared_ptr<int> sPtr;
|
||||
|
||||
get_int_void_p(std::out_ptr(sPtr, [](auto* p) {
|
||||
assert(*p == 84);
|
||||
|
||||
delete p;
|
||||
}));
|
||||
assert(*sPtr == 84);
|
||||
}
|
||||
|
||||
// pointer-like ConstructiblePtr
|
||||
{
|
||||
ConstructiblePtr<int> cPtr;
|
||||
|
||||
get_int_void_p(std::out_ptr(cPtr));
|
||||
assert(cPtr == 84);
|
||||
}
|
||||
|
||||
// pointer-like ResettablePtr
|
||||
{
|
||||
ResettablePtr<int> rPtr{nullptr};
|
||||
|
||||
get_int_void_p(std::out_ptr(rPtr));
|
||||
assert(rPtr == 84);
|
||||
}
|
||||
|
||||
// NonConstructiblePtr
|
||||
{
|
||||
NonConstructiblePtr<int> nPtr;
|
||||
|
||||
get_int_void_p(std::out_ptr(nPtr));
|
||||
assert(nPtr == 84);
|
||||
}
|
||||
}
|
||||
|
||||
// Test updating an `out_ptr_t`-managed pointer for an API with a void pointer type.
|
||||
// The API returns `nullptr`.
|
||||
void test_get_int_void_p_nullptr() {
|
||||
auto get_int_void_p_nullptr = [](void** pp) { *pp = nullptr; };
|
||||
|
||||
// raw pointer
|
||||
{
|
||||
int* rPtr;
|
||||
|
||||
get_int_void_p_nullptr(std::out_ptr<int*>(rPtr));
|
||||
assert(rPtr == nullptr);
|
||||
|
||||
delete rPtr;
|
||||
}
|
||||
|
||||
// std::unique_ptr
|
||||
{
|
||||
std::unique_ptr<int> uPtr;
|
||||
|
||||
get_int_void_p_nullptr(std::out_ptr(uPtr));
|
||||
assert(uPtr == nullptr);
|
||||
}
|
||||
|
||||
// std::shared_ptr
|
||||
{
|
||||
std::shared_ptr<int> sPtr;
|
||||
|
||||
get_int_void_p_nullptr(std::out_ptr(sPtr, [](auto* p) {
|
||||
assert(p == nullptr);
|
||||
|
||||
delete p;
|
||||
}));
|
||||
assert(sPtr == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test_get_int_p();
|
||||
test_get_int_p_nullptr();
|
||||
test_get_int_void_p();
|
||||
test_get_int_void_p_nullptr();
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <memory>
|
||||
|
||||
// [out.ptr], function template out_ptr
|
||||
// template<class Pointer = void, class Smart, class... Args>
|
||||
// auto out_ptr(Smart& s, Args&&... args); // since c++23
|
||||
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
int main(int, char**) {
|
||||
// `std::out_ptr<>` requires `std::shared_ptr<>` with a deleter.
|
||||
{
|
||||
std::shared_ptr<int> sPtr;
|
||||
|
||||
// expected-error-re@*:* {{static assertion failed due to requirement {{.*}}Using std::shared_ptr<> without a deleter in std::out_ptr is not supported.}}
|
||||
std::ignore = std::out_ptr(sPtr);
|
||||
// expected-error@*:* {{no matching conversion for functional-style cast from 'std::shared_ptr<int>' to 'std::out_ptr_t<shared_ptr<int>, _Ptr>' (aka 'out_ptr_t<std::shared_ptr<int>, int *>')}}
|
||||
std::ignore = std::out_ptr<int*>(sPtr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <memory>
|
||||
|
||||
// [out.ptr.t], class template out_ptr_t
|
||||
// template<class Smart, class Pointer, class... Args>
|
||||
// class out_ptr_t; // since c++23
|
||||
|
||||
// operator Pointer*() const noexcept;
|
||||
// operator void**() const noexcept;
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <memory>
|
||||
|
||||
int main(int, char**) {
|
||||
// operator Pointer*()
|
||||
{
|
||||
std::unique_ptr<int> uPtr;
|
||||
|
||||
const std::out_ptr_t<std::unique_ptr<int>, int*> oPtr{uPtr};
|
||||
|
||||
static_assert(noexcept(oPtr.operator int**()));
|
||||
std::same_as<int**> decltype(auto) pPtr = oPtr.operator int**();
|
||||
|
||||
assert(*pPtr == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_ptr<int, std::default_delete<int>> uPtr;
|
||||
|
||||
const std::out_ptr_t<decltype(uPtr), int*, std::default_delete<int>> oPtr{uPtr, std::default_delete<int>{}};
|
||||
|
||||
static_assert(noexcept(oPtr.operator int**()));
|
||||
std::same_as<int**> decltype(auto) pPtr = oPtr.operator int**();
|
||||
|
||||
assert(*pPtr == nullptr);
|
||||
}
|
||||
|
||||
// operator void**()
|
||||
{
|
||||
std::unique_ptr<int> uPtr;
|
||||
|
||||
const std::out_ptr_t<std::unique_ptr<int>, void*> oPtr{uPtr};
|
||||
|
||||
static_assert(noexcept(oPtr.operator void**()));
|
||||
std::same_as<void**> decltype(auto) pPtr = oPtr.operator void**();
|
||||
|
||||
assert(*pPtr == nullptr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <memory>
|
||||
|
||||
// [out.ptr.t], class template out_ptr_t
|
||||
// template<class Smart, class Pointer, class... Args>
|
||||
// class out_ptr_t; // since c++23
|
||||
|
||||
// explicit out_ptr_t(Smart&, Args...);
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include "test_convertible.h"
|
||||
#include "../types.h"
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
std::unique_ptr<int> uPtr;
|
||||
|
||||
std::out_ptr_t<std::unique_ptr<int>, int*>{uPtr};
|
||||
|
||||
static_assert(!test_convertible<std::out_ptr_t<std::unique_ptr<int>, int*>>(), "This constructor must be explicit");
|
||||
|
||||
// Test the state of the pointer after construction. Complete tests are available in out_ptr.general.pass.cpp
|
||||
assert(uPtr == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_ptr<int, std::default_delete<int>> uPtr;
|
||||
|
||||
std::out_ptr_t<decltype(uPtr), int*, std::default_delete<int>>{uPtr, std::default_delete<int>{}};
|
||||
|
||||
static_assert(!test_convertible<std::out_ptr_t<decltype(uPtr), int*, std::default_delete<int>>>(),
|
||||
"This constructor must be explicit");
|
||||
|
||||
// Test the state of the pointer after construction. Complete tests are available in out_ptr.general.pass.cpp
|
||||
assert(uPtr == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_ptr<int, MoveOnlyDeleter<int>> uPtr;
|
||||
|
||||
std::out_ptr_t<decltype(uPtr), int*, MoveOnlyDeleter<int>>{uPtr, MoveOnlyDeleter<int>{}};
|
||||
|
||||
// Test the state of the pointer after construction. Complete tests are available in out_ptr.general.pass.cpp
|
||||
assert(uPtr == nullptr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// <memory>
|
||||
|
||||
// [out.ptr.t], class template out_ptr_t
|
||||
// template<class Smart, class Pointer, class... Args>
|
||||
// class out_ptr_t; // since c++23
|
||||
|
||||
#include <memory>
|
||||
|
||||
int main(int, char**) {
|
||||
// `std::out_ptr_t<>` requires `std::shared_ptr<>` with a deleter.
|
||||
{
|
||||
std::shared_ptr<int> sPtr;
|
||||
|
||||
// expected-error-re@*:* {{static assertion failed due to requirement {{.*}}Using std::shared_ptr<> without a deleter in std::out_ptr is not supported.}}
|
||||
std::out_ptr_t<std::shared_ptr<int>, int*>{sPtr};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
86
libcxx/test/std/utilities/smartptr/adapt/types.h
Normal file
86
libcxx/test/std/utilities/smartptr/adapt/types.h
Normal file
@ -0,0 +1,86 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 TEST_LIBCXX_UTILITIES_SMARTPTR_ADAPT_TYPES_H
|
||||
#define TEST_LIBCXX_UTILITIES_SMARTPTR_ADAPT_TYPES_H
|
||||
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
// Custom deleters.
|
||||
|
||||
template <typename T>
|
||||
struct MoveOnlyDeleter {
|
||||
MoveOnlyDeleter() = default;
|
||||
MoveOnlyDeleter(const MoveOnlyDeleter&) = delete;
|
||||
MoveOnlyDeleter& operator=(const MoveOnlyDeleter&) = delete;
|
||||
MoveOnlyDeleter(MoveOnlyDeleter&&) : wasMoveInitilized{true} {}
|
||||
MoveOnlyDeleter& operator=(MoveOnlyDeleter&&) = default;
|
||||
|
||||
void operator()(T* p) const { delete p; }
|
||||
|
||||
bool wasMoveInitilized = false;
|
||||
};
|
||||
|
||||
// Custom pointer types.
|
||||
|
||||
template <typename T>
|
||||
struct ConstructiblePtr {
|
||||
using pointer = T*;
|
||||
std::unique_ptr<T> ptr;
|
||||
|
||||
ConstructiblePtr() = default;
|
||||
explicit ConstructiblePtr(T* p) : ptr{p} {}
|
||||
|
||||
auto operator==(T val) { return *ptr == val; }
|
||||
|
||||
auto* get() const { return ptr.get(); }
|
||||
|
||||
void release() { ptr.release(); }
|
||||
};
|
||||
|
||||
LIBCPP_STATIC_ASSERT(std::is_same_v<std::__pointer_of_t< ConstructiblePtr<int>>, int* >);
|
||||
static_assert(std::is_constructible_v< ConstructiblePtr<int>, int* >);
|
||||
|
||||
struct ResetArg {};
|
||||
|
||||
template <typename T>
|
||||
struct ResettablePtr {
|
||||
using element_type = T;
|
||||
std::unique_ptr<T> ptr;
|
||||
|
||||
explicit ResettablePtr(T* p) : ptr{p} {}
|
||||
|
||||
auto operator*() const { return *ptr; }
|
||||
|
||||
auto operator==(T val) { return *ptr == val; }
|
||||
|
||||
void reset() { ptr.reset(); }
|
||||
void reset(T* p, ResetArg) { ptr.reset(p); }
|
||||
|
||||
auto* get() const { return ptr.get(); }
|
||||
|
||||
void release() { ptr.release(); }
|
||||
};
|
||||
|
||||
LIBCPP_STATIC_ASSERT(std::is_same_v<std::__pointer_of_t< ResettablePtr<int>>, int* >);
|
||||
static_assert(std::is_constructible_v< ResettablePtr<int>, int* >);
|
||||
|
||||
template <typename T>
|
||||
struct NonConstructiblePtr : public ResettablePtr<T> {
|
||||
NonConstructiblePtr() : NonConstructiblePtr::ResettablePtr(nullptr) {};
|
||||
|
||||
void reset(T* p) { ResettablePtr<T>::ptr.reset(p); }
|
||||
};
|
||||
|
||||
LIBCPP_STATIC_ASSERT(std::is_same_v<std::__pointer_of_t< NonConstructiblePtr<int>>, int* >);
|
||||
static_assert(!std::is_constructible_v< NonConstructiblePtr<int>, int* >);
|
||||
|
||||
#endif // TEST_LIBCXX_UTILITIES_SMARTPTR_ADAPT_TYPES_H
|
@ -949,7 +949,6 @@ feature_test_macros = [
|
||||
"c++26": 202311, # P2833R2 Freestanding Library: inout expected span
|
||||
},
|
||||
"headers": ["memory"],
|
||||
"unimplemented": True,
|
||||
},
|
||||
{
|
||||
"name": "__cpp_lib_parallel_algorithm",
|
||||
|
Loading…
x
Reference in New Issue
Block a user