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