xref: /freebsd-src/contrib/llvm-project/libcxx/include/__memory/allocation_guard.h (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
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