Coverage Report

Created: 2024-12-05 10:39

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
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