span_test.cc
Go to the documentation of this file.
1 /**
2  * @file span_test.cc
3  * @brief Unit test for `util::span` class.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date January 29, 2019
6  * @see `larcorealg/CoreUtils/span.h`
7  */
8 
9 // Boost libraries
10 #define BOOST_TEST_MODULE ( RealComparisons_test )
11 #include <boost/test/unit_test.hpp>
12 #include <boost/iterator/indirect_iterator.hpp>
13 
14 // LArSoft libraries
19 #include "larcorealg/CoreUtils/operations.h" // util::dereference()
20 
21 // C/C++ standard libraries
22 #include <iostream> // std::cout
23 #include <vector>
24 #include <memory> // std::unique_ptr<>
25 #include <numeric> // std::iota()
26 #include <type_traits> // std::is_same<>
27 
28 
29 //------------------------------------------------------------------------------
30 template <typename Iter, typename Cont>
31 void test_span(Cont& v) {
32 
33  auto r = util::make_span(v);
34 
35  // check the type of the object
36  static_assert
37  (std::is_same<decltype(r), util::span<Iter>>());
38  static_assert(std::is_same<decltype(r), util::span<Iter, Iter>>());
39  static_assert(
40  std::is_same<typename decltype(r)::value_type, typename Iter::value_type>()
41  );
42  static_assert
43  (std::is_same<typename decltype(r)::reference, typename Iter::reference>());
44 
45  BOOST_TEST((r.begin() == v.begin()));
46  BOOST_TEST((r.end() == v.end()));
47 
48  BOOST_TEST(r.empty() == v.empty());
49  BOOST_TEST(r.size() == v.size());
50 
51  auto iV = v.cbegin();
52  unsigned int n = 0;
53  for (auto i: r) {
54  BOOST_TEST(i == *iV);
55  ++n;
56  ++iV;
57  } // for
58  BOOST_TEST(n == v.size());
59 
60 } // test_span()
61 
62 
63 //------------------------------------------------------------------------------
64 template <typename Iter, typename Cont>
65 void test_const_span(Cont& v) {
66 
67  auto r = util::make_const_span(v);
68 
69  // check the type of the object
70  static_assert
71  (std::is_same<decltype(r), util::span<Iter>>());
72  static_assert(std::is_same<decltype(r), util::span<Iter, Iter>>());
73  static_assert(
74  std::is_same<typename decltype(r)::value_type, typename Iter::value_type>()
75  );
76  static_assert
77  (std::is_same<typename decltype(r)::reference, typename Iter::reference>());
78 
79  BOOST_TEST((r.begin() == v.cbegin()));
80  BOOST_TEST((r.end() == v.cend()));
81 
82  BOOST_TEST(r.empty() == v.empty());
83  BOOST_TEST(r.size() == v.size());
84 
85  auto iV = v.cbegin();
86  unsigned int n = 0;
87  for (auto i: r) {
88  BOOST_TEST(i == *iV);
89  ++n;
90  ++iV;
91  } // for
92  BOOST_TEST(n == v.size());
93 
94 } // test_const_span()
95 
96 
97 //------------------------------------------------------------------------------
98 template <typename Iter, typename Cont>
99 void test_adapted_span(Cont& v) {
100 
101  /*
102  * In this test we create a container of pointers to `v` elements and iterate
103  * `v` values through that one. The iteration is supposed to be transparent,
104  * with the iteration code not expressing that we are passing via pointers.
105  */
106 
107  std::vector<typename Iter::pointer> ptrs;
108  std::transform
109  (v.begin(), v.end(), std::back_inserter(ptrs), [](auto& v){ return &v; });
110 
112  (ptrs, [](auto&& iter){ return boost::make_indirect_iterator(iter); });
113 
114  // check the type of the object
115  static_assert(
116  std::is_same<typename decltype(r)::value_type, typename Iter::value_type>()
117  );
118 
119  BOOST_TEST(r.empty() == v.empty());
120  BOOST_TEST(r.size() == v.size());
121 
122  unsigned int n = 0;
123  for (auto&& [ rangeValue, value ]: util::zip(r, v)) {
124  BOOST_TEST(&rangeValue == &value);
125  BOOST_TEST(rangeValue == value);
126  ++n;
127  } // for
128  BOOST_TEST(n == v.size());
129 
130 } // test_adapted_span()
131 
132 
133 //------------------------------------------------------------------------------
134 template <typename Iter, typename Cont>
135 void test_transformed_span(Cont& v) {
136 
137  /*
138  * In this test we create a container of pointers to `v` elements and iterate
139  * `v` values through that one. The iteration is supposed to be transparent,
140  * with the iteration code not expressing that we are passing via pointers,
141  * because of our transformation dereferencing the pointers.
142  */
143 
144  using pointer_t = typename std::iterator_traits<Iter>::pointer;
145  using reference_t = typename std::iterator_traits<Iter>::reference;
146 
147  std::vector<pointer_t> ptrs;
148  std::transform
149  (v.begin(), v.end(), std::back_inserter(ptrs), [](auto& v){ return &v; });
150 
152  (ptrs, [](auto* ptr) -> reference_t { return *ptr; });
153 
154  // check the type of the object
155  static_assert(
156  std::is_same<typename decltype(r)::value_type, typename Iter::value_type>()
157  );
158 
159  BOOST_TEST(r.empty() == v.empty());
160  BOOST_TEST(r.size() == v.size());
161 
162  unsigned int n = 0;
163  for (auto&& [ rangeValue, value ]: util::zip(r, v)) {
164  BOOST_TEST(&rangeValue == &value);
165  BOOST_TEST(rangeValue == value);
166  ++n;
167  } // for
168  BOOST_TEST(n == v.size());
169 
170 } // test_transformed_span()
171 
172 
173 //------------------------------------------------------------------------------
174 template <typename Iter, typename Cont>
176 
177  /*
178  * In this test we create a container of unique_ptr to `v` elements and
179  * iterate `v` values through it. The iteration is supposed to be transparent,
180  * with the iteration code not expressing that we are passing via pointers,
181  * because of our transformation dereferencing the pointers.
182  */
183 
184  using value_t = typename std::iterator_traits<Iter>::value_type;
185  using pointer_t = std::unique_ptr<value_t>;
186 
187  std::vector<pointer_t> ptrs;
188  std::transform(
189  v.begin(), v.end(), std::back_inserter(ptrs),
190  [](auto& v){ return std::make_unique<value_t>(v); }
191  );
192 
194 
195  // check the type of the object
196  static_assert(std::is_same<typename decltype(r)::value_type, value_t>());
197 
198  BOOST_TEST(r.empty() == v.empty());
199  BOOST_TEST(r.size() == v.size());
200 
201  unsigned int n = 0;
202  for (auto&& [ rangeValue, value ]: util::zip(r, v)) {
203  BOOST_TEST(&rangeValue == &value);
204  BOOST_TEST(rangeValue == value);
205  ++n;
206  } // for
207  BOOST_TEST(n == v.size());
208 
209 } // test_transformed_span_with_unmoveable_values()
210 
211 
212 //------------------------------------------------------------------------------
213 
215  using Data_t = std::vector<int>;
216 
218  decltype(r)::value_type s = 0;
219  for (auto v: r) s += v;
220  return s;
221  } // sum
222 
223  void analyse() {
224 
225  Data_t v(10U);
226  std::iota(v.begin(), v.end(), 1); // { 1, 2, 3, 4 ,5 ,6, 7, 8, 9, 10 }
227 
228  auto span5 = util::span(v.begin(), v.begin() + 5);
229  std::cout << "Sum of 5 numbers: " << sum(span5) << std::endl;
230 
231  auto span8 = util::span(v.begin(), v.begin() + 8);
232  std::cout << "Sum of 8 numbers: " << sum(span8) << std::endl;
233 
234  auto full_span = util::make_span(v);
235  std::cout << "Sum of all numbers: " << sum(full_span) << std::endl;
236 
237  } // analyse()
238 
239 }; // struct SpanDocumentation1TestClass
240 
241 
242 //------------------------------------------------------------------------------
243 
245  /*
246  * float accumulate(std::vector<std::unique_ptr<float>> const& v) {
247  *
248  * using src_iterator = std::vector<std::unique_ptr<float>>::const_iterator;
249  *
250  * float sum = 0.0F;
251  * for (float v: util::make_adapted_span(v, boost::make_indirect_iterator<src_iterator>))
252  * sum += v;
253  *
254  * } // accumulate()
255  */
256 
257  float accumulate(std::vector<std::unique_ptr<float>> const& v)
258  {
259 
260  using src_iterator = std::vector<std::unique_ptr<float>>::const_iterator;
261 
262  float sum = 0.0F;
263  for (float v: util::make_adapted_span(v, boost::make_indirect_iterator<src_iterator>))
264  sum += v;
265 
266  return sum;
267  } // accumulate()
268 
269  void analyse()
270  {
271  float const salt = 3.0;
272  constexpr std::size_t N = 10;
273 
274  std::vector<std::unique_ptr<float>> data;
275  for (auto i: util::counter(N))
276  data.push_back(std::make_unique<float>(salt * i));
277 
278  float sum = accumulate(data);
279  float const expectedSum = (N * (N - 1) / 2) * salt;
280 
281  BOOST_TEST(sum == expectedSum);
282 
283  } // analyse()
284 
285 }; // struct makeAdaptedSpanDocumentation1TestClass
286 
287 
288 //------------------------------------------------------------------------------
289 
291 
292  /*
293  * float accumulate(std::vector<std::unique_ptr<float>> const& v) {
294  *
295  * float sum = 0.0F;
296  * for (float v: util::make_transformed_span(v, [](auto& ptr){ return *ptr; }))
297  * sum += v;
298  *
299  * return sum;
300  * } // accumulate()
301  */
302 
303 
304  float accumulate(std::vector<std::unique_ptr<float>> const& v)
305  {
306  float sum = 0.0F;
307  for (float v: util::make_transformed_span(v, [](auto& ptr){ return *ptr; }))
308  sum += v;
309 
310  return sum;
311  } // accumulate()
312 
313  /*
314  * void scale(std::vector<std::unique_ptr<float>>& v, float factor) {
315  *
316  * for (float& v: util::make_transformed_span(v, [](auto& ptr) -> float& { return *ptr; }))
317  * v *= factor;
318  *
319  * } // scale()
320  */
321 
322  void scale(std::vector<std::unique_ptr<float>>& v, float factor)
323  {
324 
325  for (float& v: util::make_transformed_span(v, [](auto& ptr) -> float& { return *ptr; }))
326  v *= factor;
327 
328  } // scale()
329 
331  {
332  float const salt = 3.0;
333  constexpr std::size_t N = 10;
334 
335  std::vector<std::unique_ptr<float>> data;
336  for (auto i: util::counter(N))
337  data.push_back(std::make_unique<float>(salt * i));
338 
339  float sum = accumulate(data);
340  float const expectedSum = (N * (N - 1) / 2) * salt;
341 
342  BOOST_TEST(sum == expectedSum);
343 
344  } // analyse_accumulate()
345 
347  {
348  constexpr std::size_t N = 10;
349  const float factor = 3.0F;
350 
351  std::vector<std::unique_ptr<float>> data;
352  for (auto i: util::counter(N))
353  data.push_back(std::make_unique<float>(i));
354 
355  scale(data, factor);
356 
357  for (auto&& [ i, ptr ]: util::enumerate(data))
358  BOOST_TEST(*ptr == factor * i);
359 
360  } // analyse_scale()
361 
362  void analyse()
363  {
364  analyse_accumulate();
365  analyse_scale();
366  }
367 
368 }; // struct makeTransformedSpanDocumentation1TestClass
369 
370 
371 //------------------------------------------------------------------------------
372 BOOST_AUTO_TEST_CASE(span_testcase) {
373 
374  using TestVector_t = std::vector<int>;
375 
376  TestVector_t ev;
377  test_span<TestVector_t::iterator>(ev);
378  test_const_span<TestVector_t::const_iterator>(ev);
379 
380  TestVector_t v3 { 1, 2, 3 };
381  test_span<TestVector_t::iterator>(v3);
382  test_const_span<TestVector_t::const_iterator>(v3);
383 
384  TestVector_t const cv4 { 1, 2, 3, 4 };
385  test_span<TestVector_t::const_iterator>(cv4);
386  test_const_span<TestVector_t::const_iterator>(cv4);
387 
388 
389 } // BOOST_AUTO_TEST_CASE(span_testcase)
390 
391 
392 //------------------------------------------------------------------------------
393 BOOST_AUTO_TEST_CASE(adapted_span_testcase) {
394 
395  using TestVector_t = std::vector<int>;
396 
397  TestVector_t ev;
398  test_adapted_span<TestVector_t::iterator>(ev);
399 
400  TestVector_t v3 { 1, 2, 3 };
401  test_adapted_span<TestVector_t::iterator>(v3);
402 
403  TestVector_t const cv4 { 1, 2, 3, 4 };
404  test_adapted_span<TestVector_t::const_iterator>(cv4);
405 
406 } // BOOST_AUTO_TEST_CASE(adapted_span_testcase)
407 
408 
409 //------------------------------------------------------------------------------
410 BOOST_AUTO_TEST_CASE(transformed_span_testcase) {
411 
412  using TestVector_t = std::vector<int>;
413 
414  TestVector_t ev;
415  test_transformed_span<TestVector_t::iterator>(ev);
416  test_transformed_span_with_unmoveable_values<TestVector_t::iterator>(ev);
417 
418  TestVector_t v3 { 1, 2, 3 };
419  test_transformed_span<TestVector_t::iterator>(v3);
420 
421  TestVector_t const cv4 { 1, 2, 3, 4 };
422  test_transformed_span<TestVector_t::const_iterator>(cv4);
423 
424 } // BOOST_AUTO_TEST_CASE(transformed_span_testcase)
425 
426 
427 //------------------------------------------------------------------------------
428 BOOST_AUTO_TEST_CASE(span_documentation_testcase) {
429 
430  // this only checks that the example compiles and runs
432  doc1.analyse();
433 
434 } // BOOST_AUTO_TEST_CASE(span_documentation_testcase)
435 
436 
437 //------------------------------------------------------------------------------
438 BOOST_AUTO_TEST_CASE(adapted_span_documentation_testcase) {
439 
441  doc1.analyse();
442 
443 } // BOOST_AUTO_TEST_CASE(span_documentation_testcase)
444 
445 
446 //------------------------------------------------------------------------------
447 BOOST_AUTO_TEST_CASE(transformed_span_documentation_testcase) {
448 
450  doc1.analyse();
451 
452 } // BOOST_AUTO_TEST_CASE(span_documentation_testcase)
453 
454 
455 //------------------------------------------------------------------------------
span(IterB &&b, IterE &&e, Adaptor &&adaptor) -> span< decltype(adaptor(std::forward< IterB >(b))), decltype(adaptor(std::forward< IterE >(e))) >
Definition of util::zip().
An object with a begin and end iterator.
std::vector< int > Data_t
Definition: span_test.cc:215
float accumulate(std::vector< std::unique_ptr< float >> const &v)
Definition: span_test.cc:304
Definition of util::enumerate().
auto make_span(BIter begin, EIter end)
Creates a span from specified iterators (can use constructor instead).
Definition: span.h:197
struct vector vector
Provides a few simple operations for use in generic programming.
intermediate_table::const_iterator const_iterator
int sum(util::span< Data_t::iterator > r)
Definition: span_test.cc:217
auto make_adapted_span(BIter begin, EIter end, Adaptor &&adaptor)
Definition: span.h:223
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
Definition: enumerate.h:69
void test_const_span(Cont &v)
Definition: span_test.cc:65
BOOST_AUTO_TEST_CASE(span_testcase)
Definition: span_test.cc:372
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
Definition: counter.h:285
void test_transformed_span_with_unmoveable_values(Cont &v)
Definition: span_test.cc:175
auto make_transformed_span(BIter begin, EIter end, Op &&op)
Definition: span.h:294
std::void_t< T > n
Test of util::counter and support utilities.
void test_transformed_span(Cont &v)
Definition: span_test.cc:135
decltype(auto) dereference()
Returns a functor that returns *ptr of its argument ptr.
Definition: operations.h:125
float accumulate(std::vector< std::unique_ptr< float >> const &v)
Definition: span_test.cc:257
void test_span(Cont &v)
Definition: span_test.cc:31
auto zip(Iterables &&...iterables)
Range-for loop helper iterating across many collections at the same time.
Definition: zip.h:295
void scale(std::vector< std::unique_ptr< float >> &v, float factor)
Definition: span_test.cc:322
static QCString * s
Definition: config.cpp:1042
void test_adapted_span(Cont &v)
Definition: span_test.cc:99
QTextStream & endl(QTextStream &s)
auto make_const_span(Cont &cont)
Creates a span with constant iterator access from a container type.
Definition: span.h:206