Coverage Report

Created: 2024-07-18 11:41

test/zserio/TrackingAllocator.h
Line
Count
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
    ~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
    void allocated(void* ptr)
31
217
    {
32
217
        m_allocations.insert(ptr);
33
217
    }
34
35
    void deallocated(void* ptr)
36
217
    {
37
217
        EXPECT_TRUE(m_allocations.count(ptr) > 0);
38
217
        m_allocations.erase(ptr);
39
217
    }
40
41
    size_t numAllocs() const
42
253
    {
43
253
        return m_allocations.size();
44
253
    }
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
class TrackingAllocatorImpl
61
{
62
public:
63
    using value_type = typename std::allocator<T>::value_type;
64
    using pointer = typename std::allocator_traits<std::allocator<T>>::pointer;
65
66
    TrackingAllocatorImpl() :
67
            m_tracker(std::make_shared<detail::AllocationTracker>())
68
234
    {}
69
1.59k
    ~TrackingAllocatorImpl() = default;
70
71
1.03k
    TrackingAllocatorImpl(const TrackingAllocatorImpl&) = default;
72
49
    TrackingAllocatorImpl& operator=(const TrackingAllocatorImpl&) = default;
73
74
    TrackingAllocatorImpl(TrackingAllocatorImpl&&) = delete;
75
    TrackingAllocatorImpl& operator=(TrackingAllocatorImpl&&) = delete;
76
77
    template <typename Other>
78
    TrackingAllocatorImpl(const TrackingAllocatorImpl<Other>& other) :
79
            m_allocator(other.m_allocator),
80
            m_tracker(other.m_tracker)
81
331
    {}
82
83
    value_type* allocate(std::size_t size)
84
217
    {
85
217
        const auto ptr = m_allocator.allocate(size);
86
217
        m_tracker->allocated(ptr);
87
217
        return ptr;
88
217
    }
89
90
    void deallocate(value_type* memory, std::size_t size) noexcept
91
217
    {
92
217
        m_tracker->deallocated(memory);
93
217
        m_allocator.deallocate(memory, size);
94
217
    }
95
96
    bool operator==(const TrackingAllocatorImpl& other) const
97
101
    {
98
101
        return std::tie(m_tracker, m_allocator) == std::tie(other.m_tracker, other.m_allocator);
99
101
    }
100
101
    bool operator!=(const TrackingAllocatorImpl& other) const
102
7
    {
103
7
        return !(*this == other);
104
7
    }
105
106
    size_t numAllocs() const
107
253
    {
108
253
        return m_tracker->numAllocs();
109
253
    }
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
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
    using TrackingAllocatorImpl<T>::TrackingAllocatorImpl;
131
132
    TrackingAllocator select_on_container_copy_construction() const
133
30
    {
134
30
        return *this;
135
30
    }
136
};
137
138
/**
139
 * Non-propagating allocator. Ie. container copy/move does not propagate
140
 * the allocator.
141
 */
142
template <typename T>
143
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
    using TrackingAllocatorImpl<T>::TrackingAllocatorImpl;
150
151
    TrackingAllocatorNonProp select_on_container_copy_construction() const
152
27
    {
153
27
        return TrackingAllocatorNonProp();
154
27
    }
155
};
156
157
} // namespace zserio
158
159
#endif // ZSERIO_TRACKING_ALLOCATOR_H_INC