Author: Louis Dionne Date: 2020-12-14T17:10:05-05:00 New Revision: 19d57b5c42b4e80fcbd5b6a2167e4a5f4f7b64c3
URL: https://github.com/llvm/llvm-project/commit/19d57b5c42b4e80fcbd5b6a2167e4a5f4f7b64c3 DIFF: https://github.com/llvm/llvm-project/commit/19d57b5c42b4e80fcbd5b6a2167e4a5f4f7b64c3.diff LOG: [libc++] Refactor allocate_shared to use an allocation guard This commit is a step towards making it easier to add support for arrays in allocate_shared. Adding support for arrays will require writing multiple functions, and the current complexity of writing allocate_shared is prohibitive for understanding. Differential Revision: https://reviews.llvm.org/D93130 Added: libcxx/include/__memory/utilities.h Modified: libcxx/include/CMakeLists.txt libcxx/include/memory Removed: ################################################################################ diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 71361a9e53df..cd12f60a049c 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -14,6 +14,7 @@ set(files __memory/allocator_traits.h __memory/base.h __memory/pointer_traits.h + __memory/utilities.h __mutex_base __node_handle __nullptr diff --git a/libcxx/include/__memory/utilities.h b/libcxx/include/__memory/utilities.h new file mode 100644 index 000000000000..ccbfbe78966c --- /dev/null +++ b/libcxx/include/__memory/utilities.h @@ -0,0 +1,87 @@ +// -*- 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_UTILITIES_H +#define _LIBCPP___MEMORY_UTILITIES_H + +#include <__config> +#include <__memory/allocator_traits.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 + +// Helper class to allocate memory using an Allocator in an exception safe +// manner. +// +// The intended usage of this class is as follows: +// +// 0 +// 1 __allocation_guard<SomeAllocator> guard(alloc, 10); +// 2 do_some_initialization_that_may_throw(guard.__get()); +// 3 save_allocated_pointer_in_a_noexcept_operation(guard.__release_ptr()); +// 4 +// +// If line (2) throws an exception during initialization of the memory, the +// guard's destructor will be called, and the memory will be released using +// Allocator deallocation. Otherwise, we release the memory from the guard on +// line (3) in an operation that can't throw -- after that, the guard is not +// responsible for the memory anymore. +// +// This is similar to a unique_ptr, except it's easier to use with a +// custom allocator. +template<class _Alloc> +struct __allocation_guard { + using _Pointer = typename allocator_traits<_Alloc>::pointer; + using _Size = typename allocator_traits<_Alloc>::size_type; + + _LIBCPP_HIDE_FROM_ABI + explicit __allocation_guard(_Alloc __alloc, _Size __n) + : __alloc_(_VSTD::move(__alloc)) + , __n_(__n) + , __ptr_(allocator_traits<_Alloc>::allocate(__alloc_, __n_)) // initialization order is important + { } + + _LIBCPP_HIDE_FROM_ABI + ~__allocation_guard() _NOEXCEPT { + if (__ptr_ != nullptr) { + allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __n_); + } + } + + _LIBCPP_HIDE_FROM_ABI + _Pointer __release_ptr() _NOEXCEPT { // not called __release() because it's a keyword in objective-c++ + _Pointer __tmp = __ptr_; + __ptr_ = nullptr; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI + _Pointer __get() const _NOEXCEPT { + return __ptr_; + } + +private: + _Alloc __alloc_; + _Size __n_; + _Pointer __ptr_; +}; + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MEMORY_UTILITIES_H diff --git a/libcxx/include/memory b/libcxx/include/memory index f81ff6680f9f..24ad9e567b99 100644 --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -682,6 +682,7 @@ void* align(size_t alignment, size_t size, void*& ptr, size_t& space); #include <__memory/allocator_traits.h> #include <__memory/base.h> #include <__memory/pointer_traits.h> +#include <__memory/utilities.h> #if !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER) # include <atomic> #endif @@ -3299,28 +3300,21 @@ shared_ptr<_Tp>::reset(_Yp* __p, _Dp __d, _Alloc __a) shared_ptr(__p, __d, __a).swap(*this); } -template<class _Tp, class _Alloc, class ..._Args> -inline _LIBCPP_INLINE_VISIBILITY -typename enable_if -< - !is_array<_Tp>::value, - shared_ptr<_Tp> ->::type -allocate_shared(const _Alloc& __a, _Args&& ...__args) +// +// std::allocate_shared and std::make_shared +// +template<class _Tp, class _Alloc, class ..._Args, class = _EnableIf<!is_array<_Tp>::value> > +_LIBCPP_HIDE_FROM_ABI +shared_ptr<_Tp> allocate_shared(const _Alloc& __a, _Args&& ...__args) { static_assert(is_constructible<_Tp, _Args...>::value, "allocate_shared/make_shared: the type is not constructible from the provided arguments"); - - typedef __shared_ptr_emplace<_Tp, _Alloc> _CntrlBlk; - typedef typename __allocator_traits_rebind<_Alloc, _CntrlBlk>::type _A2; - typedef __allocator_destructor<_A2> _D2; - - _A2 __a2(__a); - unique_ptr<_CntrlBlk, _D2> __hold2(__a2.allocate(1), _D2(__a2, 1)); - ::new ((void*)_VSTD::addressof(*__hold2.get())) _CntrlBlk(__a, _VSTD::forward<_Args>(__args)...); - - typename shared_ptr<_Tp>::element_type *__p = __hold2->__get_elem(); - return shared_ptr<_Tp>::__create_with_control_block(__p, _VSTD::addressof(*__hold2.release())); + using _ControlBlock = __shared_ptr_emplace<_Tp, _Alloc>; + using _ControlBlockAllocator = typename __allocator_traits_rebind<_Alloc, _ControlBlock>::type; + __allocation_guard<_ControlBlockAllocator> __guard(__a, 1); + ::new ((void*)_VSTD::addressof(*__guard.__get())) _ControlBlock(__a, _VSTD::forward<_Args>(__args)...); + auto __control_block = __guard.__release_ptr(); + return shared_ptr<_Tp>::__create_with_control_block((*__control_block).__get_elem(), _VSTD::addressof(*__control_block)); } template<class _Tp, class ..._Args, class = _EnableIf<!is_array<_Tp>::value> > _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits