Sequoia
Loading...
Searching...
No Matches
AllocationTestDiagnosticsUtilities.hpp
Go to the documentation of this file.
1
2// Copyright Oliver J. Rosten 2020. //
3// Distributed under the GNU GENERAL PUBLIC LICENSE, Version 3.0. //
4// (See accompanying file LICENSE.md or copy at //
5// https://www.gnu.org/licenses/gpl-3.0.en.html) //
7
8#pragma once
9
13
14#include <vector>
15
16namespace sequoia::testing
17{
18 template<class T=int, class Allocator=std::allocator<int>>
20 {
21 using allocator_type = Allocator;
22
23 inefficient_equality(std::initializer_list<T> list) : x{list} {}
24
25 inefficient_equality(std::initializer_list<T> list, const allocator_type& a) : x(list, a) {}
26
28
29 inefficient_equality(const inefficient_equality& other, const allocator_type& a) : x(other.x, a) {}
30
31 inefficient_equality(inefficient_equality&&) noexcept = default;
32
33 inefficient_equality(inefficient_equality&& other, const allocator_type& a) : x(std::move(other.x), a) {}
34
35 inefficient_equality& operator=(const inefficient_equality&) = default;
36
37 inefficient_equality& operator=(inefficient_equality&&) = default;
38
39 friend void swap(inefficient_equality& lhs, inefficient_equality& rhs)
40 {
41 std::ranges::swap(lhs.x, rhs.x);
42 }
43
44 std::vector<T, Allocator> x{};
45
46 [[nodiscard]]
47 friend bool operator==(const inefficient_equality lhs, const inefficient_equality rhs) noexcept
48 {
49 return lhs.x == rhs.x;
50 }
51
52 [[nodiscard]]
53 friend bool operator!=(const inefficient_equality& lhs, const inefficient_equality& rhs) noexcept
54 {
55 return lhs.x != rhs.x;
56 }
57
58 template<class Stream>
59 friend Stream& operator<<(Stream& s, const inefficient_equality& b)
60 {
61 for(auto i : b.x) s << i << ' ';
62 return s;
63 }
64 };
65
66 template<class T, class Allocator>
68 {
69 using allocation_count_shifter<int>::shift;
70
71 static int shift(int count, const alloc_prediction<comparison_flavour::equality>&) noexcept
72 {
73 if constexpr(with_msvc_v && (iterator_debug_level() > 0))
74 {
75 if(count > 1) return count + 2;
76 }
77
78 return count;
79 }
80 };
81
82 template<class T=int, class Allocator=std::allocator<int>>
84 {
85 using allocator_type = Allocator;
86
87 inefficient_inequality(std::initializer_list<T> list) : x{list} {}
88
89 inefficient_inequality(std::initializer_list<T> list, const allocator_type& a) : x(list, a) {}
90
92
93 inefficient_inequality(const inefficient_inequality& other, const allocator_type& a) : x(other.x, a) {}
94
96
97 inefficient_inequality(inefficient_inequality&& other, const allocator_type& a) : x(std::move(other.x), a) {}
98
99 inefficient_inequality& operator=(const inefficient_inequality&) = default;
100
101 inefficient_inequality& operator=(inefficient_inequality&&) = default;
102
103 friend void swap(inefficient_inequality& lhs, inefficient_inequality& rhs)
104 {
105 std::ranges::swap(lhs.x, rhs.x);
106 }
107
108 std::vector<T, Allocator> x{};
109
110 [[nodiscard]]
111 friend bool operator==(const inefficient_inequality& lhs, const inefficient_inequality& rhs) noexcept
112 {
113 return lhs.x == rhs.x;
114 }
115
116 [[nodiscard]]
117 friend bool operator!=(const inefficient_inequality lhs, const inefficient_inequality rhs) noexcept
118 {
119 return !(rhs == lhs);
120 }
121
122 template<class Stream>
123 friend Stream& operator<<(Stream& s, const inefficient_inequality& b)
124 {
125 for(auto i : b.x) s << i << ' ';
126 return s;
127 }
128 };
129
130 template<class T, class Allocator>
132 {
133 using allocation_count_shifter<int>::shift;
134
135 static int shift(int count, const alloc_prediction<comparison_flavour::inequality>&) noexcept
136 {
137 if constexpr(with_msvc_v && (iterator_debug_level() > 0))
138 {
139 if(count > 1) return count + 2;
140 }
141
142 return count;
143 }
144 };
145
146 template<class T=int, class Allocator=std::allocator<int>>
148 {
149 using allocator_type = Allocator;
150
151 inefficient_copy(std::initializer_list<T> list) : x{list} {}
152
153 inefficient_copy(std::initializer_list<T> list, const allocator_type& a) : x(list, a) {}
154
155 inefficient_copy(const inefficient_copy& other) : x(other.x.get_allocator())
156 {
157 x.reserve(1);
158 x.shrink_to_fit();
159 x.reserve(other.x.size());
160 std::copy(other.x.cbegin(), other.x.cend(), std::back_inserter(x));
161 }
162
163 inefficient_copy(const inefficient_copy& other, const allocator_type& a)
164 : x(other.x, a)
165 {}
166
167 inefficient_copy(inefficient_copy&&) noexcept = default;
168
169 inefficient_copy(inefficient_copy&& other, const allocator_type& a) : x(std::move(other.x), a)
170 {}
171
172 inefficient_copy& operator=(const inefficient_copy&) = default;
173
174 inefficient_copy& operator=(inefficient_copy&&) = default;
175
176 friend void swap(inefficient_copy& lhs, inefficient_copy& rhs)
177 {
178 std::ranges::swap(lhs.x, rhs.x);
179 }
180
181 std::vector<T, Allocator> x{};
182
183 [[nodiscard]]
184 friend bool operator==(const inefficient_copy& lhs, const inefficient_copy& rhs) noexcept
185 {
186 return lhs.x == rhs.x;
187 }
188
189 [[nodiscard]]
190 friend bool operator!=(const inefficient_copy& lhs, const inefficient_copy& rhs) noexcept
191 {
192 return !(lhs == rhs);
193 }
194
195 template<class Stream>
196 friend Stream& operator<<(Stream& s, const inefficient_copy& b)
197 {
198 for(auto i : b.x) s << i << ' ';
199 return s;
200 }
201 };
202
203 template<class T=int, class Allocator=std::allocator<int>>
205 {
206 using allocator_type = Allocator;
207
208 inefficient_para_copy(std::initializer_list<T> list) : x{list} {}
209
210 inefficient_para_copy(std::initializer_list<T> list, const allocator_type& a) : x(list, a) {}
211
213
214 inefficient_para_copy(const inefficient_para_copy& other, const allocator_type& a)
215 : x(a)
216 {
217 x.reserve(1);
218 x.shrink_to_fit();
219 x.reserve(other.x.size());
220 std::copy(other.x.cbegin(), other.x.cend(), std::back_inserter(x));
221 }
222
223 inefficient_para_copy(inefficient_para_copy&&) noexcept = default;
224
225 inefficient_para_copy(inefficient_para_copy&& other, const allocator_type& a) : x(std::move(other.x), a) {}
226
227 inefficient_para_copy& operator=(const inefficient_para_copy&) = default;
228
229 inefficient_para_copy& operator=(inefficient_para_copy&&) = default;
230
231 friend void swap(inefficient_para_copy& lhs, inefficient_para_copy& rhs)
232 {
233 std::ranges::swap(lhs.x, rhs.x);
234 }
235
236 std::vector<T, Allocator> x{};
237
238 [[nodiscard]]
239 friend bool operator==(const inefficient_para_copy& lhs, const inefficient_para_copy& rhs) noexcept
240 {
241 return lhs.x == rhs.x;
242 }
243
244 [[nodiscard]]
245 friend bool operator!=(const inefficient_para_copy& lhs, const inefficient_para_copy& rhs) noexcept
246 {
247 return !(lhs == rhs);
248 }
249
250 template<class Stream>
251 friend Stream& operator<<(Stream& s, const inefficient_para_copy& b)
252 {
253 for(auto i : b.x) s << i << ' ';
254 return s;
255 }
256 };
257
258 template<class T=int, class Allocator=std::allocator<int>>
260 {
261 using allocator_type = Allocator;
262
263 inefficient_move(std::initializer_list<T> list) : x{list} {}
264
265 inefficient_move(std::initializer_list<T> list, const allocator_type& a) : x(list, a) {}
266
267 inefficient_move(const inefficient_move& other) = default;
268
269 inefficient_move(const inefficient_move& other, const allocator_type& a)
270 : x(other.x, a)
271 {}
272
273 inefficient_move(inefficient_move&& other) : x{std::move(other.x)}
274 {
275 x.reserve(x.capacity() + 1);
276 }
277
278 inefficient_move(inefficient_move&& other, const allocator_type& a) : x(std::move(other.x), a) {}
279
280 inefficient_move& operator=(const inefficient_move&) = default;
281
282 inefficient_move& operator=(inefficient_move&&) = default;
283
284 friend void swap(inefficient_move& lhs, inefficient_move& rhs)
285 {
286 std::ranges::swap(lhs.x, rhs.x);
287 }
288
289 std::vector<T, Allocator> x{};
290
291 [[nodiscard]]
292 friend bool operator==(const inefficient_move& lhs, const inefficient_move& rhs) noexcept
293 {
294 return lhs.x == rhs.x;
295 }
296
297 [[nodiscard]]
298 friend bool operator!=(const inefficient_move& lhs, const inefficient_move& rhs) noexcept
299 {
300 return !(lhs == rhs);
301 }
302
303 template<class Stream>
304 friend Stream& operator<<(Stream& s, const inefficient_move& b)
305 {
306 for(auto i : b.x) s << i << ' ';
307 return s;
308 }
309 };
310
311 template<class T=int, class Allocator=std::allocator<int>>
313 {
314 using allocator_type = Allocator;
315
316 inefficient_para_move(std::initializer_list<T> list) : x{list} {}
317
318 inefficient_para_move(std::initializer_list<T> list, const allocator_type& a) : x(list, a) {}
319
320 inefficient_para_move(const inefficient_para_move& other) = default;
321
322 inefficient_para_move(const inefficient_para_move& other, const allocator_type& a)
323 : x(other.x, a)
324 {}
325
327
328 inefficient_para_move(inefficient_para_move&& other, const allocator_type& a) : x(std::move(other.x), a)
329 {
330 x.reserve(x.capacity() + 1);
331 }
332
333 inefficient_para_move& operator=(const inefficient_para_move&) = default;
334
335 inefficient_para_move& operator=(inefficient_para_move&&) = default;
336
337 friend void swap(inefficient_para_move& lhs, inefficient_para_move& rhs)
338 {
339 std::ranges::swap(lhs.x, rhs.x);
340 }
341
342 std::vector<T, Allocator> x{};
343
344 [[nodiscard]]
345 friend bool operator==(const inefficient_para_move& lhs, const inefficient_para_move& rhs) noexcept
346 {
347 return lhs.x == rhs.x;
348 }
349
350 [[nodiscard]]
351 friend bool operator!=(const inefficient_para_move& lhs, const inefficient_para_move& rhs) noexcept
352 {
353 return !(lhs == rhs);
354 }
355
356 template<class Stream>
357 friend Stream& operator<<(Stream& s, const inefficient_para_move& b)
358 {
359 for(auto i : b.x) s << i << ' ';
360 return s;
361 }
362 };
363
364 template<class T=int, class Allocator=std::allocator<int>>
366 {
367 using allocator_type = Allocator;
368
369 inefficient_serialization(std::initializer_list<T> list) : x{list} {}
370
371 inefficient_serialization(std::initializer_list<T> list, const allocator_type& a) : x{list, a} {}
372
373 inefficient_serialization(const allocator_type& a) : x(a) {}
374
376
377 inefficient_serialization(const inefficient_serialization& other, const allocator_type& a) : x(other.x, a) {}
378
380
381 inefficient_serialization(inefficient_serialization&& other, const allocator_type& a) : x(std::move(other.x), a) {}
382
383 inefficient_serialization& operator=(const inefficient_serialization&) = default;
384
386
387 void swap(inefficient_serialization& other) noexcept(noexcept(std::ranges::swap(this->x, other.x)))
388 {
389 std::ranges::swap(x, other.x);
390 }
391
392 friend void swap(inefficient_serialization& lhs, inefficient_serialization& rhs)
393 noexcept(noexcept(lhs.swap(rhs)))
394 {
395 lhs.swap(rhs);
396 }
397
398 std::vector<T, Allocator> x{};
399
400 [[nodiscard]]
401 friend bool operator==(const inefficient_serialization&, const inefficient_serialization&) noexcept = default;
402
403 [[nodiscard]]
404 friend bool operator!=(const inefficient_serialization&, const inefficient_serialization&) noexcept = default;
405
406 template<class Stream>
407 friend Stream& operator<<(Stream& s, const inefficient_serialization b)
408 {
409 for(auto i : b.x) s << i << ' ';
410 return s;
411 }
412
413 template<class Stream>
414 friend Stream& operator>>(Stream& s, inefficient_serialization& b)
415 {
416 b.x.clear();
417
418 int i{};
419 while(s >> i)
420 {
421 b.x.push_back(i);
422 }
423
424 return s;
425 }
426 };
427
428 template<class T, class Allocator>
430 {
431 using allocation_count_shifter<int>::shift;
432
433 static int shift(int count, const alloc_prediction<null_allocation_event::serialization>&)
434 {
435 if constexpr(with_msvc_v && (iterator_debug_level() > 0))
436 {
437 if(count) return count + 1;
438 }
439
440 return count;
441 }
442 };
443
444 template<class T = int, class Allocator = std::allocator<int>>
446 {
447 using allocator_type = Allocator;
448
449 broken_copy_assignment_propagation(std::initializer_list<T> list) : x{list} {}
450
451 broken_copy_assignment_propagation(std::initializer_list<T> list, const allocator_type& a) : x{list, a} {}
452
453 broken_copy_assignment_propagation(const allocator_type& a) : x(a) {}
454
456
457 broken_copy_assignment_propagation(const broken_copy_assignment_propagation& other, const allocator_type& a) : x(other.x, a) {}
458
460
461 broken_copy_assignment_propagation(broken_copy_assignment_propagation&& other, const allocator_type& a) : x(std::move(other.x), a) {}
462
463 // Broken if propagation on copy assignment is not the same as for move
465 {
466 auto tmp{other};
467 *this = std::move(tmp);
468
469 return *this;
470 }
471
473
474 void swap(broken_copy_assignment_propagation& other) noexcept(noexcept(std::ranges::swap(this->x, other.x)))
475 {
476 std::ranges::swap(x, other.x);
477 }
478
480 noexcept(noexcept(lhs.swap(rhs)))
481 {
482 lhs.swap(rhs);
483 }
484
485 std::vector<T, Allocator> x{};
486
487 [[nodiscard]]
488 friend bool operator==(const broken_copy_assignment_propagation&, const broken_copy_assignment_propagation&) noexcept = default;
489
490 [[nodiscard]]
491 friend bool operator!=(const broken_copy_assignment_propagation&, const broken_copy_assignment_propagation&) noexcept = default;
492
493 template<class Stream>
494 friend Stream& operator<<(Stream& s, const broken_copy_assignment_propagation& b)
495 {
496 for(auto i : b.x) s << i << ' ';
497 return s;
498 }
499
500 template<class Stream>
501 friend Stream& operator>>(Stream& s, broken_copy_assignment_propagation& b)
502 {
503 b.x.clear();
504
505 int i{};
506 while(s >> i)
507 {
508 b.x.push_back(i);
509 }
510
511 return s;
512 }
513 };
514
515 template<class T, bool PropagateCopy, bool PropagateMove, bool PropagateSwap>
516 struct allocation_count_shifter<broken_copy_assignment_propagation<T, shared_counting_allocator<T, PropagateCopy, PropagateMove, PropagateSwap>>>
518 {
519 using allocation_count_shifter<int>::shift;
520
521 static int shift(int count, const alloc_prediction<null_allocation_event::spectator>&)
522 {
523 if constexpr(with_msvc_v && (iterator_debug_level() > 0))
524 {
525 if constexpr(!PropagateCopy)
526 {
527 if(count) return count + 2;
528 }
529 }
530
531 return count;
532 }
533
534 static int shift(int count, const alloc_prediction<assignment_allocation_event::assign_no_prop>&)
535 {
536 if constexpr(with_msvc_v && (iterator_debug_level() > 0))
537 {
538 if constexpr(!PropagateCopy)
539 {
540 if(count) return count + 2;
541 }
542 }
543
544 return count;
545 }
546
547 static int shift(int count, const alloc_prediction<assignment_allocation_event::assign>&)
548 {
549 if constexpr(with_msvc_v && (iterator_debug_level() > 0))
550 {
551 if(count) return count - 1;
552 }
553
554 return count;
555 }
556 };
557}
Helper for dealing with allocator propagation during copy assignment.
Definition: AllocationCheckersCore.hpp:73
Somewhat similar to std::allocator but logs (de)allocations via an counter which is shared upon copyi...
Definition: AllocationTestUtilities.hpp:41
Definition: AllocationCheckers.hpp:200
Definition: AllocationTestDiagnosticsUtilities.hpp:446
Definition: AllocationTestDiagnosticsUtilities.hpp:148
Definition: AllocationTestDiagnosticsUtilities.hpp:20
Definition: AllocationTestDiagnosticsUtilities.hpp:84
Definition: AllocationTestDiagnosticsUtilities.hpp:260
Definition: AllocationTestDiagnosticsUtilities.hpp:205
Definition: AllocationTestDiagnosticsUtilities.hpp:313
Definition: AllocationTestDiagnosticsUtilities.hpp:366