GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/zserio/UniquePtr.h Lines: 25 25 100.0 %
Date: 2023-12-13 14:51:09 Branches: 88 194 45.4 %

Line Branch Exec 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
17
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
    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
75
    UniquePtrDeleter() :
49

75
            UniquePtrDeleter(ALLOC_U())
50
    {
51
75
    }
52
53
    /**
54
     * Constructor from given allocator.
55
     */
56
    template <typename ALLOC_U = ALLOC_T>
57
251
    UniquePtrDeleter(const ALLOC_U& allocator) :
58
251
            AllocatorHolder<ALLOC_T>(allocator)
59
    {
60
        static_assert(std::is_same<allocator_type, RebindAlloc<ALLOC_U, T>>::value,
61
                "UniquePtrDeleter requires same allocator in constructor!");
62
251
    }
63
64
    /**
65
     * Constructor from deleter to another type.
66
     */
67
    template <typename ALLOC_U>
68
29
    UniquePtrDeleter(const UniquePtrDeleter<ALLOC_U>& deleter) :
69


29
            UniquePtrDeleter(deleter.get_allocator())
70
29
    {}
71
72
92
    void operator()(T* ptr)
73
    {
74





184
        allocator_type alloc = this->get_allocator();
75
        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
93
allocate_unique(const ALLOC& allocator, Args&& ...args)
103
{
104
    using Allocator = RebindAlloc<ALLOC, T>;
105
    using AllocTraits = std::allocator_traits<Allocator>;
106
107
186
    Allocator typedAllocator = allocator;
108









93
    typename AllocTraits::pointer ptr = AllocTraits::allocate(typedAllocator, 1);
109
    try
110
    {
111











93
        AllocTraits::construct(typedAllocator, std::addressof(*ptr), std::forward<Args>(args)...);
112









184
        return zserio::unique_ptr<T, Allocator>(std::addressof(*ptr), typedAllocator);
113
    }
114
2
    catch (...)
115
    {
116


1
        AllocTraits::deallocate(typedAllocator, ptr, 1);
117
1
        throw;
118
    }
119
}
120
121
} // namespace zserio
122
123
#endif // ZSERIO_UNIQUE_PTR_H_INC