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 | 404 | ~UniquePtrDeleter() = default; |
28 | | |
29 | 157 | 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 | 77 | {} |
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 | 261 | { |
60 | 261 | static_assert(std::is_same<allocator_type, RebindAlloc<ALLOC_U, T>>::value, |
61 | 261 | "UniquePtrDeleter requires same allocator in constructor!"); |
62 | 261 | } |
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 | 33 | {} |
71 | | |
72 | | void operator()(T* ptr) |
73 | 96 | { |
74 | 96 | allocator_type alloc = this->get_allocator(); |
75 | 96 | using AllocTraits = std::allocator_traits<allocator_type>; |
76 | 96 | AllocTraits::destroy(alloc, std::addressof(*ptr)); |
77 | 96 | AllocTraits::deallocate(alloc, ptr, 1); |
78 | 96 | } |
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>> allocate_unique(const ALLOC& allocator, Args&&... args) |
102 | 97 | { |
103 | 97 | using Allocator = RebindAlloc<ALLOC, T>; |
104 | 97 | using AllocTraits = std::allocator_traits<Allocator>; |
105 | | |
106 | 97 | Allocator typedAllocator = allocator; |
107 | 97 | typename AllocTraits::pointer ptr = AllocTraits::allocate(typedAllocator, 1); |
108 | 97 | try |
109 | 97 | { |
110 | 97 | AllocTraits::construct(typedAllocator, std::addressof(*ptr), std::forward<Args>(args)...); |
111 | 97 | return zserio::unique_ptr<T, Allocator>(std::addressof(*ptr), typedAllocator); |
112 | 97 | } |
113 | 97 | catch (...) |
114 | 97 | { |
115 | 1 | AllocTraits::deallocate(typedAllocator, ptr, 1); |
116 | 1 | throw; |
117 | 1 | } |
118 | 97 | } |
119 | | |
120 | | } // namespace zserio |
121 | | |
122 | | #endif // ZSERIO_UNIQUE_PTR_H_INC |