Skip to content

Commit

Permalink
[libc++] Remove get_temporary_buffer and return_temporary_buffer (#10…
Browse files Browse the repository at this point in the history
…0914)

Works towards P0619R4 / #99985.

The use of `std::get_temporary_buffer` and `std::return_temporary_buffer`
are replaced with `unique_ptr`-based RAII buffer holder.

Escape hatches:
- `_LIBCPP_ENABLE_CXX20_REMOVED_TEMPORARY_BUFFER` restores
`std::get_temporary_buffer` and `std::return_temporary_buffer`.

Drive-by changes:
- In `<syncstream>`, states that `get_temporary_buffer` is now removed,
because `<syncstream>` is added in C++20.
  • Loading branch information
frederick-vs-ja authored Sep 16, 2024
1 parent 0bc8168 commit 94e7c0b
Show file tree
Hide file tree
Showing 18 changed files with 153 additions and 84 deletions.
3 changes: 3 additions & 0 deletions libcxx/docs/ReleaseNotes/20.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ Improvements and New Features
- The ``lexicographical_compare`` and ``ranges::lexicographical_compare`` algorithms have been optimized for trivially
equality comparable types, resulting in a performance improvement of up to 40x.

- The ``_LIBCPP_ENABLE_CXX20_REMOVED_TEMPORARY_BUFFER`` macro has been added to make ``std::get_temporary_buffer`` and
``std::return_temporary_buffer`` available.

- The ``_LIBCPP_ENABLE_CXX20_REMOVED_UNCAUGHT_EXCEPTION`` macro has been added to make ``std::uncaught_exception``
available in C++20 and later modes.

Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx20Papers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"`P0528R3 <https://wg21.link/P0528R3>`__","The Curious Case of Padding Bits, Featuring Atomic Compare-and-Exchange","2018-06 (Rapperswil)","","",""
"`P0542R5 <https://wg21.link/P0542R5>`__","Support for contract based programming in C++","2018-06 (Rapperswil)","|Nothing To Do|","n/a","Pulled at the 2019-07 meeting in Cologne"
"`P0556R3 <https://wg21.link/P0556R3>`__","Integral power-of-2 operations","2018-06 (Rapperswil)","|Complete|","9.0",""
"`P0619R4 <https://wg21.link/P0619R4>`__","Reviewing Deprecated Facilities of C++17 for C++20","2018-06 (Rapperswil)","|Partial|","","Only sections D.7, D.8, D.9, D.10, D.11 and D.13 are implemented. Sections D.4 and D.12 remain undone."
"`P0619R4 <https://wg21.link/P0619R4>`__","Reviewing Deprecated Facilities of C++17 for C++20","2018-06 (Rapperswil)","|Partial|","","Only sections D.7, D.8, D.9, D.10, D.11, D.12, and D.13 are implemented. Section D.4 remains undone."
"`P0646R1 <https://wg21.link/P0646R1>`__","Improving the Return Value of Erase-Like Algorithms","2018-06 (Rapperswil)","|Complete|","10.0",""
"`P0722R3 <https://wg21.link/P0722R3>`__","Efficient sized delete for variable sized classes","2018-06 (Rapperswil)","|Complete|","9.0",""
"`P0758R1 <https://wg21.link/P0758R1>`__","Implicit conversion traits and utility functions","2018-06 (Rapperswil)","|Complete|","",""
Expand Down
3 changes: 3 additions & 0 deletions libcxx/docs/UserDocumentation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ C++20 Specific Configuration Macros
**_LIBCPP_ENABLE_CXX20_REMOVED_RAW_STORAGE_ITERATOR**:
This macro is used to re-enable `raw_storage_iterator`.

**_LIBCPP_ENABLE_CXX20_REMOVED_TEMPORARY_BUFFER**:
This macro is used to re-enable `get_temporary_buffer` and `return_temporary_buffer`.

