Skip to content

Commit 84770c8

Browse files
committed
[libc++][memory] P1132R8: out_ptr - a scalable output pointer abstraction
Differential Revision: https://reviews.llvm.org/D150525
1 parent 511ba45 commit 84770c8

26 files changed

+999
-37
lines changed

libcxx/docs/FeatureTestMacroTable.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ Status
342342
--------------------------------------------------- -----------------
343343
``__cpp_lib_optional`` ``202110L``
344344
--------------------------------------------------- -----------------
345-
``__cpp_lib_out_ptr`` *unimplemented*
345+
``__cpp_lib_out_ptr`` ``202106L``
346346
--------------------------------------------------- -----------------
347347
``__cpp_lib_print`` *unimplemented*
348348
--------------------------------------------------- -----------------

libcxx/docs/Status/Cxx23Issues.csv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@
192192
"`3515 <https://wg21.link/LWG3515>`__","§[stacktrace.basic.nonmem]: ``operator<<`` should be less templatized", "November 2022","","",""
193193
"`3545 <https://wg21.link/LWG3545>`__","``std::pointer_traits`` should be SFINAE-friendly", "November 2022","|Complete|","18.0",""
194194
"`3569 <https://wg21.link/LWG3569>`__","``join_view`` fails to support ranges of ranges with non-default_initializable iterators", "November 2022","","","|ranges|"
195-
"`3594 <https://wg21.link/LWG3594>`__","``inout_ptr`` — inconsistent ``release()`` in destructor", "November 2022","","",""
195+
"`3594 <https://wg21.link/LWG3594>`__","``inout_ptr`` — inconsistent ``release()`` in destructor", "November 2022","|Complete|","17.0",""
196196
"`3597 <https://wg21.link/LWG3597>`__","Unsigned integer types don't model advanceable", "November 2022","","","|ranges|"
197197
"`3600 <https://wg21.link/LWG3600>`__","Making ``istream_iterator`` copy constructor trivial is an ABI break", "November 2022","","",""
198198
"`3629 <https://wg21.link/LWG3629>`__","``make_error_code`` and ``make_error_condition`` are customization points","November 2022","|Complete|","16.0",""
@@ -282,7 +282,7 @@
282282
"`3645 <https://wg21.link/LWG3645>`__","``resize_and_overwrite`` is overspecified to call its callback with lvalues","February 2023","|Complete|","14.0",""
283283
"`3655 <https://wg21.link/LWG3655>`__","The ``INVOKE`` operation and union types","February 2023","|Complete|","18.0",""
284284
"`3723 <https://wg21.link/LWG3723>`__","``priority_queue::push_range`` needs to ``append_range``","February 2023","","","|ranges|"
285-
"`3734 <https://wg21.link/LWG3734>`__","Inconsistency in ``inout_ptr`` and ``out_ptr`` for empty case","February 2023","","",""
285+
"`3734 <https://wg21.link/LWG3734>`__","Inconsistency in ``inout_ptr`` and ``out_ptr`` for empty case","February 2023","|Complete|","17.0",""
286286
"`3772 <https://wg21.link/LWG3772>`__","``repeat_view``'s ``piecewise`` constructor is missing Postconditions","February 2023","","","|ranges|"
287287
"`3786 <https://wg21.link/LWG3786>`__","Flat maps' deduction guide needs to default ``Allocator`` to be useful","February 2023","","",""
288288
"`3803 <https://wg21.link/LWG3803>`__","``flat_foo`` constructors taking ``KeyContainer`` lack ``KeyCompare`` parameter","February 2023","","",""

