Line | Count | Source |
1 | | #ifndef ZSERIO_UNIQUE_PTR_H_INC |
2 | | #define ZSERIO_UNIQUE_PTR_H_INC |
3 | | |
4 | | #include <memory> |
5 | | #include <type_traits> |
6 | | |
7 | | #include "zserio/AllocatorHolder.h" |
8 | | #include "zserio/RebindAlloc.h" |
9 | | |
10 | | namespace zserio |
11 | | { |
12 | | |
13 | | namespace detail |
14 | | { |
15 | | |
16 | | /** |
17 | | * Custom deleter to ensure proper deallocation of the unique_ptr. |
18 | | */ |
19 | | template <class ALLOC_T> |
20 | | struct UniquePtrDeleter : public AllocatorHolder<ALLOC_T> |
21 | | { |
22 | | using allocator_type = ALLOC_T; |
23 | | using T = typename allocator_type::value_type; |
24 | | |
25 | | /** Method generated by default. */ |
26 | | /** \{ */ |
27 | 242 | ~UniquePtrDeleter() = default; |
28 | | |
29 | 124 | UniquePtrDeleter(UniquePtrDeleter&& other) = default; |
30 | 17 | UniquePtrDeleter& operator=(UniquePtrDeleter&& other) = default; |
31 | | /** |
32 | | * \} |
33 | | */ |
34 | | |
35 | | /** |
36 | | * Copying is disallowed! |
37 | | * \{ |
38 | | */ |
39 | | UniquePtrDeleter(const UniquePtrDeleter& other) = delete; |
40 | | UniquePtrDeleter& operator=(const UniquePtrDeleter& other) = delete; |
41 | | /** |
42 | | * \} |
43 | | */ |
44 | | |
45 | | /** |
46 | | * Empty constructor. |
47 | | */ |
48 | | template <typename ALLOC_U = ALLOC_T> |
49 | | UniquePtrDeleter() : |
50 | | UniquePtrDeleter(ALLOC_U()) |
51 | | {} |
52 | | |
53 | | /** |
54 | | * Constructor from given allocator. |
55 | | */ |
56 | | template <typename ALLOC_U = ALLOC_T> |
57 | | UniquePtrDeleter(const ALLOC_U& allocator) : |
58 | | AllocatorHolder<ALLOC_T>(allocator) |
59 | 118 | { |
60 | 118 | static_assert(std::is_same<allocator_type, RebindAlloc<ALLOC_U, T>>::value, |
61 | 118 | "UniquePtrDeleter requires same allocator in constructor!"); |
62 | 118 | } |
63 | | |
64 | | /** |
65 | | * DISABLED - Constructor from deleter to another type. |
66 | | * |
67 | | * This was originally used in JsonReader to cast polymorphic |
68 | | * types but it leads to only releasing memory of the base class and |
69 | | * it is correctly flagged by ASAN in clang-21. For polymorphic types |
70 | | * use std::shared_ptr. |
71 | | */ |
72 | | template <typename ALLOC_U> |
73 | | UniquePtrDeleter(const UniquePtrDeleter<ALLOC_U>& deleter) = delete; |
74 | | |
75 | | void operator()(T* ptr) |
76 | 63 | { |
77 | 63 | allocator_type alloc = this->get_allocator(); |
78 | 63 | using AllocTraits = std::allocator_traits<allocator_type>; |
79 | 63 | AllocTraits::destroy(alloc, std::addressof(*ptr)); |
80 | 63 | AllocTraits::deallocate(alloc, ptr, 1); |
81 | 63 | } |
82 | | }; |
83 | | |
84 | | } // namespace detail |
85 | | |
86 | | /** |
87 | | * Typedef to std::unique_ptr provided for convenience - using std::allocator. |
88 | | * |
89 | | * Uses custom deleter to ensure proper deallocation. |
90 | | */ |
91 | | template <typename T, typename ALLOC = std::allocator<T>> |
92 | | using unique_ptr = std::unique_ptr<T, detail::UniquePtrDeleter<ALLOC>>; |
93 | | |
94 | | /** |
95 | | * Allocates memory for an object of type T using given allocator and constructs it passing args to its |
96 | | * constructor. |
97 | | * |
98 | | * \param allocator Allocator to use. |
99 | | * \param args List of elements passed to T's constructor. |
100 | | * |
101 | | * \return Object of type zserio::unique_ptr<T, ALLOC> that owns and stores a pointer to the constructed object. |
102 | | */ |
103 | | template <typename T, typename ALLOC, class... Args> |
104 | | zserio::unique_ptr<T, RebindAlloc<ALLOC, T>> allocate_unique(const ALLOC& allocator, Args&&... args) |
105 | 64 | { |
106 | 64 | using Allocator = RebindAlloc<ALLOC, T>; |
107 | 64 | using AllocTraits = std::allocator_traits<Allocator>; |
108 | | |
109 | 64 | Allocator typedAllocator = allocator; |
110 | 64 | typename AllocTraits::pointer ptr = AllocTraits::allocate(typedAllocator, 1); |
111 | 64 | try |
112 | 64 | { |
113 | 64 | AllocTraits::construct(typedAllocator, std::addressof(*ptr), std::forward<Args>(args)...); |
114 | 64 | return zserio::unique_ptr<T, Allocator>(std::addressof(*ptr), typedAllocator); |
115 | 64 | } |
116 | 64 | catch (...) |
117 | 64 | { |
118 | 1 | AllocTraits::deallocate(typedAllocator, ptr, 1); |
119 | 1 | throw; |
120 | 1 | } |
121 | 64 | } |
122 | | |
123 | | } // namespace zserio |
124 | | |
125 | | #endif // ZSERIO_UNIQUE_PTR_H_INC |