**_LIBCPP_ENABLE_CXX20_REMOVED_TYPE_TRAITS**:
This macro is used to re-enable `is_literal_type`, `is_literal_type_v`,
`result_of` and `result_of_t`.
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@ set(files
__memory/temporary_buffer.h
__memory/uninitialized_algorithms.h
__memory/unique_ptr.h
__memory/unique_temporary_buffer.h
__memory/uses_allocator.h
__memory/uses_allocator_construction.h
__memory/voidify.h
Expand Down
23 changes: 13 additions & 10 deletions libcxx/include/__algorithm/inplace_merge.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
#include <__iterator/iterator_traits.h>
#include <__iterator/reverse_iterator.h>
#include <__memory/destruct_n.h>
#include <__memory/temporary_buffer.h>
#include <__memory/unique_ptr.h>
#include <__memory/unique_temporary_buffer.h>
#include <__utility/pair.h>
#include <new>

Expand Down Expand Up @@ -208,16 +208,19 @@ _LIBCPP_HIDE_FROM_ABI void __inplace_merge(
_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _Compare&& __comp) {
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type;
difference_type __len1 = _IterOps<_AlgPolicy>::distance(__first, __middle);
difference_type __len2 = _IterOps<_AlgPolicy>::distance(__middle, __last);
difference_type __buf_size = std::min(__len1, __len2);
// TODO: Remove the use of std::get_temporary_buffer
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
pair<value_type*, ptrdiff_t> __buf = std::get_temporary_buffer<value_type>(__buf_size);
_LIBCPP_SUPPRESS_DEPRECATED_POP
unique_ptr<value_type, __return_temporary_buffer> __h(__buf.first);
difference_type __len1 = _IterOps<_AlgPolicy>::distance(__first, __middle);
difference_type __len2 = _IterOps<_AlgPolicy>::distance(__middle, __last);
difference_type __buf_size = std::min(__len1, __len2);
__unique_temporary_buffer<value_type> __unique_buf = std::__allocate_unique_temporary_buffer<value_type>(__buf_size);
return std::__inplace_merge<_AlgPolicy>(
std::move(__first), std::move(__middle), std::move(__last), __comp, __len1, __len2, __buf.first, __buf.second);
std::move(__first),
std::move(__middle),
std::move(__last),
__comp,
__len1,
__len2,
__unique_buf.get(),
__unique_buf.get_deleter().__count_);
}