libcxx/docs/Status/Cxx23Papers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"","","","","","",""
1414
"`P0401R6 <https://wg21.link/P0401R6>`__","LWG","Providing size feedback in the Allocator interface","June 2021","|Complete|","15.0"
1515
"`P0448R4 <https://wg21.link/P0448R4>`__","LWG","A strstream replacement using span<charT> as buffer","June 2021","",""
16-
"`P1132R8 <https://wg21.link/P1132R8>`__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","",""
16+
"`P1132R8 <https://wg21.link/P1132R8>`__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","|Complete|","17.0"
1717
"`P1328R1 <https://wg21.link/P1328R1>`__","LWG","Making std::type_info::operator== constexpr","June 2021","|Complete|","17.0"
1818
"`P1425R4 <https://wg21.link/P1425R4>`__","LWG","Iterators pair constructors for stack and queue","June 2021","|Complete|","14.0","|ranges|"
1919
"`P1518R2 <https://wg21.link/P1518R2>`__","LWG","Stop overconstraining allocators in container deduction guides","June 2021","|Complete|","13.0"

libcxx/include/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,8 @@ set(files
529529
__memory/concepts.h
530530
__memory/construct_at.h
531531
__memory/destruct_n.h
532+
__memory/inout_ptr.h
533+
__memory/out_ptr.h
532534
__memory/pointer_traits.h
533535
__memory/ranges_construct_at.h
534536
__memory/ranges_uninitialized_algorithms.h

libcxx/include/__memory/allocator_traits.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
3838
template <class _Tp> struct NAME<_Tp, __void_t<typename _Tp:: PROPERTY > > : true_type { }
3939

4040
// __pointer
41-
_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_pointer, pointer);
4241
template <class _Tp, class _Alloc,
4342
class _RawAlloc = __libcpp_remove_reference_t<_Alloc>,
4443
bool = __has_pointer<_RawAlloc>::value>

libcxx/include/__memory/inout_ptr.h

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef _LIBCPP___INOUT_PTR_H
11+
#define _LIBCPP___INOUT_PTR_H
12+
13+
#include <__config>
14+
#include <__memory/addressof.h>
15+
#include <__memory/pointer_traits.h>
16+
#include <__memory/shared_ptr.h>
17+
#include <__memory/unique_ptr.h>
18+
#include <__type_traits/is_same.h>
19+
#include <__type_traits/is_specialization.h>
20+
#include <__type_traits/is_void.h>
21+
#include <tuple>
22+
23+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
24+
# pragma GCC system_header
25+
#endif
26+
27+
_LIBCPP_BEGIN_NAMESPACE_STD
28+
29+
#if _LIBCPP_STD_VER >= 23
30+
31+
template <class _Smart, class _Pointer, class... _Args>
32+
class _LIBCPP_TEMPLATE_VIS inout_ptr_t {
33+
static_assert(!__is_specialization_v<_Smart, shared_ptr>, "std::shared_ptr<> is not supported");
34+
35+
public:
36+
_LIBCPP_HIDE_FROM_ABI explicit inout_ptr_t(_Smart& __s, _Args... __args)
37+
: __s_(__s), __a_(std::forward<_Args>(__args)...), __p_([&__s] {
38+
if constexpr (is_pointer_v<_Smart>) {
39+
return __s;
40+
} else {
41+
return __s.get();
42+
}
43+
}()) {
44+
if constexpr (requires { __s.release(); }) {
45+
__s.release();
46+
} else {
47+
__s = _Smart();
48+
}
49+
}
50+
51+
_LIBCPP_HIDE_FROM_ABI inout_ptr_t(const inout_ptr_t&) = delete;
52+
53+
_LIBCPP_HIDE_FROM_ABI ~inout_ptr_t() {
54+
if (!__p_) {
55+
return;
56+
}
57+
58+
using _SP = __pointer_of_or_t<_Smart, _Pointer>;
59+
if constexpr (is_pointer_v<_Smart>) {
60+
std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
61+
std::move(__a_));
62+
} else if constexpr (__resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...>) {
63+
std::apply([&](auto&&... __args) { __s_.reset(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
64+
std::move(__a_));
65+
} else if constexpr (is_constructible_v<_Smart, _SP, _Args...>) {
66+
std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
67+
std::move(__a_));
68+
} else {
69+
static_assert(is_pointer_v<_Smart> || __resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...> ||
70+
is_constructible_v<_Smart, _SP, _Args...>);
71+
}
72+
}
73+
74+
_LIBCPP_HIDE_FROM_ABI operator _Pointer*() const noexcept { return std::addressof(const_cast<_Pointer&>(__p_)); }
75+
76+
_LIBCPP_HIDE_FROM_ABI operator void**() const noexcept
77+
requires(!is_same_v<_Pointer, void*>)
78+
{
79+
static_assert(is_pointer_v<_Pointer>);
80+
81+
return reinterpret_cast<void**>(static_cast<_Pointer*>(*this));
82+
}
83+
84+
private:
85+
_Smart& __s_;
86+
tuple<_Args...> __a_;
87+
_Pointer __p_;
88+
};
89+
90+
template <class _Pointer = void, class _Smart, class... _Args>
91+
_LIBCPP_HIDE_FROM_ABI auto inout_ptr(_Smart& __s, _Args&&... __args) {
92+
using _Ptr = conditional_t<is_void_v<_Pointer>, __pointer_of_t<_Smart>, _Pointer>;
93+
return std::inout_ptr_t<_Smart, _Ptr, _Args&&...>{__s, std::forward<_Args>(__args)...};
94+
}
95+
96+
#endif // _LIBCPP_STD_VER >= 23
97+
98+
_LIBCPP_END_NAMESPACE_STD
99+
100+
#endif // _LIBCPP___INOUT_PTR_H

