Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AnyTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file AnyTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2021 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #include <boost/test/data/test_case.hpp>
10 #include <boost/test/unit_test.hpp>
11 
12 #include "Acts/Utilities/Any.hpp"
13 
14 #include <any>
15 #include <array>
16 #include <cstddef>
17 #include <type_traits>
18 #include <utility>
19 
20 using namespace Acts;
21 
22 #if defined(_ACTS_ANY_ENABLE_TRACK_ALLOCATIONS)
23 #define CHECK_ANY_ALLOCATIONS() \
24  do { \
25  _AnyAllocationReporter::checkAllocations(); \
26  } while (0)
27 #else
28 #define CHECK_ANY_ALLOCATIONS() \
29  do { \
30  } while (0)
31 #endif
32 
33 BOOST_AUTO_TEST_SUITE(AnyTests)
34 
35 BOOST_AUTO_TEST_CASE(AnyConstructPrimitive) {
36  {
37  // small type
38  Any a;
39  BOOST_CHECK(!a);
40 
41  int v = 5;
42  a = Any{v};
43  BOOST_CHECK(!!a);
44 
45  BOOST_CHECK_EQUAL(a.as<int>(), v);
46  BOOST_CHECK_NE(a.as<int>(), v + 1);
47 
48  BOOST_CHECK_THROW(a.as<float>(), std::bad_any_cast);
49  BOOST_CHECK_THROW(a = Any{0.5f}, std::bad_any_cast);
50  }
52 
53  {
54  // type that is large
55  Any a;
56  BOOST_CHECK(!a);
57 
58  std::array<int, 2> v{1, 2};
59  a = Any{v};
60  BOOST_CHECK(!!a);
61 
62  BOOST_CHECK_EQUAL_COLLECTIONS(a.as<decltype(v)>().begin(),
63  a.as<decltype(v)>().end(), v.begin(),
64  v.end());
65  BOOST_CHECK_THROW(a.as<float>(), std::bad_any_cast);
66  BOOST_CHECK_THROW(a = Any{0.5f}, std::bad_any_cast);
67  }
69 
70  {
71  // type that is large
72  Any a;
73  BOOST_CHECK(!a);
74 
75  std::array<unsigned long, 5> v{1, 2, 3, 4, 5};
76  a = Any{v};
77  BOOST_CHECK(!!a);
78 
79  BOOST_CHECK_EQUAL_COLLECTIONS(a.as<decltype(v)>().begin(),
80  a.as<decltype(v)>().end(), v.begin(),
81  v.end());
82  BOOST_CHECK_THROW(a.as<float>(), std::bad_any_cast);
83  BOOST_CHECK_THROW(a = Any{0.5f}, std::bad_any_cast);
84  }
86 }
87 
88 BOOST_AUTO_TEST_CASE(AnyAssignConstructEmpty) {
89  Any a;
90  Any b;
91  a = b;
92  Any c{a};
93  a = std::move(b);
94  Any d{std::move(a)};
95 
96  BOOST_CHECK(!a);
97  BOOST_CHECK(!b);
98  BOOST_CHECK(!c);
99  BOOST_CHECK(!d);
100 
102 }
103 
104 BOOST_AUTO_TEST_CASE(AnyConstructCustom) {
105  struct A {
106  int value;
107  A() { value = 76; }
108  };
109 
110  Any a;
111  BOOST_CHECK(!a);
112  a = Any{A{}};
113 
114  BOOST_CHECK(!!a);
115 
116  BOOST_CHECK_EQUAL(a.as<A>().value, 76);
117 
119 }
120 
121 BOOST_AUTO_TEST_CASE(AnyConstructCustomInPlace) {
122  struct A {
123  int value;
124  A(int v) { value = v; }
125  };
126 
127  Any a{std::in_place_type<A>, 42};
128  BOOST_CHECK(!!a);
129  BOOST_CHECK_EQUAL(a.as<A>().value, 42);
130 
132 }
133 
135  {
136  // small type
137  Any a;
138  BOOST_CHECK(!a);
139 
140  int v = 5;
141  a = Any{v};
142  BOOST_CHECK(!!a);
143 
144  Any b = std::move(a);
145  BOOST_CHECK(!!b);
146  BOOST_CHECK_EQUAL(b.as<int>(), 5);
147 
148  Any c;
149  c = std::move(b);
150  BOOST_CHECK(!!c);
151  BOOST_CHECK_EQUAL(c.as<int>(), 5);
152  }
153 
155 }
156 
158  {
159  // small type
160  Any a;
161  BOOST_CHECK(!a);
162 
163  int v = 5;
164  a = Any{v};
165  BOOST_CHECK(!!a);
166 
167  Any b = a;
168  BOOST_CHECK(!!b);
169  BOOST_CHECK_EQUAL(b.as<int>(), 5);
170 
171  Any c;
172  c = a;
173  BOOST_CHECK(!!c);
174  BOOST_CHECK_EQUAL(c.as<int>(), 5);
175  }
177 }
178 
179 struct D {
180  bool* destroyed;
181  D(bool* d) : destroyed{d} {}
182  ~D() { *destroyed = true; }
183 };
184 
185 struct D2 {
186  bool* destroyed{nullptr};
187  std::array<char, 512> blob{};
188 
189  D2(bool* d) : destroyed{d} {}
190 
191  ~D2() { *destroyed = true; }
192 };
193 
194 BOOST_AUTO_TEST_CASE(AnyDestroy) {
195  { // small type
196  bool destroyed = false;
197  D d{&destroyed};
198  BOOST_CHECK(!destroyed);
199  {
200  Any a{std::move(d)};
201  BOOST_CHECK(!destroyed);
202  }
203  BOOST_CHECK(destroyed);
204  }
206 
207  { // large type
208  bool destroyed = false;
209  D2 d{&destroyed};
210  BOOST_CHECK(!destroyed);
211  {
212  Any a{std::move(d)};
213  BOOST_CHECK(!destroyed);
214  }
215  BOOST_CHECK(destroyed);
216  }
218 }
219 
220 BOOST_AUTO_TEST_CASE(AnyDestroyCopy) {
221  { // small type
222  bool destroyed = false;
223 
224  {
225  Any b;
226  {
227  Any a{std::in_place_type<D>, &destroyed};
228  BOOST_CHECK(!destroyed);
229  b = a;
230  BOOST_CHECK(!destroyed);
231  }
232  BOOST_CHECK(destroyed); // a destroyed, should be true
233  destroyed = false;
234  BOOST_CHECK(!destroyed);
235  }
236  BOOST_CHECK(destroyed); // b destroyed, should be true again
237  }
239 
240  { // large type
241  bool destroyed = false;
242 
243  {
244  Any b;
245  {
246  Any a{std::in_place_type<D2>, &destroyed};
247  BOOST_CHECK(!destroyed);
248  b = a;
249  BOOST_CHECK(!destroyed);
250  }
251  BOOST_CHECK(destroyed); // a destroyed, should be true
252  destroyed = false;
253  BOOST_CHECK(!destroyed);
254  }
255  BOOST_CHECK(destroyed); // b destroyed, should be true again
256  }
258 }
259 
260 BOOST_AUTO_TEST_CASE(AnyDestroyInPlace) {
261  { // small type
262  bool destroyed = false;
263  BOOST_CHECK(!destroyed);
264  {
265  Any a{std::in_place_type<D>, &destroyed};
266  BOOST_CHECK(!destroyed);
267  }
268  BOOST_CHECK(destroyed);
269  }
271 
272  { // large type
273  bool destroyed = false;
274  BOOST_CHECK(!destroyed);
275  {
276  Any a{std::in_place_type<D2>, &destroyed};
277  BOOST_CHECK(!destroyed);
278  }
279  BOOST_CHECK(destroyed);
280  }
282 }
283 
284 struct D3 {
285  size_t* destroyed{nullptr};
286  std::array<char, 512> blob{};
287 
288  D3(size_t* d) : destroyed{d} {}
289 
290  ~D3() { (*destroyed)++; }
291 };
292 
294  size_t destroyed = 0;
295  for (size_t i = 0; i < 10000; i++) {
296  {
297  BOOST_CHECK_EQUAL(destroyed, i);
298  Any a;
299  BOOST_CHECK_EQUAL(destroyed, i);
300  a = Any{std::in_place_type<D3>, &destroyed};
301  BOOST_CHECK_EQUAL(destroyed, i);
302  }
303  BOOST_CHECK_EQUAL(destroyed, i + 1);
304  }
306 }
307 
309  size_t nDestroy = 0;
310  size_t nCopyConstruct = 0;
311  size_t nCopy = 0;
312  size_t nMoveConstruct = 0;
313  size_t nMove = 0;
314 };
315 
316 template <size_t PADDING>
317 struct Lifecycle;
318 
319 template <>
320 struct Lifecycle<0> {
322 
323  Lifecycle(LifecycleCounters* _counters) : counters{_counters} {}
324 
325  Lifecycle(Lifecycle&& o) {
326  counters = o.counters;
327  counters->nMoveConstruct++;
328  }
329 
331  counters = o.counters;
332  counters->nMove++;
333  return *this;
334  }
335 
336  Lifecycle(const Lifecycle& o) {
337  counters = o.counters;
338  counters->nCopyConstruct++;
339  }
340 
341  Lifecycle& operator=(const Lifecycle& o) {
342  counters = o.counters;
343  counters->nCopy++;
344  return *this;
345  }
346 
347  ~Lifecycle() { counters->nDestroy++; }
348 };
349 
350 template <size_t PADDING>
351 struct Lifecycle : public Lifecycle<0> {
352  std::array<char, PADDING> m_padding{};
353 
354  Lifecycle(LifecycleCounters* _counters) : Lifecycle<0>(_counters) {}
355 };
356 
357 template <size_t PADDING>
361 
363 };
364 
365 #define checkCounters() \
366  do { \
367  BOOST_REQUIRE_EQUAL(l.counters.nCopy, counters.nCopy); \
368  BOOST_REQUIRE_EQUAL(l.counters.nCopyConstruct, counters.nCopyConstruct); \
369  BOOST_REQUIRE_EQUAL(l.counters.nMove, counters.nMove); \
370  BOOST_REQUIRE_EQUAL(l.counters.nMoveConstruct, counters.nMoveConstruct); \
371  BOOST_REQUIRE_EQUAL(l.counters.nDestroy, counters.nDestroy); \
372  } while (0)
373 
374 #define makeCounter(counter, n) \
375  do { \
376  counter += n; \
377  checkCounters(); \
378  } while (0)
379 
380 #define incCopyConstruct(n) makeCounter(counters.nCopyConstruct, n)
381 #define incCopy(n) makeCounter(counters.nCopy, n)
382 #define incMoveConstruct(n) makeCounter(counters.nMoveConstruct, n)
383 #define incMove(n) makeCounter(counters.nMove, n)
384 #define incDestroy(n) makeCounter(counters.nDestroy, n)
385 
386 BOOST_AUTO_TEST_CASE(LifeCycleSmall) {
389 
390  checkCounters();
391 
392  {
393  const auto& o = l.inner; // force copy
394  Any a{o};
395  incCopyConstruct(1);
396 
397  const auto& _a = a; // force copy later
398  {
399  Any b{_a};
400  incCopyConstruct(1);
401  }
402  incDestroy(1);
403 
404  {
405  Any b;
406  b = _a;
407  incCopyConstruct(1);
408  b = _a;
409  incCopy(1);
410  }
411  incDestroy(1);
412 
413  {
414  Any b{a};
415  incCopyConstruct(1);
416  b = a;
417  incCopy(1);
418  }
419  incDestroy(1);
420 
421  {
422  auto _a2 = a;
423  incCopyConstruct(1);
424  Any b;
425  b = std::move(_a2);
426  incMoveConstruct(1);
427  auto _a3 = a;
428  incCopyConstruct(1);
429  b = std::move(_a3);
430  incMove(1);
431  }
432  incDestroy(3);
433  }
434  incDestroy(1);
435 
436  checkCounters();
437 
439 }
440 
441 BOOST_AUTO_TEST_CASE(LifeCycleHeap) {
444 
445  checkCounters();
446 
447  {
448  const auto& o = l.inner; // force copy
449  Any a{o};
450  incCopyConstruct(1);
451 
452  const auto& _a = a; // force copy later
453  {
454  Any b{_a};
455  incCopyConstruct(1);
456  }
457  incDestroy(1);
458 
459  {
460  Any b;
461  b = _a;
462  incCopyConstruct(1);
463  b = _a;
464  incCopy(1);
465  }
466  incDestroy(1);
467 
468  {
469  Any b{a};
470  incCopyConstruct(1);
471  b = a;
472  incCopy(1);
473  }
474  incDestroy(1);
475 
476  {
477  Any _a2 = a;
478  incCopyConstruct(1);
479  Any b;
480  b = std::move(_a2);
481  // no actual move
482 
483  Any _a3 = a;
484  incCopyConstruct(1);
485  b = std::move(_a3);
486  // no actual move
487  incDestroy(1);
488  }
489  incDestroy(1);
490  }
491  incDestroy(1);
492 
493  checkCounters();
494 
496 }
497 
498 BOOST_AUTO_TEST_SUITE_END()