template <class _BidirectionalIterator, class _Compare>
Expand Down
22 changes: 9 additions & 13 deletions libcxx/include/__algorithm/stable_partition.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
#include <__iterator/distance.h>
#include <__iterator/iterator_traits.h>
#include <__memory/destruct_n.h>
#include <__memory/temporary_buffer.h>
#include <__memory/unique_ptr.h>
#include <__memory/unique_temporary_buffer.h>
#include <__utility/move.h>
#include <__utility/pair.h>
#include <new>
Expand Down Expand Up @@ -132,14 +132,12 @@ __stable_partition_impl(_ForwardIterator __first, _ForwardIterator __last, _Pred
// We now have a reduced range [__first, __last)
// *__first is known to be false
difference_type __len = _IterOps<_AlgPolicy>::distance(__first, __last);
__unique_temporary_buffer<value_type> __unique_buf;
pair<value_type*, ptrdiff_t> __p(0, 0);
unique_ptr<value_type, __return_temporary_buffer> __h;
if (__len >= __alloc_limit) {
// TODO: Remove the use of std::get_temporary_buffer
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
__p = std::get_temporary_buffer<value_type>(__len);
_LIBCPP_SUPPRESS_DEPRECATED_POP
__h.reset(__p.first);
__unique_buf = std::__allocate_unique_temporary_buffer<value_type>(__len);
__p.first = __unique_buf.get();
__p.second = __unique_buf.get_deleter().__count_;
}
return std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
std::move(__first), std::move(__last), __pred, __len, __p, forward_iterator_tag());
Expand Down Expand Up @@ -272,14 +270,12 @@ _LIBCPP_HIDE_FROM_ABI _BidirectionalIterator __stable_partition_impl(
// *__last is known to be true
// __len >= 2
difference_type __len = _IterOps<_AlgPolicy>::distance(__first, __last) + 1;
__unique_temporary_buffer<value_type> __unique_buf;
pair<value_type*, ptrdiff_t> __p(0, 0);
unique_ptr<value_type, __return_temporary_buffer> __h;
if (__len >= __alloc_limit) {
// TODO: Remove the use of std::get_temporary_buffer
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
__p = std::get_temporary_buffer<value_type>(__len);
_LIBCPP_SUPPRESS_DEPRECATED_POP
__h.reset(__p.first);
__unique_buf = std::__allocate_unique_temporary_buffer<value_type>(__len);
__p.first = __unique_buf.get();
__p.second = __unique_buf.get_deleter().__count_;
}
return std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
std::move(__first), std::move(__last), __pred, __len, __p, bidirectional_iterator_tag());
Expand Down
12 changes: 5 additions & 7 deletions libcxx/include/__algorithm/stable_sort.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
#include <__debug_utils/strict_weak_ordering_check.h>
#include <__iterator/iterator_traits.h>
#include <__memory/destruct_n.h>
#include <__memory/temporary_buffer.h>
#include <__memory/unique_ptr.h>
#include <__memory/unique_temporary_buffer.h>
#include <__type_traits/is_trivially_assignable.h>
#include <__utility/move.h>
#include <__utility/pair.h>
Expand Down Expand Up @@ -241,14 +241,12 @@ __stable_sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last,
using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type;

difference_type __len = __last - __first;
__unique_temporary_buffer<value_type> __unique_buf;
pair<value_type*, ptrdiff_t> __buf(0, 0);
unique_ptr<value_type, __return_temporary_buffer> __h;
if (__len > static_cast<difference_type>(__stable_sort_switch<value_type>::value)) {
// TODO: Remove the use of std::get_temporary_buffer
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
__buf = std::get_temporary_buffer<value_type>(__len);
_LIBCPP_SUPPRESS_DEPRECATED_POP
__h.reset(__buf.first);
__unique_buf = std::__allocate_unique_temporary_buffer<value_type>(__len);
__buf.first = __unique_buf.get();
__buf.second = __unique_buf.get_deleter().__count_;
}

std::__stable_sort<_AlgPolicy, __comp_ref_type<_Compare> >(__first, __last, __comp, __len, __buf.first, __buf.second);
Expand Down
51 changes: 11 additions & 40 deletions libcxx/include/__memory/temporary_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#define _LIBCPP___MEMORY_TEMPORARY_BUFFER_H

#include <__config>
#include <__memory/unique_temporary_buffer.h>
#include <__utility/pair.h>
#include <cstddef>
#include <new>
Expand All @@ -19,57 +20,27 @@
# pragma GCC system_header
#endif

#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_TEMPORARY_BUFFER)

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Tp>
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_CFI _LIBCPP_DEPRECATED_IN_CXX17 pair<_Tp*, ptrdiff_t>
get_temporary_buffer(ptrdiff_t __n) _NOEXCEPT {
pair<_Tp*, ptrdiff_t> __r(0, 0);
const ptrdiff_t __m =
(~ptrdiff_t(0) ^ ptrdiff_t(ptrdiff_t(1) << (sizeof(ptrdiff_t) * __CHAR_BIT__ - 1))) / sizeof(_Tp);
if (__n > __m)
__n = __m;
while (__n > 0) {
#if !defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION)
if (__is_overaligned_for_new(_LIBCPP_ALIGNOF(_Tp))) {
align_val_t __al = align_val_t(_LIBCPP_ALIGNOF(_Tp));
__r.first = static_cast<_Tp*>(::operator new(__n * sizeof(_Tp), __al, nothrow));
} else {
__r.first = static_cast<_Tp*>(::operator new(__n * sizeof(_Tp), nothrow));
}
#else
if (__is_overaligned_for_new(_LIBCPP_ALIGNOF(_Tp))) {
// Since aligned operator new is unavailable, return an empty
// buffer rather than one with invalid alignment.
return __r;
}

__r.first = static_cast<_Tp*>(::operator new(__n * sizeof(_Tp), nothrow));
#endif

if (__r.first) {
__r.second = __n;
break;
}
__n /= 2;
}
return __r;
__unique_temporary_buffer<_Tp> __unique_buf = std::__allocate_unique_temporary_buffer<_Tp>(__n);
pair<_Tp*, ptrdiff_t> __result(__unique_buf.get(), __unique_buf.get_deleter().__count_);
__unique_buf.release();
return __result;
}

