Coverage Report

Created: 2025-10-02 14:32

src/zserio/pmr/PolymorphicAllocator.h
Line
Count
Source
1
#ifndef ZSERIO_PMR_POLYMORPHIC_ALLOCATOR_H_INC
2
#define ZSERIO_PMR_POLYMORPHIC_ALLOCATOR_H_INC
3
4
#include <limits>
5
#include <type_traits>
6
#include <utility>
7
8
#include "zserio/Types.h"
9
#include "zserio/pmr/MemoryResource.h"
10
11
namespace zserio
12
{
13
namespace pmr
14
{
15
namespace detail
16
{
17
18
/**
19
 * Polymorphic allocator inspired by C++17 standard.
20
 */
21
template <class T = uint8_t>
22
class PolymorphicAllocatorBase
23
{
24
public:
25
    using value_type = T;
26
27
    // Following typedefs are only present for compatibility with older std. libraries, that does not fully
28
    // conform to C++11. [old-compiler-support]
29
    using pointer = value_type*;
30
    using const_pointer = const value_type*;
31
    using size_type = size_t;
32
    using difference_type = ptrdiff_t;
33
    using reference = value_type&;
34
    using const_reference = const value_type&;
35
36
    /**
37
     * Constructor.
38
     *
39
     * Note that this is intentionally non-explicit to allow to pass MemoryResource wherever
40
     * the PolymorphicAllocator is required.
41
     *
42
     * \param resource Memory resource. According to the C++ standard the resource may not be NULL. Since it
43
     *                 implies undefined behaviour, we define a non-standard extension here. When the resource
44
     *                 is NULL, getDefaultResource() is used instead!
45
     */
46
    PolymorphicAllocatorBase(MemoryResource* resource = getDefaultResource()) noexcept :
47
            m_resource(resource != nullptr ? resource : getDefaultResource()) // non-standard extension
48
142
    {}
49
50
    /**
51
     * Method generated by default.
52
     * \{
53
     */
54
    ~PolymorphicAllocatorBase() = default;
55
56
    PolymorphicAllocatorBase(const PolymorphicAllocatorBase& other) noexcept = default;
57
    PolymorphicAllocatorBase& operator=(const PolymorphicAllocatorBase& other) noexcept = default;
58
59
    PolymorphicAllocatorBase(PolymorphicAllocatorBase&& other) noexcept = default;
60
    PolymorphicAllocatorBase& operator=(PolymorphicAllocatorBase&& other) noexcept = default;
61
    /**
62
     * \}
63
     */
64
65
    /**
66
     * Copy constructor from PolymorphicAllocator with another value_type.
67
     *
68
     * \param other Other PolymorphicAllocator.
69
     */
70
    template <class U>
71
    PolymorphicAllocatorBase(const PolymorphicAllocatorBase<U>& other) noexcept :
72
            m_resource(other.resource())
73
402
    {}
74
75
    /**
76
     * Assignment operator from PolymorphicAllocator with another value_type.
77
     *
78
     * \param other Other PolymorphicAllocator.
79
     */
80
    template <class U>
81
    PolymorphicAllocatorBase& operator=(const PolymorphicAllocatorBase<U>& other) noexcept
82
    {
83
        m_resource = other.resource();
84
        return *this;
85
    }
86
87
    /**
88
     * Allocates memory for n values.
89
     *
90
     * \param size Number of values to allocate memory for.
91
     */
92
    value_type* allocate(size_t size)
93
196
    {
94
196
        return static_cast<value_type*>(m_resource->allocate(size * sizeof(value_type), alignof(value_type)));
95
196
    }
96
97
    /**
98
     * Deallocates memory for n values.
99
     *
100
     * \param memory Pointer to the memory to deallocate.
101
     * \param size Number of values held by the memory pointed to by memory.
102
     *         Shall be the same size as was used for allocation of memory.
103
     */
104
    void deallocate(value_type* memory, size_t size) noexcept
105
196
    {
106
196
        m_resource->deallocate(memory, size * sizeof(value_type), alignof(value_type));
107
196
    }
108
109
    /**
110
     * Gets the underlying memory resource.
111
     */
112
    MemoryResource* resource() const noexcept
113
554
    {
114
554
        return m_resource;
115
554
    }
116
117
    /**
118
     * Constructs an object in allocated memory.
119
     *
120
     * \param ptr Pointer to memory where the object will be constructed.
121
     * \param args Parameters to be forwarded to the object constructor.
122
     * \note This is only necessary for compatibility with older std. libraries, that does not fully
123
     * conform to C++11. [old-compiler-support]
124
     */
125
    template <typename U, typename... Args>
126
    void construct(U* ptr, Args&&... args) noexcept(
127
            noexcept(new (static_cast<void*>(ptr)) U(std::forward<Args>(args)...)))
128
214
    {
129
214
        new (static_cast<void*>(ptr)) U(std::forward<Args>(args)...);
130
214
    }
131
132
    /**
133
     * Destroys an object
134
     *
135
     * \param ptr Pointer to the object to be destroyed.
136
     * \note This is only necessary for compatibility with older std. libraries, that does not fully
137
     * conform to C++11. [old-compiler-support]
138
     */
139
    template <typename U>
140
    void destroy(U* ptr) noexcept(noexcept(ptr->~U()))
141
214
    {
142
214
        ptr->~U();
143
214
    }
144
145
    /**
146
     * Returns theoretical maximal limit for allocation.
147
     *
148
     * \return Theoretical maximal limit for allocation.
149
     * \note This is only necessary for compatibility with older std. libraries, that does not fully
150
     * conform to C++11. [old-compiler-support]
151
     */
152
    size_type max_size() const noexcept
153
129
    {
154
129
        return std::numeric_limits<size_type>::max() / sizeof(value_type);
155
129
    }
156
157
private:
158
    MemoryResource* m_resource;
159
};
160
161
template <class T, class U>
162
bool operator==(const PolymorphicAllocatorBase<T>& lhs, const PolymorphicAllocatorBase<U>& rhs) noexcept
163
68
{
164
68
    return *lhs.resource() == *rhs.resource();
165
68
}
166
167
template <class T, class U>
168
bool operator!=(const PolymorphicAllocatorBase<T>& lhs, const PolymorphicAllocatorBase<U>& rhs) noexcept
169
6
{
170
6
    return !(lhs == rhs);
171
6
}
172
173
} // namespace detail
174
175
/**
176
 * Non-propagating version of the polymorphic allocator. This allocator behaves as the polymorphic_allocator
177
 * from C++17.
178
 */
179
template <class T = uint8_t>
180
class PolymorphicAllocator : public detail::PolymorphicAllocatorBase<T>
181
{
182
public:
183
    using detail::PolymorphicAllocatorBase<T>::PolymorphicAllocatorBase;
184
185
    using propagate_on_container_copy_assignment = std::false_type;
186
    using propagate_on_container_move_assignment = std::false_type;
187
    using propagate_on_container_swap = std::false_type;
188
189
    /**
190
     * Returns instance of the allocator to be used when a container gets copied.
191
     */
192
    PolymorphicAllocator select_on_container_copy_construction() const
193
1
    {
194
1
        return PolymorphicAllocator();
195
1
    }
196
197
    /**
198
     * Rebind template.
199
     * \note This is only necessary for compatibility with older std. libraries, that does not fully
200
     * conform to C++11. [old-compiler-support]
201
     */
202
    template <typename U>
203
    struct rebind
204
    {
205
        using other = PolymorphicAllocator<U>;
206
    };
207
};
208
209
/**
210
 * Propagating version of the polymorphic allocator. This one is propagated on container copy and assignment.
211
 */
212
template <class T = uint8_t>
213
class PropagatingPolymorphicAllocator : public detail::PolymorphicAllocatorBase<T>
214
{
215
public:
216
    using detail::PolymorphicAllocatorBase<T>::PolymorphicAllocatorBase;
217
218
    using propagate_on_container_copy_assignment = std::true_type;
219
    using propagate_on_container_move_assignment = std::true_type;
220
    using propagate_on_container_swap = std::true_type;
221
222
    /**
223
     * Returns instance of the allocator to be used when a container gets copied.
224
     */
225
    PropagatingPolymorphicAllocator select_on_container_copy_construction() const
226
29
    {
227
29
        return *this;
228
29
    }
229
230
    /**
231
     * Rebind template.
232
     * \note This is only necessary for compatibility with older std. libraries, that does not fully
233
     * conform to C++11. [old-compiler-support]
234
     */
235
    template <typename U>
236
    struct rebind
237
    {
238
        using other = PropagatingPolymorphicAllocator<U>;
239
    };
240
};
241
242
} // namespace pmr
243
} // namespace zserio
244
245
#endif // ZSERIO_PMR_POLYMORPHIC_ALLOCATOR_H_INC