libcxx/include/__memory/out_ptr.h

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef _LIBCPP___OUT_PTR_H
11+
#define _LIBCPP___OUT_PTR_H
12+
13+
#include <__config>
14+
#include <__memory/addressof.h>
15+
#include <__memory/pointer_traits.h>
16+
#include <__memory/shared_ptr.h>
17+
#include <__memory/unique_ptr.h>
18+
#include <__type_traits/is_specialization.h>
19+
#include <__type_traits/is_void.h>
20+
#include <tuple>
21+
22+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
23+
# pragma GCC system_header
24+
#endif
25+
26+
_LIBCPP_BEGIN_NAMESPACE_STD
27+
28+
#if _LIBCPP_STD_VER >= 23
29+
30+
template <class _Tp>
31+
concept __resettable_adapted_ptr = requires(_Tp __ptr) { __ptr().reset(); };
32+
33+
template <class _Smart, class _Pointer, class... _Args>
34+
class _LIBCPP_TEMPLATE_VIS out_ptr_t {
35+
static_assert(!__is_specialization_v<_Smart, shared_ptr> || sizeof...(_Args) > 0,
36+
"Specialization of std::shared_ptr<> requires a deleter.");
37+
38+
public:
39+
_LIBCPP_HIDE_FROM_ABI explicit out_ptr_t(_Smart& __s, _Args... __args)
40+
: __s_(__s), __a_(std::forward<_Args>(__args)...), __p_() {
41+
using _Ptr = decltype(__s);
42+
if constexpr (__resettable_smart_pointer<_Ptr>) {
43+
__s_.reset();
44+
} else if constexpr (is_constructible_v<_Smart>) {
45+
__s_ = _Smart();
46+
} else {
47+
static_assert(__resettable_smart_pointer<_Ptr> || is_constructible_v<_Smart>);
48+
}
49+
}
50+
51+
_LIBCPP_HIDE_FROM_ABI out_ptr_t(const out_ptr_t&) = delete;
52+
53+
_LIBCPP_HIDE_FROM_ABI ~out_ptr_t() {
54+
if (!__p_) {
55+
return;
56+
}
57+
58+
using _SP = __pointer_of_or_t<_Smart, _Pointer>;
59+
if constexpr (__resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...>) {
60+
std::apply([&](auto&&... __args) { __s_.reset(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
61+
std::move(__a_));
62+
} else if constexpr (is_constructible_v<_Smart, _SP, _Args...>) {
63+
std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
64+
std::move(__a_));
65+
} else {
66+
static_assert(__resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...> ||
67+
is_constructible_v<_Smart, _SP, _Args...>);
68+
}
69+
}
70+
71+
_LIBCPP_HIDE_FROM_ABI operator _Pointer*() const noexcept { return std::addressof(const_cast<_Pointer&>(__p_)); }
72+
73+
_LIBCPP_HIDE_FROM_ABI operator void**() const noexcept
74+
requires(!is_same_v<_Pointer, void*>)
75+
{
76+
static_assert(is_pointer_v<_Pointer>);
77+
78+
return reinterpret_cast<void**>(static_cast<_Pointer*>(*this));
79+
}
80+
81+
private:
82+
_Smart& __s_;
83+
tuple<_Args...> __a_;
84+
_Pointer __p_ = _Pointer();
85+
};
86+
87+
template <class _Pointer = void, class _Smart, class... _Args>
88+
_LIBCPP_HIDE_FROM_ABI auto out_ptr(_Smart& __s, _Args&&... __args) {
89+
using _Ptr = conditional_t<is_void_v<_Pointer>, __pointer_of_t<_Smart>, _Pointer>;
90+
return std::out_ptr_t<_Smart, _Ptr, _Args&&...>{__s, std::forward<_Args>(__args)...};
91+
}
92+
93+
#endif // _LIBCPP_STD_VER >= 23
94+
95+
_LIBCPP_END_NAMESPACE_STD
96+
97+
#endif // _LIBCPP___OUT_PTR_H

libcxx/include/__memory/pointer_traits.h

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@
1515
#include <__type_traits/conditional.h>
1616
#include <__type_traits/conjunction.h>
1717
#include <__type_traits/decay.h>
18+
#include <__type_traits/enable_if.h>
1819
#include <__type_traits/is_class.h>
1920
#include <__type_traits/is_function.h>
2021
#include <__type_traits/is_void.h>
22+
#include <__type_traits/negation.h>
2123
#include <__type_traits/void_t.h>
2224
#include <__utility/declval.h>
25+
#include <__utility/forward.h>
2326
#include <cstddef>
2427

2528
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -28,11 +31,16 @@
2831

2932
_LIBCPP_BEGIN_NAMESPACE_STD
3033

31-
template <class _Tp, class = void>
32-
struct __has_element_type : false_type {};
34+
// clang-format off
35+
#define _LIBCPP_CLASS_TRAITS_HAS_XXX(NAME, PROPERTY) \
36+
template <class _Tp, class = void> \
37+
struct NAME : false_type {}; \
38+
template <class _Tp> \
39+
struct NAME<_Tp, __void_t<typename _Tp::PROPERTY> > : true_type {}
40+
// clang-format on
3341

34-
template <class _Tp>
35-
struct __has_element_type<_Tp, __void_t<typename _Tp::element_type> > : true_type {};
42+
_LIBCPP_CLASS_TRAITS_HAS_XXX(__has_pointer, pointer);
43+
_LIBCPP_CLASS_TRAITS_HAS_XXX(__has_element_type, element_type);
3644

3745
template <class _Ptr, bool = __has_element_type<_Ptr>::value>
3846
struct __pointer_traits_element_type {};
@@ -242,6 +250,57 @@ auto to_address(const _Pointer& __p) noexcept -> decltype(std::__to_address(__p)
242250
}
243251
#endif
244252

253+
#if _LIBCPP_STD_VER >= 23
254+
255+
template <class _Tp>
256+
struct __pointer_of {};
257+
258+
template <class _Tp>
259+
requires(__has_pointer<_Tp>::value)
260+
struct __pointer_of<_Tp> {
261+
using type = typename _Tp::pointer;
262+
};
263+
264+
template <class _Tp>
265+
requires(!__has_pointer<_Tp>::value && __has_element_type<_Tp>::value)
266+
struct __pointer_of<_Tp> {
267+
using type = typename _Tp::element_type*;
268+
};
269+
270+
template <class _Tp>
271+
requires(!__has_pointer<_Tp>::value && !__has_element_type<_Tp>::value &&
272+
__has_element_type<pointer_traits<_Tp>>::value)
273+
struct __pointer_of<_Tp> {
274+
using type = typename pointer_traits<_Tp>::element_type*;
275+
};
276+
277+
template <typename _Tp>
278+
using __pointer_of_t = typename __pointer_of<_Tp>::type;
279+
280+
template <class _Tp, class _Up>
281+
struct __pointer_of_or {
282+
using type _LIBCPP_NODEBUG = _Up;
283+
};
284+
285+
template <class _Tp, class _Up>
286+
requires requires { typename __pointer_of_t<_Tp>; }
287+
struct __pointer_of_or<_Tp, _Up> {
288+
using type _LIBCPP_NODEBUG = __pointer_of_t<_Tp>;
289+
};
290+
291+
template <typename _Tp, typename _Up>
292+
using __pointer_of_or_t = typename __pointer_of_or<_Tp, _Up>::type;
293+
294+
template <class _Smart>
295+
concept __resettable_smart_pointer = requires(_Smart __s) { __s.reset(); };
296+
297+
template <class _Smart, class _Pointer = void, class... _Args>
298+
concept __resettable_smart_pointer_with_args = requires(_Smart __s, _Pointer __p, _Args... __args) {
299+
__s.reset(static_cast<__pointer_of_or_t<_Smart, _Pointer>>(__p), std::forward<_Args>(__args)...);
300+
};
301+
302+
#endif
303+
245304
_LIBCPP_END_NAMESPACE_STD
246305

247306
#endif // _LIBCPP___MEMORY_POINTER_TRAITS_H

libcxx/include/memory

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,22 @@ void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
910910
template<size_t N, class T>
911911
[[nodiscard]] constexpr T* assume_aligned(T* ptr); // since C++20
912912
913+
// [out.ptr.t], class template out_ptr_t
914+
template<class Smart, class Pointer, class... Args>
915+
class out_ptr_t; // since c++23
916+
917+
// [out.ptr], function template out_ptr
918+
template<class Pointer = void, class Smart, class... Args>
919+
auto out_ptr(Smart& s, Args&&... args); // since c++23
920+
921+
// [inout.ptr.t], class template inout_ptr_t
922+
template<class Smart, class Pointer, class... Args>
923+
class inout_ptr_t; // since c++23
924+
925+
// [inout.ptr], function template inout_ptr
926+
template<class Pointer = void, class Smart, class... Args>
927+
auto inout_ptr(Smart& s, Args&&... args); // since c++23
928+
913929
} // std
914930
915931
*/
@@ -928,6 +944,8 @@ template<size_t N, class T>
928944
#include <__memory/compressed_pair.h>
929945
#include <__memory/concepts.h>
930946
#include <__memory/construct_at.h>
947+
#include <__memory/inout_ptr.h>
948+
#include <__memory/out_ptr.h>
931949
#include <__memory/pointer_traits.h>
932950
#include <__memory/ranges_construct_at.h>
933951
#include <__memory/ranges_uninitialized_algorithms.h>