template <class _Tp>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_IN_CXX17 void return_temporary_buffer(_Tp* __p) _NOEXCEPT {
std::__libcpp_deallocate_unsized((void*)__p, _LIBCPP_ALIGNOF(_Tp));
__unique_temporary_buffer<_Tp> __unique_buf(__p);
(void)__unique_buf;
}

struct __return_temporary_buffer {
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI void operator()(_Tp* __p) const {
std::return_temporary_buffer(__p);
}
_LIBCPP_SUPPRESS_DEPRECATED_POP
};

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_TEMPORARY_BUFFER)

#endif // _LIBCPP___MEMORY_TEMPORARY_BUFFER_H
92 changes: 92 additions & 0 deletions libcxx/include/__memory/unique_temporary_buffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// -*- 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___MEMORY_UNIQUE_TEMPORARY_BUFFER_H
#define _LIBCPP___MEMORY_UNIQUE_TEMPORARY_BUFFER_H

#include <__assert>
#include <__config>

#include <__memory/allocator.h>
#include <__memory/unique_ptr.h>
#include <__type_traits/is_constant_evaluated.h>
#include <cstddef>
#include <new>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Tp>
struct __temporary_buffer_deleter {
ptrdiff_t __count_; // ignored in non-constant evaluation

_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __temporary_buffer_deleter() _NOEXCEPT : __count_(0) {}
_LIBCPP_HIDE_FROM_ABI
_LIBCPP_CONSTEXPR explicit __temporary_buffer_deleter(ptrdiff_t __count) _NOEXCEPT : __count_(__count) {}

_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void operator()(_Tp* __ptr) _NOEXCEPT {
if (__libcpp_is_constant_evaluated()) {
allocator<_Tp>().deallocate(__ptr, __count_);
return;
}

std::__libcpp_deallocate_unsized((void*)__ptr, _LIBCPP_ALIGNOF(_Tp));
}
};

template <class _Tp>
using __unique_temporary_buffer = unique_ptr<_Tp, __temporary_buffer_deleter<_Tp> >;

