PupStlCpp11.hpp
Go to the documentation of this file.
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 /// \file
5 /// PUP routines for new C+11 STL containers and other standard
6 /// library objects Charm does not provide implementations for
7 
8 #pragma once
9 
10 #include <algorithm>
11 #include <array>
12 #include <deque>
13 #include <initializer_list>
14 #include <memory>
15 #include <pup_stl.h>
16 #include <tuple>
17 #include <unordered_map>
18 #include <unordered_set>
19 #include <utility>
20 
21 #include "Utilities/Requires.hpp"
22 
23 namespace PUP {
24 
25 // @{
26 /// \ingroup ParallelGroup
27 /// Serialization of std::array for Charm++
28 template <typename T, std::size_t N,
30 inline void pup(PUP::er& p, std::array<T, N>& a) { // NOLINT
31  std::for_each(a.begin(), a.end(), [&p](auto& t) { p | t; });
32 }
33 
34 template <typename T, std::size_t N,
36 inline void pup(PUP::er& p, std::array<T, N>& a) { // NOLINT
37  PUParray(p, a.data(), N);
38 }
39 // @}
40 
41 /// \ingroup ParallelGroup
42 /// Serialization of std::array for Charm++
43 template <typename T, std::size_t N>
44 inline void operator|(er& p, std::array<T, N>& a) { // NOLINT
45  pup(p, a);
46 }
47 
48 /// \ingroup ParallelGroup
49 /// Serialization of std::deque for Charm++
50 template <typename T>
51 inline void pup(PUP::er& p, std::deque<T>& d) { // NOLINT
52  size_t number_elem = PUP_stl_container_size(p, d);
53 
54  if (p.isUnpacking()) {
55  for (size_t i = 0; i < number_elem; ++i) {
56  T v;
57  p | v;
58  d.emplace_back(std::move(v));
59  }
60  } else {
61  for (auto& v : d) {
62  p | v;
63  }
64  }
65 }
66 
67 /// \ingroup ParallelGroup
68 /// Serialization of std::deque for Charm++
69 template <typename T>
70 inline void operator|(er& p, std::deque<T>& d) { // NOLINT
71  pup(p, d);
72 }
73 
74 /// \ingroup ParallelGroup
75 /// Serialization of std::unordered_map for Charm++
76 /// \warning This does not work with custom hash functions that have state
77 template <typename K, typename V, typename H>
78 inline void pup(PUP::er& p, std::unordered_map<K, V, H>& m) { // NOLINT
79  size_t number_elem = PUP_stl_container_size(p, m);
80 
81  if (p.isUnpacking()) {
82  for (size_t i = 0; i < number_elem; ++i) {
83  std::pair<K, V> kv;
84  p | kv;
85  m.emplace(std::move(kv));
86  }
87  } else {
88  for (auto& kv : m) {
89  p | kv;
90  }
91  }
92 }
93 
94 /// \ingroup ParallelGroup
95 /// Serialization of std::unordered_map for Charm++
96 /// \warning This does not work with custom hash functions that have state
97 template <typename K, typename V, typename H>
98 inline void operator|(er& p, std::unordered_map<K, V, H>& m) { // NOLINT
99  pup(p, m);
100 }
101 
102 /// \ingroup ParallelGroup
103 /// Serialization of std::unordered_set for Charm++
104 template <typename T>
105 inline void pup(PUP::er& p, std::unordered_set<T>& s) { // NOLINT
106  size_t number_elem = PUP_stl_container_size(p, s);
107 
108  if (p.isUnpacking()) {
109  for (size_t i = 0; i < number_elem; ++i) {
110  T element;
111  p | element;
112  s.emplace(std::move(element));
113  }
114  } else {
115  // This intenionally is not a reference because at least with stdlibc++ the
116  // reference code does not compile because it turns the dereferenced
117  // iterator into a value
118  for (T e : s) {
119  p | e;
120  }
121  }
122 }
123 
124 /// \ingroup ParallelGroup
125 /// Serialization of std::unordered_set for Charm++
126 template <class T>
127 inline void operator|(er& p, std::unordered_set<T>& s) { // NOLINT
128  pup(p, s);
129 }
130 
131 /// \ingroup ParallelGroup
132 /// Serialization of enum for Charm++
133 ///
134 /// \note This requires a change to Charm++ to work
135 template <typename T, Requires<std::is_enum<T>::value> = nullptr>
136 inline void operator|(PUP::er& p, T& s) { // NOLINT
137  pup_bytes(&p, static_cast<void*>(&s), sizeof(T));
138 }
139 
140 namespace detail {
141 // clang-tidy: no references
142 template <typename... Args, size_t... Is>
143 void pup_tuple_impl(PUP::er& p, std::tuple<Args...>& t, // NOLINT
144  std::index_sequence<Is...> /*meta*/) noexcept {
145  (void)std::initializer_list<char>{(p | std::get<Is>(t), '0')...};
146 }
147 } // namespace detail
148 
149 /// \ingroup ParallelGroup
150 /// Serialization of std::tuple for Charm++
151 template <typename... Args>
152 inline void pup(PUP::er& p, std::tuple<Args...>& t) noexcept { // NOLINT
153  detail::pup_tuple_impl(p, t, std::make_index_sequence<sizeof...(Args)>{});
154 }
155 
156 /// \ingroup ParallelGroup
157 /// Serialization of std::tuple for Charm++
158 template <typename... Args>
159 inline void operator|(PUP::er& p, std::tuple<Args...>& t) { // NOLINT
160  pup(p, t);
161 }
162 
163 // @{
164 /// \ingroup ParallelGroup
165 /// Serialization of a unique_ptr for Charm++
166 template <typename T,
168 inline void pup(PUP::er& p, std::unique_ptr<T>& t) { // NOLINT
169  bool is_nullptr = nullptr == t;
170  p | is_nullptr;
171  if (not is_nullptr) {
172  T* t1;
173  if (p.isUnpacking()) {
174  // clang-tidy: use gsl::owner for owning memory
175  t1 = new T; // NOLINT
176  } else {
177  t1 = t.get();
178  }
179  p | *t1;
180  if (p.isUnpacking()) {
181  t.reset(t1);
182  }
183  }
184 }
185 
186 template <typename T, Requires<std::is_base_of<PUP::able, T>::value> = nullptr>
187 inline void pup(PUP::er& p, std::unique_ptr<T>& t) { // NOLINT
188  T* t1 = nullptr;
189  if (p.isUnpacking()) {
190  p | t1;
191  t = std::unique_ptr<T>(t1);
192  } else {
193  t1 = t.get();
194  p | t1;
195  }
196 }
197 // @}
198 
199 /// \ingroup ParallelGroup
200 /// Serialization of a unique_ptr for Charm++
201 template <typename T>
202 inline void operator|(PUP::er& p, std::unique_ptr<T>& t) { // NOLINT
203  pup(p, t);
204 }
205 } // namespace PUP
Definition: Strahlkorper.hpp:14
Defines the type alias Requires.
Definition: Determinant.hpp:11
typename Requires_detail::requires_impl< B >::template_error_type_failed_to_meet_requirements_on_template_parameters Requires
Express requirements on the template parameters of a function or class, replaces std::enable_if_t ...
Definition: Requires.hpp:67