TIMPI
packed_range_unit.C
Go to the documentation of this file.
1 #include <timpi/parallel_sync.h>
2 #include <timpi/timpi.h>
3 #include <timpi/packing.h>
4 
5 #include <iterator>
6 #include <map>
7 #include <set>
8 #include <string>
9 #include <vector>
10 #include <memory>
11 
12 #define TIMPI_UNIT_ASSERT(expr) \
13  if (!(expr)) \
14  timpi_error()
15 
16 std::string stringy_number(int number)
17 {
18  std::string digit_strings [10] = {"zero", "one", "two",
19  "three", "four", "five", "six", "seven", "eight", "nine"};
20 
21  std::string returnval = "done";
22  while (number)
23  {
24  returnval = digit_strings[number%10]+" "+returnval;
25  number = number/10;
26  };
27 
28  return returnval;
29 }
30 
31 
32 std::vector<char> fake_stringy_number(int number)
33 {
34  const std::string returnval = stringy_number(number);
35  return std::vector<char>(returnval.begin(), returnval.end());
36 }
37 
38 template <typename T>
40 {
41  using iterator_category = std::output_iterator_tag;
42  using value_type = T;
43  using difference_type = std::ptrdiff_t;
44  using pointer = T*;
45  using reference = T&;
46 
47  template <typename T2>
48  void operator=(const T2&) {}
49 
51  return *this;
52  }
53 
55  return null_output_iterator(*this);
56  }
57 
58  // We don't return a reference-to-T here because we don't want to
59  // construct one or have any of its methods called.
60  null_output_iterator & operator*() { return *this; }
61 };
62 
63 
64 template <int i, typename T>
65 inline
66 auto my_get(T & container) -> decltype(std::get<i>(container))
67 {
68  return std::get<i>(container);
69 }
70 
71 
72 template <int i, typename T>
73 inline
74 auto my_get(T & container) -> decltype(*container.begin())
75 {
76  auto fwd_it = container.begin();
77  for (int n_it = 0; n_it < i; ++n_it)
78  ++fwd_it;
79  return *fwd_it;
80 }
81 
82 
83 // Need to disambiguate - array has get() and begin()...
84 template <int i, typename T, std::size_t N>
85 inline
86 auto my_get(std::array<T, N> & container) -> decltype(std::get<i>(container))
87 {
88  return std::get<i>(container);
89 }
90 
91 
92 template <typename T>
93 inline void my_resize(T & container, std::size_t size) { container.resize(size); }
94 
95 template <typename T, typename U>
96 inline void my_resize(std::pair<T,U> &, std::size_t) {}
97 
98 template <typename ... Types>
99 inline void my_resize(std::tuple<Types...> &, std::size_t) {}
100 
101 template <typename T, std::size_t N>
102 inline void my_resize(std::array<T,N> &, std::size_t) {}
103 
104 
105 #if __cplusplus > 201402L
106 namespace libMesh
107 {
108 namespace Parallel
109 {
110 template <>
111 class Packing<std::unique_ptr<int>>
112 {
113 public:
114  typedef int buffer_type;
115 
116  static unsigned int packed_size(typename std::vector<int>::const_iterator) { return 1; }
117  static unsigned int packable_size(const std::unique_ptr<int> &, const void *) { return 1; }
118 
119  template <typename Iter>
120  static void pack(const std::unique_ptr<int> & object, Iter data_out, const void *) { data_out = *object; }
121 
122  template <typename BufferIter>
123  static std::unique_ptr<int> unpack(BufferIter in, const void *)
124  {
125  return std::make_unique<int>(*in++);
126  }
127 };
128 }
129 }
130 #endif
131 
132 using namespace TIMPI;
133 
135 
137  {
138  std::vector<std::string> send(1);
139  if (TestCommWorld->rank() == 0)
140  send[0].assign("Hello");
141  else
142  send[0].assign("Goodbye");
143 
145  ((void *)(NULL), send.begin(), send.end(),
147  }
148 
149 
150  // Make sure we don't have problems with strings of length above 256
151  // inside pairs, like we used to.
152  template <typename PairAtLeast>
154  {
155  std::vector<PairAtLeast> sendv(2);
156  my_resize(sendv[0], 2);
157  my_resize(sendv[1], 2);
158 
159  my_get<0>(sendv[0]).assign("Hello");
160  auto & s0 = my_get<1>(sendv[0]);
161  s0.assign("Is it me you're looking for?\n");
162  for (int i=0; i != 6; ++i)
163  s0 = s0+s0;
164  timpi_assert_greater(s0.size(), 256);
165 
166  my_get<0>(sendv[1]).assign("Goodbye");
167  auto & s1 = my_get<1>(sendv[1]);
168  s1.assign("to you! Guess it's better to say, goodbye\n");
169  for (int i=0; i != 6; ++i)
170  s1 = s1+s1;
171  timpi_assert_greater(s1.size(), 256);
172 
173  std::vector<PairAtLeast> send(1);
174  my_resize(send[0], 2);
175 
176  if (TestCommWorld->rank() == 0)
177  send[0] = sendv[0];
178  else
179  send[0] = sendv[1];
180 
181  std::vector<PairAtLeast> recv;
182 
184  ((void *)(NULL), send.begin(), send.end(),
185  std::back_inserter(recv));
186 
187  const std::size_t comm_size = TestCommWorld->size();
188  const std::size_t vec_size = recv.size();
189  TIMPI_UNIT_ASSERT(comm_size == vec_size);
190 
191  TIMPI_UNIT_ASSERT(sendv[0] == recv[0]);
192  for (std::size_t i=1; i < vec_size; ++i)
193  TIMPI_UNIT_ASSERT(sendv[1] == recv[i]);
194  }
195 
196 
198  {
199  testGettableStringAllGather<std::pair<std::string, std::string>>();
200  }
201 
202 
204  {
205  testGettableStringAllGather<std::array<std::string, 4>>();
206  }
207 
208 
210  {
211  testGettableStringAllGather<std::list<std::string>>();
212  }
213 
214 
216  {
217  testGettableStringAllGather<std::vector<std::string>>();
218  }
219 
220 
221  // Make sure we don't have problems with strings of length above 256
222  // inside other containers either. Also test mixing strings with
223  // other types.
225  {
226 #ifdef TIMPI_HAVE_CXX17 // static_assert without message
227  static_assert(Has_buffer_type<Packing<std::string>>::value);
229  static_assert(Has_buffer_type<Packing<std::tuple<std::string>>>::value);
231  static_assert(Has_buffer_type<Packing<std::tuple<std::string, std::string>>>::value);
233  static_assert(Has_buffer_type<Packing<std::tuple<std::string, std::string, int>>>::value);
234 #endif
235 
236  std::vector<std::tuple<std::string, std::string, int>> sendv(2);
237 
238  auto & s0 = std::get<1>(sendv[0]);
239  std::get<0>(sendv[0]).assign("Hello");
240  s0.assign("Is it me you're looking for?\n");
241  for (int i=0; i != 6; ++i)
242  s0 = s0+s0;
243  timpi_assert_greater(s0.size(), 256);
244  std::get<2>(sendv[0]) = 257;
245 
246  auto & s1 = std::get<1>(sendv[1]);
247  std::get<0>(sendv[1]).assign("Goodbye");
248  s1.assign("to you! Guess it's better to say, goodbye\n");
249  for (int i=0; i != 6; ++i)
250  s1 = s1+s1;
251  timpi_assert_greater(s1.size(), 256);
252  std::get<2>(sendv[1]) = 258;
253 
254  std::vector<std::tuple<std::string, std::string, int>> send(1);
255  if (TestCommWorld->rank() == 0)
256  send[0] = sendv[0];
257  else
258  send[0] = sendv[1];
259 
260  std::vector<std::tuple<std::string, std::string, int>> recv;
261 
263  ((void *)(NULL), send.begin(), send.end(),
264  std::back_inserter(recv));
265 
266  const std::size_t comm_size = TestCommWorld->size();
267  const std::size_t vec_size = recv.size();
268  TIMPI_UNIT_ASSERT(comm_size == vec_size);
269 
270  TIMPI_UNIT_ASSERT(sendv[0] == recv[0]);
271  for (std::size_t i=1; i < vec_size; ++i)
272  TIMPI_UNIT_ASSERT(sendv[1] == recv[i]);
273  }
274 
275 
276 
277  // We should be able to nest containers in other containers in the
278  // first containers etc.
280  {
281  typedef std::tuple<unsigned int, std::vector<std::tuple<char,int,std::size_t>>, unsigned int> send_type;
282 
283 #ifdef TIMPI_HAVE_CXX17 // static_assert without message
284  static_assert(Has_buffer_type<Packing<std::vector<std::tuple<char,int,std::size_t>>>>::value);
285  static_assert(Has_buffer_type<Packing<send_type>>::value);
286 #endif
287 
288  std::vector<send_type> sendv(2);
289 
290  std::get<0>(sendv[0]) = 100;
291  std::get<1>(sendv[0]) = {{'a', -4, 1000},{'b', -5, 2000}};
292  std::get<2>(sendv[0]) = 3000;
293 
294  std::get<0>(sendv[1]) = 200;
295  std::get<1>(sendv[1]) = {{'c', -6, 4000},{'d', -7, 5000}};
296  std::get<2>(sendv[1]) = 6000;
297 
298  std::vector<send_type> send(1);
299  if (TestCommWorld->rank() == 0)
300  send[0] = sendv[0];
301  else
302  send[0] = sendv[1];
303 
304  std::vector<send_type> recv;
305 
307  ((void *)(NULL), send.begin(), send.end(),
308  std::back_inserter(recv));
309 
310  const std::size_t comm_size = TestCommWorld->size();
311  const std::size_t vec_size = recv.size();
312  TIMPI_UNIT_ASSERT(comm_size == vec_size);
313 
314  TIMPI_UNIT_ASSERT(sendv[0] == recv[0]);
315  for (std::size_t i=1; i < vec_size; ++i)
316  TIMPI_UNIT_ASSERT(sendv[1] == recv[i]);
317  }
318 
319 
320 
322  {
323  std::vector<std::string> send(1);
324  const unsigned int my_rank = TestCommWorld->rank();
325  const unsigned int dest_rank =
326  (my_rank + 1) % TestCommWorld->size();
327  const unsigned int source_rank =
328  (my_rank + TestCommWorld->size() - 1) % TestCommWorld->size();
329 
330  {
331  std::ostringstream os;
332  os << my_rank;
333  send[0] = os.str();
334  }
335 
337  (dest_rank, (void *)(NULL), send.begin(), send.end(),
338  source_rank, (void *)(NULL),
340  (std::string*)NULL);
341  }
342 
344  {
345  // This method uses a specialized allgather method that is only defined
346  // when we have MPI
347 #ifdef TIMPI_HAVE_MPI
348  std::vector<std::string> vals;
349  const unsigned int my_rank = TestCommWorld->rank();
350  TestCommWorld->allgather(std::string(my_rank+1, '0' + my_rank), vals);
351 
352  const std::size_t comm_size = TestCommWorld->size();
353  const std::size_t vec_size = vals.size();
354  TIMPI_UNIT_ASSERT(comm_size == vec_size);
355 
356  for (std::size_t i = 0; i < vec_size; ++i)
357  TIMPI_UNIT_ASSERT(vals[i] == std::string(i + 1, '0' + i));
358 #endif
359  }
360 
362  {
363  std::vector<processor_id_type> vals;
364 
365  std::vector<std::string> send(1), recv;
366 
367  const unsigned int my_rank = TestCommWorld->rank();
368  const unsigned int dest_rank =
369  (my_rank + 1) % TestCommWorld->size();
370  const unsigned int source_rank =
371  (my_rank + TestCommWorld->size() - 1) % TestCommWorld->size();
372 
373  {
374  std::ostringstream os;
375  os << my_rank;
376  send[0] = os.str();
377  }
378 
380  (dest_rank, (void *)(NULL), send.begin(), send.end(),
381  source_rank, (void *)(NULL),
382  std::back_inserter(recv),
383  (std::string*)NULL);
384 
385  TIMPI_UNIT_ASSERT(recv.size() == std::size_t(1));
386 
387  std::string check;
388  {
389  std::ostringstream os;
390  os << source_rank;
391  check = os.str();
392  }
393 
394  TIMPI_UNIT_ASSERT(recv[0] == check);
395  }
396 
398  {
399  // Number of entries in the map on each processor
400  const unsigned int n_map_entries = 147;
401 
402  // Offset between blocks of entries; must exceed n_map_entries
403  const unsigned int map_offset = 1000;
404 
405  // Large enough strings that we'll exceed a single packed buffer
406  const unsigned int string_size = 32768;
407 
408  // Each entry in the map will be the same test_string
409  std::string test_string(/*count*/string_size, 'a');
410 
411  std::map<unsigned int, std::string> map_of_strings;
412 
413  // Use an offset so that the map keys do not overlap
414  const unsigned int my_offset =
415  (TestCommWorld->rank() + 1) * map_offset;
416  for (unsigned int i=0; i != n_map_entries; ++i)
417  map_of_strings[my_offset + i] = test_string;
418 
419  TestCommWorld->set_union(map_of_strings);
420 
421  TIMPI_UNIT_ASSERT(map_of_strings.size() ==
422  TestCommWorld->size() * n_map_entries);
423 
424  TIMPI_UNIT_ASSERT(map_of_strings.begin()->first == map_offset);
425  }
426 
427 
428  void testPushPackedImpl(int M)
429  {
430  const int size = TestCommWorld->size(),
431  rank = TestCommWorld->rank();
432 
433  std::map<processor_id_type, std::multiset<std::string>>
434  data, received_data;
435 
436  auto stringy_number = [] (int number)
437  {
438  std::string digit_strings [10] = {"zero", "one", "two",
439  "three", "four", "five", "six", "seven", "eight", "nine"};
440 
441  std::string returnval = "done";
442  while (number)
443  {
444  returnval = digit_strings[number%10]+" "+returnval;
445  number = number/10;
446  };
447 
448  return returnval;
449  };
450 
451  for (int d=0; d != M; ++d)
452  {
453  int diffsize = std::abs(d-rank);
454  int diffsqrt = std::sqrt(diffsize);
455  if (diffsqrt*diffsqrt == diffsize)
456  for (int i=-1; i != diffsqrt; ++i)
457  data[d].insert(stringy_number(d));
458  }
459 
460  auto collect_data =
461  [&received_data]
462  (processor_id_type pid,
463  const typename std::multiset<std::string> & multiset_received)
464  {
465  auto & received = received_data[pid];
466  received.insert(multiset_received.begin(), multiset_received.end());
467  };
468 
469  // Ensure that no const_cast perfidy in parallel_sync.h messes up
470  // our original data
471  std::map<processor_id_type, std::multiset<std::string>> preserved_data {data};
472 
473  // Do the push
474  void * context = nullptr;
475  TIMPI::push_parallel_packed_range(*TestCommWorld, data, context, collect_data);
476 
477  // Test the sent data, which shouldn't have changed
478  TIMPI_UNIT_ASSERT(preserved_data.size() == data.size());
479  for (const auto & pair: preserved_data)
480  {
481  const auto &pd_ms = pair.second;
482  const auto &d_ms = data[pair.first];
483  TIMPI_UNIT_ASSERT(pd_ms.size() == d_ms.size());
484  for (auto entry : pd_ms)
485  TIMPI_UNIT_ASSERT(pd_ms.count(entry) == d_ms.count(entry));
486  }
487 
488  // Test the received results, for each processor id p we're in
489  // charge of.
490  std::vector<std::size_t> checked_sizes(size, 0);
491  for (int p=rank; p < M; p += size)
492  for (int srcp=0; srcp != size; ++srcp)
493  {
494  int diffsize = std::abs(srcp-p);
495  int diffsqrt = std::sqrt(diffsize);
496  if (diffsqrt*diffsqrt != diffsize)
497  {
498  if (received_data.count(srcp))
499  {
500  const std::multiset<std::string> & datum = received_data[srcp];
501  TIMPI_UNIT_ASSERT
502  (std::count(datum.begin(), datum.end(),
503  stringy_number(p)) == std::ptrdiff_t(0));
504  }
505  continue;
506  }
507 
508  TIMPI_UNIT_ASSERT(received_data.count(srcp) == std::size_t(1));
509  const std::multiset<std::string> & datum = received_data[srcp];
510  TIMPI_UNIT_ASSERT
511  (std::count(datum.begin(), datum.end(), stringy_number(p)) ==
512  std::ptrdiff_t(diffsqrt+1));
513  checked_sizes[srcp] += diffsqrt+1;
514  }
515 
516  for (int srcp=0; srcp != size; ++srcp)
517  TIMPI_UNIT_ASSERT(checked_sizes[srcp] == received_data[srcp].size());
518 
519  }
520 
522  {
524  }
525 
527  {
528  testPushPackedImpl((TestCommWorld->size() + 4) * 2);
529  }
530 
531  template <typename FillFunctor, typename PushFunctor>
532  void testPushPackedNestedImpl(FillFunctor fill_functor, PushFunctor push_functor)
533  {
534  const int size = TestCommWorld->size(),
535  rank = TestCommWorld->rank();
536 
537  typedef decltype(fill_functor(0)) fill_type;
538 
539  typedef std::vector<fill_type> vec_type;
540  std::map<processor_id_type, vec_type> data, received_data;
541 
542  for (int d=0; d != size; ++d)
543  {
544  int diffsize = std::abs(d-rank);
545  int diffsqrt = std::sqrt(diffsize);
546  if (diffsqrt*diffsqrt == diffsize)
547  for (int i=-1; i != diffsqrt; ++i)
548  data[d].push_back(fill_functor(d));
549  }
550 
551  auto collect_data =
552  [&received_data]
553  (processor_id_type pid,
554  const vec_type & vec_received)
555  {
556  auto & received = received_data[pid];
557  received = vec_received;
558  };
559 
560  // Ensure that no const_cast perfidy in parallel_sync.h messes up
561  // our original data
562  std::map<processor_id_type, vec_type> preserved_data {data};
563 
564  // Do the push
565  push_functor(data, collect_data);
566 
567  // Test the sent data, which shouldn't have changed
568  TIMPI_UNIT_ASSERT(preserved_data == data);
569 
570  // Test the received results, for each processor id p we're in
571  // charge of.
572  std::vector<std::size_t> checked_sizes(size, 0);
573  for (int srcp=0; srcp != size; ++srcp)
574  {
575  int diffsize = std::abs(srcp-rank);
576  int diffsqrt = std::sqrt(diffsize);
577  if (diffsqrt*diffsqrt != diffsize)
578  {
579  TIMPI_UNIT_ASSERT(!received_data.count(srcp));
580  continue;
581  }
582 
583  TIMPI_UNIT_ASSERT(received_data.count(srcp));
584  const auto & rec = received_data[srcp];
585  TIMPI_UNIT_ASSERT(rec.size() == std::size_t(diffsqrt+1));
586 
587  for (auto & tup : rec)
588  TIMPI_UNIT_ASSERT(tup == fill_functor(rank));
589  }
590  }
591 
592 
594  {
595  // Do the push explicitly with a packed_range function
596  auto explicitly_packed_push = [](auto & data, auto & collect_data) {
597  void * context = nullptr;
598  TIMPI::push_parallel_packed_range(*TestCommWorld, data, context, collect_data);
599  };
600 
601  typedef std::tuple<unsigned int, std::vector<char>, unsigned int,
602  unsigned int, unsigned int, unsigned int> tuple_type;
603  auto fill_tuple= [] (int n) {
604  return tuple_type(n, fake_stringy_number(n), n, n, n, n);
605  };
606 
607  testPushPackedNestedImpl(fill_tuple, explicitly_packed_push);
608  }
609 
610 
612  {
613  // Do the push implicitly with an auto-dispatching function
614  auto implicitly_packed_push = [](auto & data, auto & collect_data) {
615  TIMPI::push_parallel_vector_data(*TestCommWorld, data, collect_data);
616  };
617 
618  typedef std::tuple<unsigned int, std::vector<char>, unsigned int,
619  unsigned int, unsigned int, unsigned int> tuple_type;
620  auto fill_tuple= [] (int n) {
621  return tuple_type(n, fake_stringy_number(n), n, n, n, n);
622  };
623 
624  testPushPackedNestedImpl(fill_tuple, implicitly_packed_push);
625  }
626 
627 
629  {
630  typedef std::tuple<std::unordered_map<unsigned int, std::string>> tuple_type;
631 #ifdef TIMPI_HAVE_CXX17 // static_assert without message
632  static_assert(Has_buffer_type<Packing<std::string>>::value);
633  static_assert(TIMPI::StandardType<std::pair<unsigned int, unsigned int>>::is_fixed_type);
634  static_assert(TIMPI::StandardType<std::pair<const unsigned int, unsigned int>>::is_fixed_type);
635  static_assert(Has_buffer_type<Packing<std::unordered_map<unsigned int, unsigned int>>>::value);
636  static_assert(Has_buffer_type<Packing<std::pair<std::string, std::string>>>::value);
637  static_assert(Has_buffer_type<Packing<std::pair<const std::string, std::string>>>::value);
638  static_assert(Has_buffer_type<Packing<std::unordered_map<std::string, std::string>>>::value);
639  static_assert(Has_buffer_type<Packing<std::pair<unsigned int, std::string>>>::value);
640  static_assert(Has_buffer_type<Packing<std::pair<const unsigned int, std::string>>>::value);
641  static_assert(Has_buffer_type<Packing<std::unordered_map<unsigned int, std::string>>>::value);
642  static_assert(Has_buffer_type<Packing<tuple_type>>::value);
643 #endif
644 
645  auto fill_tuple = [] (int n)
646  {
647  tuple_type returnval;
648  (std::get<0>(returnval))[n] = stringy_number(n);
649  (std::get<0>(returnval))[n+1] = stringy_number(n+1);
650  return returnval;
651  };
652 
653  auto implicitly_packed_push = [](auto & data, auto & collect_data) {
654  TIMPI::push_parallel_vector_data(*TestCommWorld, data, collect_data);
655  };
656 
657  testPushPackedNestedImpl(fill_tuple, implicitly_packed_push);
658  }
659 
660 
661 // A failure case I caught downstream
663  {
664  typedef std::tuple<std::size_t, int, std::unordered_map<unsigned int, std::string>> tuple_type;
665 
666  auto fill_tuple = [] (int n)
667  {
668  tuple_type returnval;
669  std::get<0>(returnval) = n;
670  std::get<1>(returnval) = n;
671  (std::get<2>(returnval))[n] = stringy_number(n);
672  (std::get<2>(returnval))[n+1] = stringy_number(n+1);
673  return returnval;
674  };
675 
676  auto implicitly_packed_push = [](auto & data, auto & collect_data) {
677  TIMPI::push_parallel_vector_data(*TestCommWorld, data, collect_data);
678  };
679 
680  testPushPackedNestedImpl(fill_tuple, implicitly_packed_push);
681  }
682 
683 
684 #if __cplusplus > 201402L
686  {
687  const int size = TestCommWorld->size(),
688  rank = TestCommWorld->rank();
689 
690  std::map<processor_id_type, std::vector<std::unique_ptr<int>>>
691  data, received_data;
692 
693  for (int d=0; d != M; ++d)
694  {
695  int diffsize = std::abs(d-rank);
696  int diffsqrt = std::sqrt(diffsize);
697  if (diffsqrt*diffsqrt == diffsize)
698  for (int i=-1; i != diffsqrt; ++i)
699  data[d].emplace_back(std::make_unique<int>(d));
700  }
701 
702  auto collect_data =
703  [&received_data]
704  (processor_id_type pid,
705  std::vector<std::unique_ptr<int>> && vector_received)
706  {
707  auto & received = received_data[pid];
708  for (auto & val : vector_received)
709  received.emplace_back(std::move(val));
710  };
711 
712  void * context = nullptr;
713  TIMPI::push_parallel_packed_range(*TestCommWorld, std::move(data), context, collect_data);
714 
715  // Test the received results, for each processor id p we're in
716  // charge of.
717  std::vector<std::size_t> checked_sizes(size, 0);
718  for (int p=rank; p < M; p += size)
719  for (int srcp=0; srcp != size; ++srcp)
720  {
721  int diffsize = std::abs(srcp-p);
722  int diffsqrt = std::sqrt(diffsize);
723  if (diffsqrt*diffsqrt != diffsize)
724  {
725  if (received_data.count(srcp))
726  {
727  std::size_t count = 0;
728  for (const auto & val : received_data[srcp])
729  if (*val == p)
730  ++count;
731 
732  TIMPI_UNIT_ASSERT(count == (std::size_t)std::ptrdiff_t(0));
733  }
734  continue;
735  }
736 
737  TIMPI_UNIT_ASSERT(received_data.count(srcp) == std::size_t(1));
738 
739  std::size_t count = 0;
740  for (const auto & val : received_data[srcp])
741  if (*val == p)
742  ++count;
743 
744  TIMPI_UNIT_ASSERT(count == (std::size_t)std::ptrdiff_t(diffsqrt+1));
745  checked_sizes[srcp] += diffsqrt+1;
746  }
747 
748  for (int srcp=0; srcp != size; ++srcp)
749  TIMPI_UNIT_ASSERT(checked_sizes[srcp] == received_data[srcp].size());
750  }
751 
753  {
755  }
756 
758  {
759  testPushPackedImpl((TestCommWorld->size() + 4) * 2);
760  }
761 #endif
762 
763 int main(int argc, const char * const * argv)
764 {
765  TIMPI::TIMPIInit init(argc, argv);
766  TestCommWorld = &init.comm();
767 
776 
778 
779  testPushPacked();
785 #if __cplusplus > 201402L
788 #endif
789 
791  testPushPacked();
797 #if __cplusplus > 201402L
800 #endif
801 
803  testPushPacked();
809 #if __cplusplus > 201402L
812 #endif
813 
814  return 0;
815 }
std::vector< char > fake_stringy_number(int number)
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
Take a vector of length this->size(), and fill in recv[processor_id] = the value of send on that proc...
std::ptrdiff_t difference_type
void testPushPackedFailureCase()
void testPushPackedOversized()
void sync_type(const SyncType st)
Explicitly sets the SyncType used for sync operations.
Definition: communicator.h:343
void testPushPackedDispatch()
void testPushPackedMoveOversized()
The TIMPIInit class, when constructed, initializes any dependent libraries (e.g.
Definition: timpi_init.h:57
static void pack(const std::unique_ptr< int > &object, Iter data_out, const void *)
void push_parallel_packed_range(const Communicator &comm, MapToVectors &&data, Context *context, const ActionFunctor &act_on_data)
Send and receive and act on vectors of data.
void testPushPackedMove()
void my_resize(T &container, std::size_t size)
processor_id_type rank() const
Definition: communicator.h:208
Communicator * TestCommWorld
void testContainerAllGather()
void allgather_packed_range(Context *context, Iter range_begin, const Iter range_end, OutputIter out, std::size_t approx_buffer_size=1000000) const
Take a range of local variables, combine it with ranges from all processors, and write the output to ...
void testPushPacked()
Templated class to provide the appropriate MPI datatype for use with built-in C types or simple C++ c...
Definition: standard_type.h:83
Define data types and (un)serialization functions for use when encoding a potentially-variable-size o...
Definition: packing.h:60
null_output_iterator & operator*()
void testVectorStringAllGather()
int main(int argc, const char *const *argv)
null_output_iterator operator++(int)
void testNullSendReceive()
Encapsulates the MPI_Comm object.
Definition: communicator.h:108
static unsigned int packable_size(const std::unique_ptr< int > &, const void *)
static unsigned int packed_size(typename std::vector< int >::const_iterator)
processor_id_type size() const
Definition: communicator.h:211
void push_parallel_vector_data(const Communicator &comm, MapToVectors &&data, const ActionFunctor &act_on_data)
Send and receive and act on vectors of data.
std::string stringy_number(int number)
uint8_t processor_id_type
Definition: communicator.h:54
void operator=(const T2 &)
void testPushPackedNestedImpl(FillFunctor fill_functor, PushFunctor push_functor)
null_output_iterator & operator++()
void testNestingAllGather()
void testGettableStringAllGather()
static std::unique_ptr< int > unpack(BufferIter in, const void *)
void testNullAllGather()
void testArrayStringAllGather()
void testListStringAllGather()
std::output_iterator_tag iterator_category
void testContainerSendReceive()
void testLargeSetUnion()
auto my_get(T &container) -> decltype(std::get< i >(container))
void testPushPackedImpl(int M)
void testPairStringAllGather()
void send_receive_packed_range(const unsigned int dest_processor_id, const Context1 *context1, RangeIter send_begin, const RangeIter send_end, const unsigned int source_processor_id, Context2 *context2, OutputIter out, const T *output_type, const MessageTag &send_tag=no_tag, const MessageTag &recv_tag=any_tag, std::size_t approx_buffer_size=1000000) const
Send a range-of-pointers to one processor while simultaneously receiving another range from a (potent...
void testPushPackedNested()
void testTupleStringAllGather()
void testPushPackedImplMove(int M)
void testPushPackedOneTuple()
const Communicator & comm() const
Returns the Communicator created by this object, which will be a compatibility shim if MPI is not ena...
Definition: timpi_init.h:100
void set_union(T &data, const unsigned int root_id) const
Take a container (set, map, unordered_set, multimap, etc) of local variables on each processor...