diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -496,6 +496,7 @@ __memory/temp_value.h __memory/temporary_buffer.h __memory/uninitialized_algorithms.h + __memory/uninitialized_buffer.h __memory/unique_ptr.h __memory/uses_allocator.h __memory/uses_allocator_construction.h diff --git a/libcxx/include/__algorithm/inplace_merge.h b/libcxx/include/__algorithm/inplace_merge.h --- a/libcxx/include/__algorithm/inplace_merge.h +++ b/libcxx/include/__algorithm/inplace_merge.h @@ -24,7 +24,7 @@ #include <__iterator/iterator_traits.h> #include <__iterator/reverse_iterator.h> #include <__memory/destruct_n.h> -#include <__memory/temporary_buffer.h> +#include <__memory/uninitialized_buffer.h> #include <__memory/unique_ptr.h> #include <__utility/pair.h> #include @@ -225,13 +225,16 @@ difference_type __len1 = _IterOps<_AlgPolicy>::distance(__first, __middle); difference_type __len2 = _IterOps<_AlgPolicy>::distance(__middle, __last); difference_type __buf_size = _VSTD::min(__len1, __len2); -// TODO: Remove the use of std::get_temporary_buffer -_LIBCPP_SUPPRESS_DEPRECATED_PUSH - pair __buf = _VSTD::get_temporary_buffer(__buf_size); -_LIBCPP_SUPPRESS_DEPRECATED_POP - unique_ptr __h(__buf.first); + auto __buf = std::__make_uninitialized_buffer(nothrow, __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, + __buf.get(), + __buf ? __buf_size : 0); } template diff --git a/libcxx/include/__algorithm/stable_partition.h b/libcxx/include/__algorithm/stable_partition.h --- a/libcxx/include/__algorithm/stable_partition.h +++ b/libcxx/include/__algorithm/stable_partition.h @@ -16,7 +16,7 @@ #include <__iterator/distance.h> #include <__iterator/iterator_traits.h> #include <__memory/destruct_n.h> -#include <__memory/temporary_buffer.h> +#include <__memory/uninitialized_buffer.h> #include <__memory/unique_ptr.h> #include <__utility/move.h> #include <__utility/pair.h> @@ -137,18 +137,18 @@ typedef typename iterator_traits<_ForwardIterator>::difference_type difference_type; typedef typename iterator_traits<_ForwardIterator>::value_type value_type; difference_type __len = _IterOps<_AlgPolicy>::distance(__first, __last); - pair __p(0, 0); - unique_ptr __h; + + __uninitialized_buffer_t __buf; if (__len >= __alloc_limit) - { -// TODO: Remove the use of std::get_temporary_buffer -_LIBCPP_SUPPRESS_DEPRECATED_PUSH - __p = _VSTD::get_temporary_buffer(__len); -_LIBCPP_SUPPRESS_DEPRECATED_POP - __h.reset(__p.first); - } + __buf = std::__make_uninitialized_buffer(nothrow, __len); + return std::__stable_partition_impl<_AlgPolicy, _Predicate&>( - std::move(__first), std::move(__last), __pred, __len, __p, forward_iterator_tag()); + std::move(__first), + std::move(__last), + __pred, + __len, + std::make_pair(__buf.get(), __buf ? __len : 0), + forward_iterator_tag()); } template @@ -291,18 +291,17 @@ // *__last is known to be true // __len >= 2 difference_type __len = _IterOps<_AlgPolicy>::distance(__first, __last) + 1; - pair __p(0, 0); - unique_ptr __h; + __uninitialized_buffer_t __buf; if (__len >= __alloc_limit) - { -// TODO: Remove the use of std::get_temporary_buffer -_LIBCPP_SUPPRESS_DEPRECATED_PUSH - __p = _VSTD::get_temporary_buffer(__len); -_LIBCPP_SUPPRESS_DEPRECATED_POP - __h.reset(__p.first); - } + __buf = std::__make_uninitialized_buffer(nothrow, __len); + return std::__stable_partition_impl<_AlgPolicy, _Predicate&>( - std::move(__first), std::move(__last), __pred, __len, __p, bidirectional_iterator_tag()); + std::move(__first), + std::move(__last), + __pred, + __len, + std::make_pair(__buf.get(), __buf ? __len : 0), + bidirectional_iterator_tag()); } template diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -17,7 +17,6 @@ #include <__config> #include <__iterator/iterator_traits.h> #include <__memory/destruct_n.h> -#include <__memory/temporary_buffer.h> #include <__memory/unique_ptr.h> #include <__type_traits/is_trivially_copy_assignable.h> #include <__utility/move.h> @@ -248,17 +247,12 @@ using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type; difference_type __len = __last - __first; - pair __buf(0, 0); - unique_ptr __h; - if (__len > static_cast(__stable_sort_switch::value)) { -// TODO: Remove the use of std::get_temporary_buffer -_LIBCPP_SUPPRESS_DEPRECATED_PUSH - __buf = std::get_temporary_buffer(__len); -_LIBCPP_SUPPRESS_DEPRECATED_POP - __h.reset(__buf.first); - } + __uninitialized_buffer_t __buf; + if (__len > static_cast(__stable_sort_switch::value)) + __buf = std::__make_uninitialized_buffer(nothrow, __len); - std::__stable_sort<_AlgPolicy, __comp_ref_type<_Compare> >(__first, __last, __comp, __len, __buf.first, __buf.second); + std::__stable_sort<_AlgPolicy, __comp_ref_type<_Compare> >( + __first, __last, __comp, __len, __buf.get(), __buf ? __len : 0); } template diff --git a/libcxx/include/__memory/construct_at.h b/libcxx/include/__memory/construct_at.h --- a/libcxx/include/__memory/construct_at.h +++ b/libcxx/include/__memory/construct_at.h @@ -93,6 +93,16 @@ return __last; } +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 +_ForwardIterator __destroy_n(_ForwardIterator __first, _Size __n) { + while (__n > 0) { + std::__destroy_at(std::addressof(*__first)); + ++__first; + --__n; + } + return __first; +} #if _LIBCPP_STD_VER >= 17 template , int> = 0> @@ -118,9 +128,7 @@ template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator destroy_n(_ForwardIterator __first, _Size __n) { - for (; __n > 0; (void)++__first, --__n) - std::__destroy_at(std::addressof(*__first)); - return __first; + return std::__destroy_n(__first, __n); } #endif // _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__memory/temporary_buffer.h b/libcxx/include/__memory/temporary_buffer.h --- a/libcxx/include/__memory/temporary_buffer.h +++ b/libcxx/include/__memory/temporary_buffer.h @@ -74,14 +74,6 @@ _VSTD::__libcpp_deallocate_unsized((void*)__p, _LIBCPP_ALIGNOF(_Tp)); } -struct __return_temporary_buffer -{ -_LIBCPP_SUPPRESS_DEPRECATED_PUSH - template - _LIBCPP_INLINE_VISIBILITY void operator()(_Tp* __p) const {_VSTD::return_temporary_buffer(__p);} -_LIBCPP_SUPPRESS_DEPRECATED_POP -}; - _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___MEMORY_TEMPORARY_BUFFER_H diff --git a/libcxx/include/__memory/uninitialized_buffer.h b/libcxx/include/__memory/uninitialized_buffer.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__memory/uninitialized_buffer.h @@ -0,0 +1,76 @@ +//===----------------------------------------------------------------------===// +// +// 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_UNINITIALIZED_BUFFER_H +#define _LIBCPP___MEMORY_UNINITIALIZED_BUFFER_H + +#include <__config> +#include <__memory/construct_at.h> +#include <__memory/unique_ptr.h> +#include <__type_traits/is_array.h> +#include <__type_traits/is_default_constructible.h> +#include <__type_traits/remove_extent.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class __uninitialized_buffer_deleter { + size_t __count_; + _Destructor __destructor_; + +public: + template ::value, _Dummy> = 0> + __uninitialized_buffer_deleter() : __count_(0) {} + + __uninitialized_buffer_deleter(size_t __count, _Destructor __destructor) + : __count_(__count), __destructor_(std::move(__destructor)) {} + + template + _LIBCPP_HIDE_FROM_ABI void operator()(_Tp* __ptr) { + __destructor_(__ptr, __count_); +#ifdef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION + ::operator delete(__ptr, __count_ * sizeof(_Tp)); +#else + ::operator delete(__ptr, __count_ * sizeof(_Tp), align_val_t(_LIBCPP_ALIGNOF(_Tp))); +#endif + } +}; + +struct __noop { + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR void operator()(_Args&&...) const {} +}; + +template +using __uninitialized_buffer_t = unique_ptr<_Array, __uninitialized_buffer_deleter<_Destructor>>; + +template +_LIBCPP_HIDE_FROM_ABI __uninitialized_buffer_t<_Array, _Destructor> +__make_uninitialized_buffer(nothrow_t, size_t __count, _Destructor __destructor = __noop()) { + static_assert(is_array<_Array>::value, ""); + using _Tp = __remove_extent_t<_Array>; + +#ifdef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION + _Tp* __ptr = static_cast<_Tp*>(::operator new(sizeof(_Tp) * __count, nothrow)); +#else + _Tp* __ptr = static_cast<_Tp*>(::operator new(sizeof(_Tp) * __count, align_val_t(_LIBCPP_ALIGNOF(_Tp)), nothrow)); +#endif + + using _Deleter = __uninitialized_buffer_deleter<_Destructor>; + return unique_ptr<_Array, _Deleter>(__ptr, _Deleter(__count, std::move(__destructor))); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MEMORY_UNINITIALIZED_BUFFER_H diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -524,6 +524,7 @@ #include <__memory/temp_value.h> // expected-error@*:* {{use of private header from outside its module: '__memory/temp_value.h'}} #include <__memory/temporary_buffer.h> // expected-error@*:* {{use of private header from outside its module: '__memory/temporary_buffer.h'}} #include <__memory/uninitialized_algorithms.h> // expected-error@*:* {{use of private header from outside its module: '__memory/uninitialized_algorithms.h'}} +#include <__memory/uninitialized_buffer.h> // expected-error@*:* {{use of private header from outside its module: '__memory/uninitialized_buffer.h'}} #include <__memory/unique_ptr.h> // expected-error@*:* {{use of private header from outside its module: '__memory/unique_ptr.h'}} #include <__memory/uses_allocator.h> // expected-error@*:* {{use of private header from outside its module: '__memory/uses_allocator.h'}} #include <__memory/uses_allocator_construction.h> // expected-error@*:* {{use of private header from outside its module: '__memory/uses_allocator_construction.h'}} diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/stable_partition.not_enough_memory.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/stable_partition.not_enough_memory.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/stable_partition.not_enough_memory.pass.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// check that the algorithm works properly, even when no memory is available + +// + +// template Pred> +// requires ShuffleIterator +// && CopyConstructible +// Iter +// stable_partition(Iter first, Iter last, Pred pred); + +#include +#include +#include +#include + +#include "count_new.h" +#include "test_iterators.h" +#include "test_macros.h" + +int main(int, char**) { + std::vector vec(150, 3); + vec[5] = 6; + getGlobalMemCounter()->throw_after = 0; + std::stable_partition(vec.begin(), vec.end(), [](int i) { return i < 5; }); + vec[5] = 6; + getGlobalMemCounter()->throw_after = 0; + std::stable_partition(forward_iterator(vec.begin()), forward_iterator(vec.end()), [](int i) { return i < 5; }); + + return 0; +} diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge.not_enough_memory.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge.not_enough_memory.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge.not_enough_memory.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// check that the algorithm works properly, even when no memory is available + +// + +// template +// requires ShuffleIterator +// && LessThanComparable +// void +// inplace_merge(Iter first, Iter middle, Iter last); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "count_new.h" + +int main(int, char**) { + std::vector vec(150, 3); + getGlobalMemCounter()->throw_after = 0; + std::inplace_merge(vec.begin(), vec.begin() + 100, vec.end()); + + return 0; +} diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.not_enough_memory.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.not_enough_memory.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.not_enough_memory.pass.cpp @@ -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 +// +//===----------------------------------------------------------------------===// + +// check that the algorithm works properly, even when no memory is available + +// + +// template +// requires ShuffleIterator +// && LessThanComparable +// void +// stable_sort(Iter first, Iter last); + +#include +#include +#include +#include + +#include "count_new.h" +#include "test_iterators.h" +#include "test_macros.h" + +int main(int, char**) { + std::vector vec(150, 3); + getGlobalMemCounter()->throw_after = 0; + std::stable_sort(vec.begin(), vec.end()); + + return 0; +}