2 Pup routines for STL classes.
4 After including this header, you can parameter-marshall
5 a variable consisting of STL containers such as vectors,
6 lists, maps, strings, or pairs.
8 This includes variables of type "std::list<int>", or even
9 "std::map<double, std::vector<std::string> >".
11 NOT included are the rarer types like valarray or slice.
13 Orion Sky Lawlor, olawlor@acm.org, 7/22/2002
15 #ifndef _UIUC_CHARM_PUP_STL_H
16 #define _UIUC_CHARM_PUP_STL_H
18 #include <conv-config.h>
20 /*It's kind of annoying that we have to drag all these headers in
21 just so the std:: parameter declarations will compile.
28 #include <forward_list>
33 #include <unordered_map>
34 #include <unordered_set>
37 #include <utility> /*for std::pair*/
43 /*************** Simple classes ***************/
44 // Non-const version is required for puping std::pair
45 template <class A
,class B
>
46 inline void operator|(er
&p
,typename
std::pair
<A
,B
> &v
);
47 template <class A
,class B
>
48 inline void operator|(er
&p
,typename
std::pair
<const A
,B
> &v
);
50 inline void operator|(er
&p
,std::complex<T
> &v
);
52 inline void operator|(er
&p
, std::unique_ptr
<T
, std::default_delete
<T
>> &ptr
);
53 template <class charType
>
54 inline void operator|(er
&p
,typename
std::basic_string
<charType
> &v
);
55 inline void operator|(er
&p
,std::string
&v
);
56 template <class container
>
57 inline size_t PUP_stl_container_size(er
&p
,container
&c
);
58 template <class container
, class dtype
>
59 inline void PUP_stl_container_items(er
&p
, container
&c
, size_t nElem
);
60 template <> inline void PUP_stl_container_items
<std::vector
<bool>,bool>(er
&p
, std::vector
<bool> &c
, size_t nElem
);
61 template <class container
,class dtype
>
62 inline void PUP_stl_container(er
&p
,container
&c
);
63 template <class container
,class dtype
>
64 inline void PUP_stl_map(er
&p
,container
&c
);
66 inline void operator|(er
&p
,typename
std::vector
<T
> &v
);
68 inline void operator|(er
&p
,typename
std::deque
<T
> &d
);
70 inline void operator|(er
&p
,typename
std::list
<T
> &v
);
72 inline void operator|(er
&p
,typename
std::forward_list
<T
> &fl
);
73 template <class V
,class T
,class Cmp
>
74 inline void operator|(er
&p
,typename
std::map
<V
,T
,Cmp
> &m
);
75 template <class V
,class T
,class Cmp
>
76 inline void operator|(er
&p
,typename
std::multimap
<V
,T
,Cmp
> &m
);
78 inline void operator|(er
&p
,typename
std::set
<T
> &m
);
79 template <class T
,class Cmp
>
80 inline void operator|(er
&p
,typename
std::multiset
<T
,Cmp
> &m
);
81 template <> inline void operator|(er
&p
,std::vector
<bool> &v
);
83 template <class A
,class B
>
84 inline void operator|(er
&p
,typename
std::pair
<A
,B
> &v
)
86 p
.syncComment(sync_index
);
88 p
.syncComment(sync_item
);
91 // Const version is required for puping std::map
92 template <class A
,class B
>
93 inline void operator|(er
&p
,typename
std::pair
<const A
,B
> &v
)
95 p
.syncComment(sync_index
);
96 p
|*(A
*)&v
.first
; /* cast away constness on A */
97 p
.syncComment(sync_item
);
101 inline void operator|(er
&p
,std::complex<T
> &v
)
103 T re
=v
.real(), im
=v
.imag();
105 v
=std::complex<T
>(re
,im
);
107 template <class charType
>
108 inline void operator|(er
&p
,typename
std::basic_string
<charType
> &v
)
110 size_t nChar
=v
.length();
112 if (p
.isUnpacking()) { //Unpack to temporary buffer
113 charType
*buf
=new charType
[nChar
];
115 v
=std::basic_string
<charType
>(buf
,nChar
);
118 else /*packing*/ { //Do packing in-place from data
119 //Have to cast away constness here
120 p((charType
*)v
.data(),nChar
);
123 inline void operator|(er
&p
,std::string
&v
)
125 p
.syncComment(sync_begin_object
,"std::string");
126 size_t nChar
=v
.length();
128 if (p
.isUnpacking()) { //Unpack to temporary buffer
129 char *buf
=new char[nChar
];
131 v
=std::basic_string
<char>(buf
,nChar
);
134 else /*packing*/ { //Do packing in-place from data
135 //Have to cast away constness here
136 p((char *)v
.data(),nChar
);
138 p
.syncComment(sync_end_object
);
141 /**************** Containers *****************/
143 template <class container
>
144 void reserve_if_applicable(container
&c
, size_t nElem
)
149 template <class dtype
>
150 void reserve_if_applicable(std::deque
<dtype
> &c
, size_t nElem
)
154 template <class dtype
>
155 void reserve_if_applicable(std::list
<dtype
> &c
, size_t nElem
)
159 template <class dtype
>
160 void reserve_if_applicable(std::forward_list
<dtype
> &c
, size_t nElem
)
164 template <class K
, class V
>
165 void reserve_if_applicable(std::map
<K
, V
> &c
, size_t nElem
)
169 template <class K
, class V
>
170 void reserve_if_applicable(std::multimap
<K
, V
> &c
, size_t nElem
)
175 //Impl. util: pup the length of a container
176 template <class container
>
177 inline size_t PUP_stl_container_size(er
&p
,container
&c
) {
178 size_t nElem
=c
.size();
183 //Impl. util: pup each current item of a container (no allocation)
184 template <class container
, class dtype
>
185 inline void PUP_stl_container_items(er
&p
, container
&c
, size_t nElem
)
189 reserve_if_applicable(c
, nElem
);
190 for (size_t i
= 0; i
< nElem
; ++i
)
192 p
.syncComment(sync_item
);
193 detail::TemporaryObjectHolder
<dtype
> n
;
195 c
.emplace_back(std::move(n
.t
));
200 for (typename
container::iterator it
=c
.begin(); it
!=c
.end(); ++it
)
202 p
.syncComment(sync_item
);
203 // Cast away the constness (needed for std::set)
209 // Specialized to work with vector<bool>
211 inline void PUP_stl_container_items
<std::vector
<bool>, bool>(er
&p
, std::vector
<bool> &c
, size_t nElem
)
216 std::deque
<bool> q(c
.begin(), c
.end());
218 for (std::deque
<bool>::iterator it
= q
.begin(); it
!= q
.end(); it
++)
220 p
.syncComment(sync_item
);
225 template <class container
,class dtype
>
226 inline void PUP_stl_container(er
&p
,container
&c
) {
227 p
.syncComment(sync_begin_array
);
228 size_t nElem
=PUP_stl_container_size(p
,c
);
229 PUP_stl_container_items
<container
, dtype
>(p
, c
, nElem
);
230 p
.syncComment(sync_end_array
);
233 template <class container
, class K
, class V
>
234 inline void PUP_stl_map(er
&p
,container
&c
) {
235 p
.syncComment(sync_begin_list
);
236 size_t nElem
=PUP_stl_container_size(p
,c
);
238 { //Unpacking: Extract each element and insert:
239 reserve_if_applicable(c
, nElem
);
240 for (size_t i
=0;i
<nElem
;i
++)
242 detail::TemporaryObjectHolder
<K
> k
;
243 detail::TemporaryObjectHolder
<V
> v
;
245 // keep in sync with std::pair
246 p
.syncComment(sync_index
);
248 p
.syncComment(sync_item
);
251 c
.emplace(std::piecewise_construct
, std::forward_as_tuple(std::move(k
.t
)), std::forward_as_tuple(std::move(v
.t
)));
261 p
.syncComment(sync_end_list
);
265 inline void operator|(er
&p
, typename
std::vector
<T
> &v
) {
266 if (PUP::as_bytes
<T
>::value
) {
267 size_t nElem
= PUP_stl_container_size(p
, v
);
268 if (p
.isUnpacking()) {
272 PUParray(p
, v
.data(), nElem
);
274 PUP_stl_container
<std::vector
<T
>, T
>(p
, v
);
279 inline void operator|(er
&p
,typename
std::deque
<T
> &d
)
280 { PUP_stl_container
<std::deque
<T
>,T
>(p
,d
); }
282 inline void operator|(er
&p
,typename
std::list
<T
> &v
)
283 { PUP_stl_container
<std::list
<T
>,T
>(p
,v
); }
285 inline void operator|(er
&p
,typename
std::forward_list
<T
> &fl
)
286 { PUP_stl_container
<std::forward_list
<T
>,T
>(p
,fl
); }
288 template <class V
,class T
,class Cmp
>
289 inline void operator|(er
&p
,typename
std::map
<V
,T
,Cmp
> &m
)
290 { PUP_stl_map
<std::map
<V
,T
,Cmp
>,V
,T
>(p
,m
); }
291 template <class V
,class T
,class Cmp
>
292 inline void operator|(er
&p
,typename
std::multimap
<V
,T
,Cmp
> &m
)
293 { PUP_stl_map
<std::multimap
<V
,T
,Cmp
>,V
,T
>(p
,m
); }
294 /// \warning This does not work with custom hash functions that have state
295 template <class V
,class T
,class Cmp
>
296 inline void operator|(er
&p
,typename
std::unordered_map
<V
,T
,Cmp
> &m
)
297 { PUP_stl_map
<std::unordered_map
<V
,T
,Cmp
>,V
,T
>(p
,m
); }
298 template <class V
,class T
,class Cmp
>
299 inline void operator|(er
&p
,typename
std::unordered_multimap
<V
,T
,Cmp
> &m
)
300 { PUP_stl_map
<std::unordered_multimap
<V
,T
,Cmp
>,V
,T
>(p
,m
); }
303 inline void operator|(er
&p
,typename
std::set
<T
> &m
)
304 { PUP_stl_container
<std::set
<T
>,T
>(p
,m
); }
305 template <class T
,class Cmp
>
306 inline void operator|(er
&p
,typename
std::multiset
<T
,Cmp
> &m
)
307 { PUP_stl_container
<std::multiset
<T
,Cmp
>,T
>(p
,m
); }
309 inline void operator|(er
&p
,typename
std::unordered_set
<T
> &m
)
310 { PUP_stl_container
<std::unordered_set
<T
>,T
>(p
,m
); }
311 template <class T
,class Cmp
>
312 inline void operator|(er
&p
,typename
std::unordered_multiset
<T
,Cmp
> &m
)
313 { PUP_stl_container
<std::unordered_multiset
<T
,Cmp
>,T
>(p
,m
); }
315 // Specialized to work with vector<bool>, which doesn't
316 // have data() or shrink_to_fit() members
318 inline void operator|(er
&p
,std::vector
<bool> &v
) {
319 PUP_stl_container
<std::vector
<bool>, bool>(p
, v
);
322 // Distributed under the MIT License.
323 // The following allows for pupping STL structures with pointers to abstract
324 // base classes. Requires is used in place of enable_if_t to enforce
325 // requirements on template parameters for the following PUP methods.
327 struct requires_impl
{
328 using template_error_type_failed_to_meet_requirements_on_template_parameters
333 struct requires_impl
<false> {};
336 using Requires
= typename requires_impl
<
337 B
>::template_error_type_failed_to_meet_requirements_on_template_parameters
;
339 template <typename T
, std::size_t N
,
340 Requires
<!PUP::as_bytes
<T
>::value
> = nullptr>
341 inline void pup(PUP::er
& p
, std::array
<T
, N
>& a
) {
342 std::for_each(a
.begin(), a
.end(), [&p
](T
& t
) { p
| t
; });
345 template <typename T
, std::size_t N
,
346 Requires
<PUP::as_bytes
<T
>::value
> = nullptr>
347 inline void pup(PUP::er
& p
, std::array
<T
, N
>& a
) {
348 PUParray(p
, a
.data(), N
);
351 template <typename T
, std::size_t N
>
352 inline void operator|(er
& p
, std::array
<T
, N
>& a
) {
356 template <typename T
, Requires
<std::is_enum
<T
>::value
> = nullptr>
357 inline void operator|(PUP::er
& p
, T
& s
) {
358 pup_bytes(&p
, static_cast<void*>(&s
), sizeof(T
));
361 template <size_t N
= 0, typename
... Args
,
362 Requires
<0 == sizeof...(Args
)> = nullptr>
363 void pup_tuple_impl(PUP::er
& /* p */, std::tuple
<Args
...>& /* t */) {
366 template <size_t N
= 0, typename
... Args
,
367 Requires
<(0 < sizeof...(Args
) && 0 == N
)> = nullptr>
368 void pup_tuple_impl(PUP::er
& p
, std::tuple
<Args
...>& t
) {
372 template <size_t N
, typename
... Args
,
373 Requires
<(sizeof...(Args
) > 0 && N
> 0)> = nullptr>
374 void pup_tuple_impl(PUP::er
& p
, std::tuple
<Args
...>& t
) {
376 pup_tuple_impl
<N
- 1>(p
, t
);
379 template <typename
... Args
>
380 inline void pup(PUP::er
& p
, std::tuple
<Args
...>& t
) {
381 pup_tuple_impl
<sizeof...(Args
) - 1>(p
, t
);
384 template <typename
... Args
>
385 inline void operator|(PUP::er
& p
, std::tuple
<Args
...>& t
) {
389 template <typename T
,
390 Requires
<!std::is_base_of
<PUP::able
, T
>::value
> = nullptr>
391 inline void pup(PUP::er
& p
, std::unique_ptr
<T
>& t
) {
392 bool is_nullptr
= nullptr == t
;
396 if (p
.isUnpacking()) {
402 if (p
.isUnpacking()) {
408 template <typename T
, Requires
<std::is_base_of
<PUP::able
, T
>::value
> = nullptr>
409 inline void pup(PUP::er
& p
, std::unique_ptr
<T
>& t
) {
411 if (p
.isUnpacking()) {
413 t
= std::unique_ptr
<T
>(t1
);
420 template <typename T
>
421 inline void operator|(PUP::er
& p
, std::unique_ptr
<T
>& t
) {
425 } // end of namespace PUP