Coverage Report

Created: 2023-12-13 14:58

src/zserio/UniquePtr.h
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