libcxx/include/module.modulemap.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,8 @@ module std_private_memory_concepts [system] {
15191519
}
15201520
module std_private_memory_construct_at [system] { header "__memory/construct_at.h" }
15211521
module std_private_memory_destruct_n [system] { header "__memory/destruct_n.h" }
1522+
module std_private_memory_inout_ptr [system] { header "__memory/inout_ptr.h" }
1523+
module std_private_memory_out_ptr [system] { header "__memory/out_ptr.h" }
15221524
module std_private_memory_pointer_traits [system] { header "__memory/pointer_traits.h" }
15231525
module std_private_memory_ranges_construct_at [system] { header "__memory/ranges_construct_at.h" }
15241526
module std_private_memory_ranges_uninitialized_algorithms [system] {

libcxx/include/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ __cpp_lib_within_lifetime 202306L <type_traits>
455455
// # define __cpp_lib_move_only_function 202110L
456456
# undef __cpp_lib_optional
457457
# define __cpp_lib_optional 202110L
458-
// # define __cpp_lib_out_ptr 202106L
458+
# define __cpp_lib_out_ptr 202106L
459459
// # define __cpp_lib_print 202207L
460460
// # define __cpp_lib_ranges_as_const 202207L
461461
# define __cpp_lib_ranges_as_rvalue 202207L

0 commit comments

Comments
 (0)