GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: test/zserio/TrackingAllocator.h Lines: 45 45 100.0 %
Date: 2023-12-13 14:51:09 Branches: 6 20 30.0 %

Line Branch Exec Source
1
#ifndef ZSERIO_TRACKING_ALLOCATOR_H_INC
2
#define ZSERIO_TRACKING_ALLOCATOR_H_INC
3
4
#include <memory>
5
#include <set>
6
7
#include "gtest/gtest.h"
8
9
namespace zserio
10
{
11
12
namespace detail
13
{
14
15
class AllocationTracker
16
{
17
public:
18
234
    AllocationTracker() = default;
19
234
    ~AllocationTracker()
20
234
    {
21
234
        EXPECT_TRUE(m_allocations.empty());
22
234
    }
23
24
    AllocationTracker(const AllocationTracker&) = default;
25
    AllocationTracker& operator=(const AllocationTracker&) = default;
26
27
    AllocationTracker(AllocationTracker&&) = default;
28
    AllocationTracker& operator=(AllocationTracker&&) = default;
29
30
217
    void allocated(void* ptr)
31
    {
32
217
        m_allocations.insert(ptr);
33
217
    }
34
35
217
    void deallocated(void* ptr)
36
    {
37



217
        EXPECT_TRUE(m_allocations.count(ptr) > 0);
38
217
        m_allocations.erase(ptr);
39
217
    }
40
41
253
    size_t numAllocs() const
42
    {
43
253
        return m_allocations.size();
44
    }
45
46
private:
47
    std::set<void*> m_allocations;
48
};
49
50
} // namespace detail
51
52
/**
53
 * Stateful allocator that tracks the allocations. Used in unit tests.
54
 * Every copy of an allocator must be able to deallocate what any of the other copies
55
 * allocated. This allocator simulates this behavior, all copies shares the same tracker,
56
 * so it can check if the allocators are used correctly (ie. no allocations leaks,
57
 * every allocation is deallocated by the same allocator or its copy).
58
 */
59
template <typename T>
60
49
class TrackingAllocatorImpl
61
{
62
public:
63
    using value_type = typename std::allocator<T>::value_type;
64
    using pointer = typename std::allocator<T>::pointer;
65
66
234
    TrackingAllocatorImpl()
67

234
        : m_tracker(std::make_shared<detail::AllocationTracker>())
68
234
    {}
69
1595
    ~TrackingAllocatorImpl() = default;
70
71
1028
    TrackingAllocatorImpl(const TrackingAllocatorImpl&) = default;
72
    TrackingAllocatorImpl& operator=(const TrackingAllocatorImpl&) = default;
73
74
    TrackingAllocatorImpl(TrackingAllocatorImpl&&) = delete;
75
    TrackingAllocatorImpl& operator=(TrackingAllocatorImpl&&) = delete;
76
77
    template <typename Other>
78
333
    TrackingAllocatorImpl(const TrackingAllocatorImpl<Other>& other) :
79
        m_allocator(other.m_allocator),
80
333
        m_tracker(other.m_tracker)
81
333
    {}
82
83
217
    value_type* allocate(std::size_t n)
84
    {
85
217
        const auto ptr = m_allocator.allocate(n);
86
217
        m_tracker->allocated(ptr);
87
217
        return ptr;
88
    }
89
90
217
    void deallocate(value_type* p, std::size_t n) noexcept
91
    {
92
217
        m_tracker->deallocated(p);
93
217
        m_allocator.deallocate(p, n);
94
217
    }
95
96
101
    bool operator==(const TrackingAllocatorImpl& other) const
97
    {
98
101
        return std::tie(m_tracker, m_allocator) == std::tie(other.m_tracker, other.m_allocator);
99
    }
100
101
7
    bool operator!=(const TrackingAllocatorImpl& other) const
102
    {
103
7
        return !(*this == other);
104
    }
105
106
253
    size_t numAllocs() const
107
    {
108
253
        return m_tracker->numAllocs();
109
    }
110
111
    template <typename U>
112
    friend class TrackingAllocatorImpl;
113
114
private:
115
    std::allocator<T> m_allocator;
116
    std::shared_ptr<detail::AllocationTracker> m_tracker;
117
};
118
119
/**
120
 * Propagating allocator. Ie. container copy/move propagates also
121
 * the allocator.
122
 */
123
template <typename T>
124
1585
class TrackingAllocator : public TrackingAllocatorImpl<T>
125
{
126
public:
127
    using propagate_on_container_copy_assignment = std::true_type;
128
    using propagate_on_container_move_assignment = std::true_type;
129
130
159
    using TrackingAllocatorImpl<T>::TrackingAllocatorImpl;
131
132
30
    TrackingAllocator select_on_container_copy_construction() const
133
    {
134
30
        return *this;
135
    }
136
};
137
138
/**
139
 * Non-propagating allocator. Ie. container copy/move does not propagate
140
 * the allocator.
141
 */
142
template <typename T>
143
1321
class TrackingAllocatorNonProp : public TrackingAllocatorImpl<T>
144
{
145
public:
146
    using propagate_on_container_copy_assignment = std::false_type;
147
    using propagate_on_container_move_assignment = std::false_type;
148
149
174
    using TrackingAllocatorImpl<T>::TrackingAllocatorImpl;
150
151
27
    TrackingAllocatorNonProp select_on_container_copy_construction() const
152
    {
153
27
        return TrackingAllocatorNonProp();
154
    }
155
};
156
157
} // namespace zserio
158
159
#endif // ZSERIO_TRACKING_ALLOCATOR_H_INC