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