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  |