MappedContainer_test.cc
Go to the documentation of this file.
1 /**
2  * @file MappedContainer_test.cc
3  * @brief Tests the classes in `MappedContainer.h`.
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date March 22, 2019
6  * @version 1.0
7  * @see `lardataalg/Utilities/MappedContainer.h`
8  */
9 
10 // Boost libraries
11 #define BOOST_TEST_MODULE ( MappedContainer_test )
12 #include <boost/test/unit_test.hpp>
13 
14 // LArSoft libraries
16 #include "larcorealg/CoreUtils/ContainerMeta.h" // util::collection_value_t<>
17 
18 // C/C++ standard libraries
19 #include <iostream> // std::cout
20 #include <array>
21 #include <functional> // std::ref()
22 #include <algorithm> // std::copy()
23 #include <iterator> // std::back_inserter()
24 #include <type_traits> // std::is_copy_assignable_v<>...
25 #include <cstddef> // std::size_t
26 #include <limits>
27 
28 
29 //------------------------------------------------------------------------------
30 //--- Test code
31 //
32 
34  static constexpr std::size_t Dim = 10U;
35  static std::array<int, Dim> const sourceValues;
36  static constexpr std::size_t sourceSize() { return Dim; }
37 };
38 
39 // BUG the double brace syntax is required to work around clang bug 21629
40 // (https://bugs.llvm.org/show_bug.cgi?id=21629)
41 std::array<int, TestDataMakerBase::Dim> const TestDataMakerBase::sourceValues
42  {{ 0, -1, -2, -3, -4, -5, -6, -7, -8, -9 }};
43 
44 template <typename Cont>
46  using Container_t = Cont;
47  static Container_t make()
48  {
50  std::copy
51  (sourceValues.cbegin(), sourceValues.cend(), std::back_inserter(data));
52  return data;
53  }
54 }; // TestDataMakerClass
55 
56 template <typename T, std::size_t N>
58  using Container_t = std::array<T, N>;
59  static Container_t make()
60  {
61  static_assert(N >= sourceSize());
63  std::copy(sourceValues.cbegin(), sourceValues.cend(), data.begin());
64  return data;
65  }
66 }; // TestDataMakerClass<std::array>
67 
68 template <typename T>
69 struct TestDataMakerClass<std::unique_ptr<T[]>>: public TestDataMakerBase {
70  using Container_t = std::unique_ptr<T[]>;
71  static Container_t make()
72  {
73  Container_t data { new T[sourceSize()] };
74  std::copy(sourceValues.cbegin(), sourceValues.cend(), data.get());
75  return data;
76  }
77 }; // TestDataMakerClass<std::array>
78 
79 template <typename Cont>
81 
82 
83 //------------------------------------------------------------------------------
84 template <typename Cont>
85 void copyTest() {
86 
87  using Container_t = Cont;
88  using Literal_t = util::collection_value_t<Container_t>;
89  using Data_t = Literal_t;
90 
91  constexpr Literal_t defaultValue { 42 };
92 
94 
95  auto const data = makeTestData<Cont>();
96 
97  static_assert(std::is_copy_assignable_v<std::decay_t<decltype(data)>>);
98  static_assert(std::is_copy_constructible_v<std::decay_t<decltype(data)>>);
99  static_assert(std::is_move_assignable_v<std::decay_t<decltype(data)>>);
100  static_assert(std::is_move_constructible_v<std::decay_t<decltype(data)>>);
101 
102  // BUG the double brace syntax is required to work around clang bug 21629
103  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
104  std::array<std::size_t, 12U> const mapping1 = {{
105  4U, 3U, 2U, 1U, 0U, InvalidIndex,
106  9U, 8U, 7U, 6U, 5U, InvalidIndex,
107  }};
108 
109  std::array<Data_t, 12U> const expectedMappedData1 = {{
110  -4, -3, -2, -1, 0, defaultValue,
111  -9, -8, -7, -6, -5, defaultValue
112  }};
113 
114  util::MappedContainer const mappedData1
115  (data, mapping1, expectedMappedData1.size(), defaultValue);
116 
117  BOOST_TEST(mappedData1.size() == expectedMappedData1.size());
118  BOOST_TEST(mappedData1.minimal_size() == expectedMappedData1.size());
119 
120  BOOST_TEST(mappedData1.front() == expectedMappedData1.front());
121  BOOST_TEST(mappedData1.back() == expectedMappedData1.back());
122 
123  std::size_t i = 0;
124  auto const beginIterator = mappedData1.begin();
125  auto const secondIterator = beginIterator + 1;
126  auto mappedIterator = beginIterator;
127  for (auto&& mappedValue: mappedData1) {
128  BOOST_TEST_CHECKPOINT("mapped item: " << i);
129 
130  Data_t const expectedValue = expectedMappedData1[i];
131  Data_t const& expectedRef = (mapping1[i] == InvalidIndex)
132  ? mappedData1.defaultValue()
133  : data[mapping1[i]]
134  ;
135  BOOST_TEST(expectedRef == expectedValue); // test the test
136 
137  BOOST_TEST(mappedValue == expectedMappedData1[i]);
138  BOOST_TEST(mappedData1[i] == expectedMappedData1[i]);
139  BOOST_TEST(mappedData1.at(i) == expectedMappedData1[i]);
140  BOOST_TEST(beginIterator[i] == expectedMappedData1[i]);
141  BOOST_TEST(*(beginIterator + i) == expectedMappedData1[i]);
142  BOOST_TEST(*mappedIterator == expectedMappedData1[i]);
143  if (i >= 1) {
144  BOOST_TEST(secondIterator[i-1] == expectedMappedData1[i]);
145  BOOST_TEST(*(secondIterator + i - 1) == expectedMappedData1[i]);
146  BOOST_TEST( (mappedIterator != beginIterator));
147  BOOST_TEST(!(mappedIterator == beginIterator));
148  BOOST_TEST( (mappedIterator > beginIterator));
149  BOOST_TEST( (mappedIterator >= beginIterator));
150  BOOST_TEST(!(mappedIterator < beginIterator));
151  BOOST_TEST(!(mappedIterator <= beginIterator));
152  BOOST_TEST( (beginIterator != mappedIterator));
153  BOOST_TEST(!(beginIterator == mappedIterator));
154  BOOST_TEST(!(beginIterator > mappedIterator));
155  BOOST_TEST(!(beginIterator >= mappedIterator));
156  BOOST_TEST( (beginIterator < mappedIterator));
157  BOOST_TEST( (beginIterator <= mappedIterator));
158  }
159  else {
160  BOOST_TEST(!(mappedIterator != beginIterator));
161  BOOST_TEST( (mappedIterator == beginIterator));
162  BOOST_TEST(!(mappedIterator > beginIterator));
163  BOOST_TEST( (mappedIterator >= beginIterator));
164  BOOST_TEST(!(mappedIterator < beginIterator));
165  BOOST_TEST( (mappedIterator <= beginIterator));
166  BOOST_TEST(!(beginIterator != mappedIterator));
167  BOOST_TEST( (beginIterator == mappedIterator));
168  BOOST_TEST(!(beginIterator > mappedIterator));
169  BOOST_TEST( (beginIterator >= mappedIterator));
170  BOOST_TEST(!(beginIterator < mappedIterator));
171  BOOST_TEST( (beginIterator <= mappedIterator));
172  }
173 
174  BOOST_TEST(&mappedData1[i] != &expectedMappedData1[i]);
175  ++i;
176  ++mappedIterator;
177  } // for
178  BOOST_TEST(i == expectedMappedData1.size());
179 
180  // let's check a bit of overflow
181  while (i < expectedMappedData1.size() + 3U) {
182  BOOST_TEST_CHECKPOINT("mapped item: " << i << " (overflow)");
183  BOOST_CHECK_THROW(mappedData1.at(i), std::out_of_range);
184  ++i;
185  } // for
186 
187 
188 } // copyTest()
189 
190 
191 //------------------------------------------------------------------------------
192 template <typename Cont>
194 
195  using Container_t = Cont;
196  using Literal_t = util::collection_value_t<Container_t>;
197  using Data_t = Literal_t;
198 
199  constexpr Literal_t defaultValue { 42 };
200 
202 
203  auto const data = makeTestData<Cont>();
204 
205  // BUG the double brace syntax is required to work around clang bug 21629
206  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
207  std::array<std::size_t, 12U> const mapping1 = {{
208  4U, 3U, 2U, 1U, 0U, InvalidIndex,
209  9U, 8U, 7U, 6U, 5U, InvalidIndex,
210  }};
211 
212  std::array<Literal_t, 12U> const expectedMappedData1 = {{
213  -4, -3, -2, -1, 0, defaultValue,
214  -9, -8, -7, -6, -5, defaultValue
215  }};
216 
217  util::MappedContainer const mappedData1(
218  std::ref(data), mapping1, expectedMappedData1.size(),
219  defaultValue
220  );
221 
222  // a similar mapping, but the mapping itself is not copied
223  util::MappedContainer const mappedData2(std::ref(data), std::ref(mapping1));
224 
225  static_assert(
226  std::is_same_v<
227  typename decltype(mappedData1)::const_iterator::reference,
228  Data_t const&
229  >
230  );
231 
232  BOOST_TEST(mappedData1.size() == expectedMappedData1.size());
233  BOOST_TEST(mappedData1.minimal_size() == expectedMappedData1.size());
234 
235  BOOST_TEST(mappedData1.front() == expectedMappedData1.front());
236  BOOST_TEST(mappedData1.back() == expectedMappedData1.back());
237 
238  std::size_t i = 0;
239  auto const beginIterator = mappedData1.begin();
240  auto const secondIterator = beginIterator + 1;
241  auto mappedIterator = beginIterator;
242  for (auto&& mappedValue: mappedData1) {
243  BOOST_TEST_CHECKPOINT("mapped item: " << i);
244 
245  std::size_t const& expectedMappedIndex = mapping1[i];
246  Data_t const expectedValue = expectedMappedData1[i];
247  Data_t const& expectedRef = (expectedMappedIndex == InvalidIndex)
248  ? mappedData1.defaultValue()
249  : data[expectedMappedIndex]
250  ;
251  BOOST_TEST(expectedRef == expectedValue); // test the test
252 
253  decltype(auto) mappedDataRef = mappedData1[i];
254  static_assert(std::is_reference_v<decltype(mappedDataRef)>);
255 
256  BOOST_TEST(mappedData1.map_index(i) == expectedMappedIndex);
257  BOOST_TEST(mappedValue == expectedValue);
258  BOOST_TEST(mappedDataRef == expectedValue);
259  BOOST_TEST(mappedData1.at(i) == expectedValue);
260  BOOST_TEST(beginIterator[i] == expectedValue);
261  BOOST_TEST(*(beginIterator + i) == expectedValue);
262  BOOST_TEST(*mappedIterator == expectedValue);
263  if (i >= 1) {
264  BOOST_TEST(secondIterator[i-1] == expectedValue);
265  BOOST_TEST(*(secondIterator + i - 1) == expectedValue);
266  BOOST_TEST( (mappedIterator != beginIterator));
267  BOOST_TEST(!(mappedIterator == beginIterator));
268  BOOST_TEST( (mappedIterator > beginIterator));
269  BOOST_TEST( (mappedIterator >= beginIterator));
270  BOOST_TEST(!(mappedIterator < beginIterator));
271  BOOST_TEST(!(mappedIterator <= beginIterator));
272  BOOST_TEST( (beginIterator != mappedIterator));
273  BOOST_TEST(!(beginIterator == mappedIterator));
274  BOOST_TEST(!(beginIterator > mappedIterator));
275  BOOST_TEST(!(beginIterator >= mappedIterator));
276  BOOST_TEST( (beginIterator < mappedIterator));
277  BOOST_TEST( (beginIterator <= mappedIterator));
278  }
279  else {
280  BOOST_TEST(!(mappedIterator != beginIterator));
281  BOOST_TEST( (mappedIterator == beginIterator));
282  BOOST_TEST(!(mappedIterator > beginIterator));
283  BOOST_TEST( (mappedIterator >= beginIterator));
284  BOOST_TEST(!(mappedIterator < beginIterator));
285  BOOST_TEST( (mappedIterator <= beginIterator));
286  BOOST_TEST(!(beginIterator != mappedIterator));
287  BOOST_TEST( (beginIterator == mappedIterator));
288  BOOST_TEST(!(beginIterator > mappedIterator));
289  BOOST_TEST( (beginIterator >= mappedIterator));
290  BOOST_TEST(!(beginIterator < mappedIterator));
291  BOOST_TEST( (beginIterator <= mappedIterator));
292  }
293 
294  // since `data` is captured via reference, the returned elements should be
295  // exactly the same object (same physical memory location) as in the
296  // original collection:
297  BOOST_TEST(&mappedDataRef == &expectedRef);
298 
299  // mapping by reference should be equivalent to mapping by value;
300  // because of out test choice, the default values are different though
301  if (mapping1[i] != InvalidIndex)
302  BOOST_TEST(mappedData2[i] == mappedData1[i]);
303  BOOST_TEST(&mappedData2.map_index(i) == &expectedMappedIndex);
304 
305  ++i;
306  ++mappedIterator;
307  } // for
308  BOOST_TEST(i == expectedMappedData1.size());
309 
310  // let's check a bit of overflow
311  while (i < expectedMappedData1.size() + 3U) {
312  BOOST_TEST_CHECKPOINT("mapped item: " << i << " (overflow)");
313  BOOST_CHECK_THROW(mappedData1.at(i), std::out_of_range);
314  ++i;
315  } // for
316 
317 } // referenceTest()
318 
319 
320 //------------------------------------------------------------------------------
322 
323  using Mapping_t = std::array<std::size_t, 6U>;
324 
325  (void) util::MappedContainer<std::array<float, 4U> , Mapping_t>();
326  (void) util::MappedContainer<float[4U] , Mapping_t>();
329  (void) util::MappedContainer<std::unique_ptr<float> , Mapping_t>();
330  (void) util::MappedContainer<std::reference_wrapper<std::array<float, 4U>>, Mapping_t>();
331 
332 } // defaultConstructorTest()
333 
334 
335 //------------------------------------------------------------------------------
336 void autosizeTest() {
337  /*
338  * Tests that the size is correctly evinced from the mapping.
339  */
341 
342  // BUG the double brace syntax is required to work around clang bug 21629
343  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
344  std::array<double, 4U> const data {{ 0.0, -1.0, -2.0, -3.0 }};
345 
346  std::array<std::size_t, 6U> const mapping = {{
347  1U, 0U, InvalidIndex,
348  3U, 2U, InvalidIndex,
349  }};
350 
351  util::MappedContainer const mappedData(std::ref(data), mapping);
352 
353  BOOST_TEST(mappedData.size() == mapping.size());
354  BOOST_TEST(mappedData.defaultValue() == double{});
355 
356 } // autosizeTest()
357 
358 
359 //------------------------------------------------------------------------------
361  /*
362  * constexpr auto InvalidIndex = util::MappedContainerBase::invalidIndex();
363  *
364  * std::array<double, 4U> const data { 0.0, -1.0, -2.0, -3.0 };
365  *
366  * std::array<std::size_t, 6U> const mapping = {
367  * 1U, 0U, InvalidIndex,
368  * 3U, 2U, InvalidIndex,
369  * };
370  *
371  * util::MappedContainer const mappedData
372  * (std::ref(data), mapping, 6U, std::numeric_limits<double>::quiet_NaN());
373  *
374  * for (std::size_t i = 0; i < 6U; ++i) {
375  * std::cout
376  * << "Mapped element #" << i << ": " << mappedData[i] << std::endl;
377  * }
378  */
379  // BEGIN example -------------------------------------------------------------
381 
382  // BUG the double brace syntax is required to work around clang bug 21629
383  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
384  std::array<double, 4U> const data {{ 0.0, -1.0, -2.0, -3.0 }};
385 
386  std::array<std::size_t, 6U> const mapping = {{
387  1U, 0U, InvalidIndex,
388  3U, 2U, InvalidIndex,
389  }};
390 
391  util::MappedContainer const mappedData
392  (std::ref(data), mapping, 6U, std::numeric_limits<double>::quiet_NaN());
393 
394  for (std::size_t i = 0; i < 6U; ++i) {
395  std::cout
396  << "Mapped element #" << i << ": " << mappedData[i] << std::endl;
397  }
398  // END example ---------------------------------------------------------------
399 
400 } // classDoc1Test()
401 
402 
403 //------------------------------------------------------------------------------
404 //--- registration of tests
405 //
406 
407 //
408 // stat collector tests
409 //
411  copyTest<std::array<double, 10U>>();
412  referenceTest<std::array<double, 10U>>();
413  referenceTest<std::unique_ptr<double[]>>();
415  autosizeTest();
416 } // TestCase
417 
418 BOOST_AUTO_TEST_CASE(DocumentationTestCase) {
419  classDoc1Test();
420 } // DocumentationTestCase
Provides MappedContainer class.
void autosizeTest()
A meta-container providing transparent mapping on top of another.
static Container_t make()
static constexpr std::size_t sourceSize()
BOOST_AUTO_TEST_CASE(TestCase)
auto makeTestData()
void classDoc1Test()
STL namespace.
size_type size() const
Returns the nominal size of the container (after mapping).
const_iterator begin() const
Returns a constant iterator to the first mapped element.
static constexpr T invalidIndex()
static std::array< int, Dim > const sourceValues
const Index InvalidIndex
static constexpr std::size_t Dim
unique_ptr< InputSource > make(ParameterSet const &conf, InputSourceDescription &desc)
auto array(Array const &a)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:228
T copy(T const &v)
reference defaultValue()
Returns the default value for elements with no original content.
typename collection_value_type< Coll >::type collection_value_t
Type contained in the collection Coll.
Definition: ContainerMeta.h:65
C++ metaprogramming utilities for dealing with containers.
void defaultConstructorTest()
void referenceTest()
void copyTest()
QTextStream & endl(QTextStream &s)