1fe6060f1SDimitry Andric // -*- C++ -*- 2fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 3fe6060f1SDimitry Andric // 4fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 6fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7fe6060f1SDimitry Andric // 8fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 9fe6060f1SDimitry Andric 10fe6060f1SDimitry Andric #ifndef _LIBCPP___MEMORY_ALLOCATION_GUARD_H 11fe6060f1SDimitry Andric #define _LIBCPP___MEMORY_ALLOCATION_GUARD_H 12fe6060f1SDimitry Andric 13fe6060f1SDimitry Andric #include <__config> 1406c3fb27SDimitry Andric #include <__memory/addressof.h> 15fe6060f1SDimitry Andric #include <__memory/allocator_traits.h> 1681ad6265SDimitry Andric #include <__utility/move.h> 17fe6060f1SDimitry Andric #include <cstddef> 18fe6060f1SDimitry Andric 19fe6060f1SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 20fe6060f1SDimitry Andric # pragma GCC system_header 21fe6060f1SDimitry Andric #endif 22fe6060f1SDimitry Andric 2306c3fb27SDimitry Andric _LIBCPP_PUSH_MACROS 2406c3fb27SDimitry Andric #include <__undef_macros> 2506c3fb27SDimitry Andric 26fe6060f1SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 27fe6060f1SDimitry Andric 28fe6060f1SDimitry Andric // Helper class to allocate memory using an Allocator in an exception safe 29fe6060f1SDimitry Andric // manner. 30fe6060f1SDimitry Andric // 31fe6060f1SDimitry Andric // The intended usage of this class is as follows: 32fe6060f1SDimitry Andric // 33fe6060f1SDimitry Andric // 0 34fe6060f1SDimitry Andric // 1 __allocation_guard<SomeAllocator> guard(alloc, 10); 35fe6060f1SDimitry Andric // 2 do_some_initialization_that_may_throw(guard.__get()); 36fe6060f1SDimitry Andric // 3 save_allocated_pointer_in_a_noexcept_operation(guard.__release_ptr()); 37fe6060f1SDimitry Andric // 4 38fe6060f1SDimitry Andric // 39fe6060f1SDimitry Andric // If line (2) throws an exception during initialization of the memory, the 40fe6060f1SDimitry Andric // guard's destructor will be called, and the memory will be released using 41fe6060f1SDimitry Andric // Allocator deallocation. Otherwise, we release the memory from the guard on 42fe6060f1SDimitry Andric // line (3) in an operation that can't throw -- after that, the guard is not 43fe6060f1SDimitry Andric // responsible for the memory anymore. 44fe6060f1SDimitry Andric // 45fe6060f1SDimitry Andric // This is similar to a unique_ptr, except it's easier to use with a 46fe6060f1SDimitry Andric // custom allocator. 47fe6060f1SDimitry Andric template <class _Alloc> 48fe6060f1SDimitry Andric struct __allocation_guard { 49fe6060f1SDimitry Andric using _Pointer = typename allocator_traits<_Alloc>::pointer; 50fe6060f1SDimitry Andric using _Size = typename allocator_traits<_Alloc>::size_type; 51fe6060f1SDimitry Andric 52fe6060f1SDimitry Andric template <class _AllocT> // we perform the allocator conversion inside the constructor __allocation_guard__allocation_guard53*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit __allocation_guard(_AllocT __alloc, _Size __n) 54*cb14a3feSDimitry Andric : __alloc_(std::move(__alloc)), 55*cb14a3feSDimitry Andric __n_(__n), 56*cb14a3feSDimitry Andric __ptr_(allocator_traits<_Alloc>::allocate(__alloc_, __n_)) // initialization order is important 57fe6060f1SDimitry Andric {} 58fe6060f1SDimitry Andric ~__allocation_guard__allocation_guard59*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI ~__allocation_guard() _NOEXCEPT { __destroy(); } 6006c3fb27SDimitry Andric 6106c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI __allocation_guard(const __allocation_guard&) = delete; __allocation_guard__allocation_guard6206c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI __allocation_guard(__allocation_guard&& __other) _NOEXCEPT 63*cb14a3feSDimitry Andric : __alloc_(std::move(__other.__alloc_)), 64*cb14a3feSDimitry Andric __n_(__other.__n_), 65*cb14a3feSDimitry Andric __ptr_(__other.__ptr_) { 6606c3fb27SDimitry Andric __other.__ptr_ = nullptr; 6706c3fb27SDimitry Andric } 6806c3fb27SDimitry Andric 6906c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI __allocation_guard& operator=(const __allocation_guard& __other) = delete; 7006c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI __allocation_guard& operator=(__allocation_guard&& __other) _NOEXCEPT { 7106c3fb27SDimitry Andric if (std::addressof(__other) != this) { 7206c3fb27SDimitry Andric __destroy(); 7306c3fb27SDimitry Andric 7406c3fb27SDimitry Andric __alloc_ = std::move(__other.__alloc_); 7506c3fb27SDimitry Andric __n_ = __other.__n_; 7606c3fb27SDimitry Andric __ptr_ = __other.__ptr_; 7706c3fb27SDimitry Andric __other.__ptr_ = nullptr; 7806c3fb27SDimitry Andric } 7906c3fb27SDimitry Andric 8006c3fb27SDimitry Andric return *this; 81fe6060f1SDimitry Andric } 82fe6060f1SDimitry Andric 83*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _Pointer __release_ptr__allocation_guard84*cb14a3feSDimitry Andric __release_ptr() _NOEXCEPT { // not called __release() because it's a keyword in objective-c++ 85fe6060f1SDimitry Andric _Pointer __tmp = __ptr_; 86fe6060f1SDimitry Andric __ptr_ = nullptr; 87fe6060f1SDimitry Andric return __tmp; 88fe6060f1SDimitry Andric } 89fe6060f1SDimitry Andric __get__allocation_guard90*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _Pointer __get() const _NOEXCEPT { return __ptr_; } 91fe6060f1SDimitry Andric 92fe6060f1SDimitry Andric private: __destroy__allocation_guard93*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __destroy() _NOEXCEPT { 9406c3fb27SDimitry Andric if (__ptr_ != nullptr) { 9506c3fb27SDimitry Andric allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __n_); 9606c3fb27SDimitry Andric } 9706c3fb27SDimitry Andric } 9806c3fb27SDimitry Andric 99fe6060f1SDimitry Andric _Alloc __alloc_; 100fe6060f1SDimitry Andric _Size __n_; 101fe6060f1SDimitry Andric _Pointer __ptr_; 102fe6060f1SDimitry Andric }; 103fe6060f1SDimitry Andric 104fe6060f1SDimitry Andric _LIBCPP_END_NAMESPACE_STD 105fe6060f1SDimitry Andric 10606c3fb27SDimitry Andric _LIBCPP_POP_MACROS 10706c3fb27SDimitry Andric 108fe6060f1SDimitry Andric #endif // _LIBCPP___MEMORY_ALLOCATION_GUARD_H 109