template <class _Tp>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __unique_temporary_buffer<_Tp>
__allocate_unique_temporary_buffer(ptrdiff_t __count) {
using __deleter_type = __temporary_buffer_deleter<_Tp>;
using __unique_buffer_type = __unique_temporary_buffer<_Tp>;

if (__libcpp_is_constant_evaluated()) {
return __unique_buffer_type(allocator<_Tp>().allocate(__count), __deleter_type(__count));
}

_Tp* __ptr = nullptr;
const ptrdiff_t __max_count =
(~ptrdiff_t(0) ^ ptrdiff_t(ptrdiff_t(1) << (sizeof(ptrdiff_t) * __CHAR_BIT__ - 1))) / sizeof(_Tp);
if (__count > __max_count)
__count = __max_count;
while (__count > 0) {
#if !defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION)
if (__is_overaligned_for_new(_LIBCPP_ALIGNOF(_Tp))) {
align_val_t __al = align_val_t(_LIBCPP_ALIGNOF(_Tp));
__ptr = static_cast<_Tp*>(::operator new(__count * sizeof(_Tp), __al, nothrow));
} else {
__ptr = static_cast<_Tp*>(::operator new(__count * sizeof(_Tp), nothrow));
}
#else
if (__is_overaligned_for_new(_LIBCPP_ALIGNOF(_Tp))) {
// Since aligned operator new is unavailable, constructs an empty buffer rather than one with invalid alignment.
return __unique_buffer_type();
}

__ptr = static_cast<_Tp*>(::operator new(__count * sizeof(_Tp), nothrow));
#endif

if (__ptr) {
break;
}
__count /= 2;
}

return __unique_buffer_type(__ptr, __deleter_type(__count));
}

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___MEMORY_UNIQUE_TEMPORARY_BUFFER_H
4 changes: 2 additions & 2 deletions libcxx/include/memory
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@ public:
raw_storage_iterator operator++(int);
};
template <class T> pair<T*,ptrdiff_t> get_temporary_buffer(ptrdiff_t n) noexcept;
template <class T> void return_temporary_buffer(T* p) noexcept;
template <class T> pair<T*,ptrdiff_t> get_temporary_buffer(ptrdiff_t n) noexcept; // deprecated in C++17, removed in C++20
template <class T> void return_temporary_buffer(T* p) noexcept; // deprecated in C++17, removed in C++20
template <class T> T* addressof(T& r) noexcept;
template <class T> T* addressof(const T&& r) noexcept = delete;
Expand Down
5 changes: 5 additions & 0 deletions libcxx/include/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -1542,6 +1542,11 @@ module std_private_memory_unique_ptr [system] {
export std_private_type_traits_is_pointer
export std_private_type_traits_type_identity
}
module std_private_memory_unique_temporary_buffer [system] {
header "__memory/unique_temporary_buffer.h"
export std_private_memory_unique_ptr
export std_private_type_traits_is_constant_evaluated
}
module std_private_memory_uses_allocator [system] { header "__memory/uses_allocator.h" }
module std_private_memory_uses_allocator_construction [system] { header "__memory/uses_allocator_construction.h" }
module std_private_memory_voidify [system] { header "__memory/voidify.h" }
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/syncstream
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ private:
// TODO Use a more generic buffer.
// That buffer should be light with almost no additional headers. Then
// it can be use here, the __retarget_buffer, and place that use
// the now deprecated get_temporary_buffer
// the now removed get_temporary_buffer

basic_string<_CharT, _Traits, _Allocator> __str_;
bool __emit_on_sync_{false};
Expand Down
1 change: 1 addition & 0 deletions libcxx/test/libcxx/diagnostics/memory.nodiscard.verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

// check that <memory> functions are marked [[nodiscard]]

// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_CXX20_REMOVED_TEMPORARY_BUFFER
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS

// clang-format off
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,9 @@ test()
assert(array[9] == P(0, 2));
}
#if TEST_STD_VER >= 11 && !defined(TEST_HAS_NO_EXCEPTIONS)
// TODO: Re-enable this test once we're no longer using get_temporary_buffer().
// TODO: Re-enable this test once we get recursive inlining fixed.
// For now it trips up GCC due to the use of always_inline.
#if 0
# if 0
{ // check that the algorithm still works when no memory is available
std::vector<int> vec(150, 3);
vec[5] = 6;
Expand All @@ -300,7 +300,7 @@ test()
assert(std::is_partitioned(vec.begin(), vec.end(), [](int i) { return i < 5; }));
getGlobalMemCounter()->reset();
}
#endif
# endif
#endif // TEST_STD_VER >= 11 && !defined(TEST_HAS_NO_EXCEPTIONS)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

// UNSUPPORTED: c++03

// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_CXX20_REMOVED_TEMPORARY_BUFFER
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS

// <memory>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

// <memory>

// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_CXX20_REMOVED_TEMPORARY_BUFFER
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS

// template <class T>
Expand Down
Loading

0 comments on commit 94e7c0b

Please sign in to comment.