2 Pack/UnPack Library for UIUC Parallel Programming Lab
3 Orion Sky Lawlor, olawlor@uiuc.edu, 4/5/2000
5 This library allows you to easily pack an array, structure,
6 or object into a memory buffer or disk file, and then read
7 the object back later. The library can also handle translating
8 between different machine representations for integers and floats.
10 Originally, you had to write separate functions for buffer
11 sizing, pack to memory, unpack from memory, pack to disk, and
12 unpack from disk. These functions all perform the exact same function--
13 namely, they list the members of the array, struct, or object.
14 Further, all the functions must agree, or the unpacked data will
15 be garbage. This library allows the user to write *one* function,
16 pup, which will perform all needed packing/unpacking.
28 void pup(PUP::er &p) {
30 PUPn(x);PUPn(y);PUPn(z);
35 A more complex example is:
39 int nArr;//Length of array below
40 double *arr;//Heap-allocated array
44 void pup(PUP::er &p) {
45 PUPn(f); // <- automatically calls foo::pup
47 if (p.isUnpacking()) // <- must allocate array on other side.
49 PUPv(arr,nArr); // <- special syntax for arrays of simple types
57 #include <stdio.h> /*<- for "FILE *" */
58 #include <type_traits>
62 #error "Use pup_c.h for C programs-- pup.h is for C++ programs"
66 #define CmiAbort(x) { printf(x); abort(); }
69 # include "converse.h" // <- for CMK_* defines
71 extern "C" void CmiAbort(const char *msg
);
74 //We need CkMigrateMessage only to distinguish the migration
75 // constructor from all other constructors-- the type
76 // itself has no meaningful fields.
77 typedef struct {int is_only_a_name
;} CkMigrateMessage
;
80 class er
; // Forward declare for all sorts of things
83 * A utility to let classes avoid default construction when they're
84 * about to be unpacked, by defining a constructor that takes a
85 * value of type PUP::reconstruct
87 struct reconstruct
{};
89 template <typename T
, bool b
= std::is_constructible
<T
, reconstruct
>::value
>
90 struct TemporaryObjectHolder
{ };
92 struct TemporaryObjectHolder
<T
, true>
94 typename
std::remove_cv
<typename
std::remove_reference
<T
>::type
>::type t
{reconstruct()};
97 struct TemporaryObjectHolder
<T
, false>
99 typename
std::remove_cv
<typename
std::remove_reference
<T
>::type
>::type t
{};
101 template <typename T
>
102 void operator|(er
&p
, TemporaryObjectHolder
<T
> &t
) {
107 #if CMK_LONG_LONG_DEFINED
108 #define CMK_PUP_LONG_LONG long long
109 #elif CMK___int64_DEFINED
110 #define CMK_PUP_LONG_LONG __int64
114 //Item data types-- these are used to do byte swapping, etc.
116 //(this list must exactly match that in PUPer_xlate)
117 Tchar
=0,Tshort
, Tint
, Tlong
, Tlonglong
,
118 Tuchar
,Tushort
,Tuint
,Tulong
, Tulonglong
,
122 Tfloat
,Tdouble
,Tlongdouble
,
127 dataType_last
//<- for setting table lengths, etc.
130 //This should be a 1-byte unsigned type
131 typedef unsigned char myByte
;
133 //Forward declarations
137 //Used for out-of-order unpacking
139 enum {maxSections
=3};
140 int secTab
[maxSections
+1];//The start of each seek section
141 int nSec
;//Number of sections; current section #
142 int secTabOff
;//Start of the section table, relative to the seek block
147 seekBlock(er
&Np
,int nSections
);
151 //Seek to the given section number (0-based, less than nSections)
152 void seek(int toSection
);
153 //Finish with this seeker (must be called)
156 //An evil hack to avoid inheritance and virtual functions among seekers--
157 // stores the PUP::er specific block start information.
167 //The abstract base class: PUP::er.
170 er(const er
&p
);//You don't want to copy PUP::er's.
172 /// These state bits describe various user-settable properties.
173 enum {IS_USERLEVEL
=0x0004, // If set, this is *not* a migration pup-- it's something else.
174 IS_DELETING
=0x0008, // If set, C & f90 objects should delete themselves after pup
175 IS_COMMENTS
=0x0010, // If set, this PUP::er wants comments and sync codes.
176 IS_RESTARTING
=0x0020 // If set, it is during restarting
178 /// These state bits describe the PUP::er's direction.
179 enum {IS_SIZING
=0x0100,
184 unsigned int PUP_er_state
;
185 explicit /* Makes constructor below behave better */
186 er(unsigned int inType
): PUP_er_state(inType
) {} //You don't want to create raw PUP::er's.
188 virtual ~er();//<- does nothing, but might be needed by some child
190 //State queries (exactly one of these will be true)
191 bool isSizing(void) const {return (PUP_er_state
&IS_SIZING
)!=0?true:false;}
192 bool isPacking(void) const {return (PUP_er_state
&IS_PACKING
)!=0?true:false;}
193 bool isUnpacking(void) const {return (PUP_er_state
&IS_UNPACKING
)!=0?true:false;}
194 const char * typeString() const;
195 unsigned int getStateFlags(void) const {return PUP_er_state
;}
197 //This indicates that the pup routine should free memory during packing.
198 void becomeDeleting(void) {PUP_er_state
|=IS_DELETING
;}
199 bool isDeleting(void) const {return (PUP_er_state
&IS_DELETING
)!=0?true:false;}
201 //This indicates that the pup routine should not call system objects' pups.
202 void becomeUserlevel(void) {PUP_er_state
|=IS_USERLEVEL
;}
203 bool isUserlevel(void) const {return (PUP_er_state
&IS_USERLEVEL
)!=0?true:false;}
205 //This indicates that the pup routine should not call system objects' pups.
206 void becomeRestarting(void) {PUP_er_state
|=IS_RESTARTING
;}
207 bool isRestarting(void) const {return (PUP_er_state
&IS_RESTARTING
)!=0?true:false;}
209 bool hasComments(void) const {return (PUP_er_state
&IS_COMMENTS
)!=0?true:false;}
211 //For single elements, pretend it's an array containing one element
212 void operator()(signed char &v
) {(*this)(&v
,1);}
213 #if CMK_SIGNEDCHAR_DIFF_CHAR
214 void operator()(char &v
) {(*this)(&v
,1);}
216 void operator()(short &v
) {(*this)(&v
,1);}
217 void operator()(int &v
) {(*this)(&v
,1);}
218 void operator()(long &v
) {(*this)(&v
,1);}
219 void operator()(unsigned char &v
) {(*this)(&v
,1);}
220 void operator()(unsigned short &v
) {(*this)(&v
,1);}
221 void operator()(unsigned int &v
) {(*this)(&v
,1);}
222 void operator()(unsigned long &v
) {(*this)(&v
,1);}
223 void operator()(float &v
) {(*this)(&v
,1);}
224 void operator()(double &v
) {(*this)(&v
,1);}
225 #if CMK_LONG_DOUBLE_DEFINED
226 void operator()(long double &v
) {(*this)(&v
,1);}
228 void operator()(bool &v
) {(*this)(&v
,1);}
229 #ifdef CMK_PUP_LONG_LONG
230 void operator()(CMK_PUP_LONG_LONG
&v
) {(*this)(&v
,1);}
231 void operator()(unsigned CMK_PUP_LONG_LONG
&v
) {(*this)(&v
,1);}
234 void operator()(CmiInt16
&v
) {(*this)(&v
,1);}
235 void operator()(CmiUInt16
&v
) {(*this)(&v
,1);}
237 void operator()(void* &v
,void* sig
) {(*this)(&v
,1,sig
);}
241 void operator()(signed char *a
,size_t nItems
)
242 {bytes((void *)a
,nItems
,sizeof(signed char),Tchar
);}
243 #if CMK_SIGNEDCHAR_DIFF_CHAR
244 void operator()(char *a
,size_t nItems
)
245 {bytes((void *)a
,nItems
,sizeof(char),Tchar
);}
247 void operator()(short *a
,size_t nItems
)
248 {bytes((void *)a
,nItems
,sizeof(short),Tshort
);}
249 void operator()(int *a
,size_t nItems
)
250 {bytes((void *)a
,nItems
,sizeof(int),Tint
);}
251 void operator()(long *a
,size_t nItems
)
252 {bytes((void *)a
,nItems
,sizeof(long),Tlong
);}
254 //Unsigned integral types:
255 void operator()(unsigned char *a
,size_t nItems
)
256 {bytes((void *)a
,nItems
,sizeof(unsigned char),Tuchar
);}
257 void operator()(unsigned short *a
,size_t nItems
)
258 {bytes((void *)a
,nItems
,sizeof(unsigned short),Tushort
);}
259 void operator()(unsigned int *a
,size_t nItems
)
260 {bytes((void *)a
,nItems
,sizeof(unsigned int),Tuint
);}
261 void operator()(unsigned long *a
,size_t nItems
)
262 {bytes((void *)a
,nItems
,sizeof(unsigned long),Tulong
);}
264 //Floating-point types:
265 void operator()(float *a
,size_t nItems
)
266 {bytes((void *)a
,nItems
,sizeof(float),Tfloat
);}
267 void operator()(double *a
,size_t nItems
)
268 {bytes((void *)a
,nItems
,sizeof(double),Tdouble
);}
270 #if CMK_LONG_DOUBLE_DEFINED
271 void operator()(long double *a
,size_t nItems
)
272 {bytes((void *)a
,nItems
,sizeof(long double),Tlongdouble
);}
276 void operator()(bool *a
,size_t nItems
)
277 {bytes((void *)a
,nItems
,sizeof(bool),Tbool
);}
279 #ifdef CMK_PUP_LONG_LONG
280 void operator()(CMK_PUP_LONG_LONG
*a
,size_t nItems
)
281 {bytes((void *)a
,nItems
,sizeof(CMK_PUP_LONG_LONG
),Tlonglong
);}
282 void operator()(unsigned CMK_PUP_LONG_LONG
*a
,size_t nItems
)
283 {bytes((void *)a
,nItems
,sizeof(unsigned CMK_PUP_LONG_LONG
),Tulonglong
);}
286 void operator()(CmiInt16
*a
,size_t nItems
)
287 {bytes((void *)a
,nItems
,sizeof(CmiInt16
),Tint128
);}
288 void operator()(CmiUInt16
*a
,size_t nItems
)
289 {bytes((void *)a
,nItems
,sizeof(CmiUInt16
),Tuint128
);}
292 //For pointers: the last parameter is to make it more difficult to call
293 //(should not be used in normal code as pointers may loose meaning across processor)
294 void operator()(void **a
,size_t nItems
,void *pointerSignature
) {
295 (void)pointerSignature
;
296 bytes((void *)a
,nItems
,sizeof(void *),Tpointer
);
299 //For raw memory (n gives number of bytes)
301 // pup void * is error-prune, let's avoid it - Gengbin
302 void operator()(void *a,size_t nBytes)
303 {bytes((void *)a,nBytes,1,Tbyte);}
306 //For allocatable objects (system will new/delete object and call pup routine)
307 void operator()(able
** a
)
309 //For pre- or stack-allocated PUP::able objects-- just call object's pup
310 void operator()(able
& a
);
312 /// A descriptive (but entirely optional) human-readable comment field
313 virtual void comment(const char *message
);
315 /// A 32-bit "synchronization marker" (not human readable).
316 /// Some standard codes are listed under PUP::sync_....
317 virtual void synchronize(unsigned int sync
);
319 /// Insert a synchronization marker and comment into the stream.
320 /// Only applies if this PUP::er wants comments.
321 inline void syncComment(unsigned int sync
,const char *message
=0) {
322 #if CMK_ERROR_CHECKING
325 if (message
) comment(message
);
328 /* empty, to avoid expensive virtual function calls */
332 //Generic bottleneck: pack/unpack n items of size itemSize
333 // and data type t from p. Desc describes the data item
334 virtual void bytes(void *p
,size_t n
,size_t itemSize
,dataType t
) =0;
335 virtual void object(able
** a
);
337 virtual size_t size(void) const { return 0; }
339 //For seeking (pack/unpack in different orders)
340 virtual void impl_startSeek(seekBlock
&s
); /*Begin a seeking block*/
341 virtual size_t impl_tell(seekBlock
&s
); /*Give the current offset*/
342 virtual void impl_seek(seekBlock
&s
,size_t off
); /*Seek to the given offset*/
343 virtual void impl_endSeek(seekBlock
&s
);/*End a seeking block*/
345 //See more documentation before PUP_cmiAllocSizer in pup_cmialloc.h
346 //Must be a CmiAlloced buf while packing
347 virtual void pupCmiAllocBuf(void **msg
) {
349 CmiAbort("Undefined PUPer:Did you use PUP_toMem or PUP_fromMem?\n");
352 //In case source is not CmiAlloced the size can be passed and any
353 //user buf can be converted into a cmialloc'ed buf
354 virtual void pupCmiAllocBuf(void **msg
, size_t size
) {
357 CmiAbort("Undefined PUPer:Did you use PUP_toMem or PUP_fromMem?\n");
362 "Sync" codes are an extra channel to encode data in a pup stream,
363 to indicate higher-order structures in the pup'd objects.
364 Sync codes must follow this grammar:
365 <obj> -> <obj> <obj> | <array> | <list>
366 <obj> -> begin (<obj> system) <obj> end
367 <array> -> begin <obj> (item <obj>)* end
368 <list> -> begin <obj> (index <obj> item <obj>)* end
369 This hack is used, e.g., by the debugger.
372 sync_builtin
=0x70000000, // Built-in, standard sync codes begin here
373 sync_begin
=sync_builtin
+0x01000000, // Sync code at start of collection
374 sync_end
=sync_builtin
+0x02000000, // Sync code at end of collection
375 sync_last_system
=sync_builtin
+0x09000000, // Sync code at end of "system" portion of object
376 sync_array_m
=0x00100000, // Linear-indexed (0..n) array-- use item to separate
377 sync_list_m
=0x00200000, // Some other collection-- use index and item
378 sync_object_m
=0x00300000, // Sync mask for general object
380 sync_begin_array
=sync_begin
+sync_array_m
,
381 sync_begin_list
=sync_begin
+sync_list_m
,
382 sync_begin_object
=sync_begin
+sync_object_m
,
384 sync_end_array
=sync_end
+sync_array_m
,
385 sync_end_list
=sync_end
+sync_list_m
,
386 sync_end_object
=sync_end
+sync_object_m
,
388 sync_item
=sync_builtin
+0x00110000, // Sync code for a list or array item
389 sync_index
=sync_builtin
+0x00120000, // Sync code for index of item in a list
394 /************** PUP::er -- Sizer ******************/
395 //For finding the number of bytes to pack (e.g., to preallocate a memory buffer)
396 class sizer
: public er
{
399 //Generic bottleneck: n items of size itemSize
400 virtual void bytes(void *p
,size_t n
,size_t itemSize
,dataType t
);
402 //Write data to the given buffer
403 sizer(void):er(IS_SIZING
),nBytes(0) {}
405 //Return the current number of bytes to be packed
406 size_t size(void) const {return nBytes
;}
410 inline size_t size(T
&t
) {
411 PUP::sizer p
; p
|t
; return p
.size();
414 /********** PUP::er -- Binary memory buffer pack/unpack *********/
415 class mem
: public er
{ //Memory-buffer packers and unpackers
417 myByte
*origBuf
;//Start of memory buffer
418 myByte
*buf
;//Memory buffer (stuff gets packed into/out of here)
419 mem(unsigned int type
,myByte
*Nbuf
):er(type
),origBuf(Nbuf
),buf(Nbuf
) {}
420 mem(const mem
&p
); //You don't want to copy
421 void operator=(const mem
&p
); // You don't want to copy
423 //For seeking (pack/unpack in different orders)
424 virtual void impl_startSeek(seekBlock
&s
); /*Begin a seeking block*/
425 virtual size_t impl_tell(seekBlock
&s
); /*Give the current offset*/
426 virtual void impl_seek(seekBlock
&s
,size_t off
); /*Seek to the given offset*/
428 //Return the current number of buffer bytes used
429 size_t size(void) const {return buf
-origBuf
;}
431 inline char* get_current_pointer() const {
432 return reinterpret_cast<char*>(buf
);
435 inline void advance(size_t const offset
) {
440 //For packing into a preallocated, presized memory buffer
441 class toMem
: public mem
{
443 //Generic bottleneck: pack n items of size itemSize from p.
444 virtual void bytes(void *p
,size_t n
,size_t itemSize
,dataType t
);
446 //Write data to the given buffer
447 toMem(void *Nbuf
):mem(IS_PACKING
,(myByte
*)Nbuf
) {}
450 inline void toMemBuf(T
&t
,void *buf
, size_t len
) {
453 if (p
.size()!=len
) CmiAbort("Size mismatch during PUP::toMemBuf!\n"
454 "This means your pup routine doesn't match during sizing and packing");
457 //For unpacking from a memory buffer
458 class fromMem
: public mem
{
460 //Generic bottleneck: unpack n items of size itemSize from p.
461 virtual void bytes(void *p
,size_t n
,size_t itemSize
,dataType t
);
463 //Read data from the given buffer
464 fromMem(const void *Nbuf
):mem(IS_UNPACKING
,(myByte
*)Nbuf
) {}
467 inline void fromMemBuf(T
&t
,void *buf
,size_t len
) {
470 if (p
.size()!=len
) CmiAbort("Size mismatch during PUP::fromMemBuf!\n"
471 "This means your pup routine doesn't match during packing and unpacking");
474 /********** PUP::er -- Binary disk file pack/unpack *********/
475 class disk
: public er
{
477 FILE *F
;//Disk file to read from/write to
478 disk(unsigned int type
,FILE *f
):er(type
),F(f
) {}
479 disk(const disk
&p
); //You don't want to copy
480 void operator=(const disk
&p
); // You don't want to copy
482 //For seeking (pack/unpack in different orders)
483 virtual void impl_startSeek(seekBlock
&s
); /*Begin a seeking block*/
484 virtual size_t impl_tell(seekBlock
&s
); /*Give the current offset*/
485 virtual void impl_seek(seekBlock
&s
,size_t off
); /*Seek to the given offset*/
488 //For packing to a disk file
489 class toDisk
: public disk
{
491 //Generic bottleneck: pack n items of size itemSize from p.
492 virtual void bytes(void *p
,size_t n
,size_t itemSize
,dataType t
);
495 // Write data to the given file pointer
496 // (must be opened for binary write)
497 // You must close the file yourself when done.
498 toDisk(FILE *f
):disk(IS_PACKING
,f
) {error
= false;}
499 bool checkError(){return error
;}
502 //For unpacking from a disk file
503 class fromDisk
: public disk
{
505 //Generic bottleneck: unpack n items of size itemSize from p.
506 virtual void bytes(void *p
,size_t n
,size_t itemSize
,dataType t
);
508 // Read data from the given file pointer
509 // (must be opened for binary read)
510 // You must close the file yourself when done.
511 fromDisk(FILE *f
):disk(IS_UNPACKING
,f
) {}
514 /************** PUP::er -- Text *****************/
515 class toTextUtil
: public er
{
517 char *cur
; /*Current output buffer*/
518 int level
; /*Indentation distance*/
519 void beginEnv(const char *type
,int n
=0);
520 void endEnv(const char *type
);
521 char *beginLine(void);
524 virtual char *advance(char *cur
)=0; /*Consume current buffer and return next*/
525 toTextUtil(unsigned int inType
,char *buf
);
526 toTextUtil(const toTextUtil
&p
); //You don't want to copy
527 void operator=(const toTextUtil
&p
); // You don't want to copy
529 virtual void comment(const char *message
);
530 virtual void synchronize(unsigned int m
);
532 virtual void bytes(void *p
,size_t n
,size_t itemSize
,dataType t
);
533 virtual void object(able
** a
);
535 /* Return the number of characters, including terminating NULL */
536 class sizerText
: public toTextUtil
{
539 size_t charCount
; /*Total characters seen so far (not including NULL) */
541 virtual char *advance(char *cur
);
544 size_t size(void) const {return charCount
+1; /*add NULL*/ }
547 /* Copy data to this C string, including terminating NULL. */
548 class toText
: public toTextUtil
{
551 size_t charCount
; /*Total characters written so far (not including NULL) */
553 virtual char *advance(char *cur
);
555 toText(char *outStr
);
556 toText(const toText
&p
); //You don't want to copy
557 void operator=(const toText
&p
); // You don't want to copy
558 size_t size(void) const {return charCount
+1; /*add NULL*/ }
561 class toTextFile
: public er
{
564 virtual void bytes(void *p
,size_t n
,size_t itemSize
,dataType t
);
566 //Begin writing to this file, which should be opened for ascii write.
567 // You must close the file yourself when done.
568 toTextFile(FILE *f_
) :er(IS_PACKING
), f(f_
) {}
569 toTextFile(const toTextFile
&p
); //You don't want to copy
570 void operator=(const toTextFile
&p
); // You don't want to copy
571 virtual void comment(const char *message
);
573 class fromTextFile
: public er
{
576 int readInt(const char *fmt
="%d");
577 unsigned int readUint(const char *fmt
="%u");
578 CMK_TYPEDEF_INT8
readLongInt(const char *fmt
="%lld");
579 double readDouble(void);
581 virtual void bytes(void *p
,size_t n
,size_t itemSize
,dataType t
);
582 virtual void parseError(const char *what
);
584 //Begin writing to this file, which should be opened for ascii read.
585 // You must close the file yourself when done.
586 fromTextFile(FILE *f_
) :er(IS_UNPACKING
), f(f_
) {}
587 fromTextFile(const fromTextFile
&p
); //You don't want to copy
588 void operator=(const fromTextFile
&p
); // You don't want to copy
589 virtual void comment(const char *message
);
592 /********** PUP::er -- Heterogenous machine pack/unpack *********/
593 //This object describes the data representation of a machine.
596 typedef unsigned char myByte
;
597 myByte magic
[4];//Magic number (to identify machineInfo structs)
598 myByte version
;//0-- current version
600 myByte intBytes
[5]; //<- sizeof(char,short,int,long,int128)
601 myByte intFormat
;//0-- big endian. 1-- little endian.
603 myByte floatBytes
; //<- sizeof(...)
605 myByte floatFormat
;//0-- big endian IEEE. 1-- little endian IEEE.
610 // myByte padding[1];//Padding to 16 bytes
612 //Return true if our magic number is valid.
613 bool valid(void) const;
614 //Return true if we differ from the current (running) machine.
615 bool needsConversion(void) const;
617 //Get a machineInfo for the current machine
618 static const machineInfo
¤t(void);
625 if (version
== 0) p(intBytes
, 4);
628 p(floatBytes
); p(doubleBytes
); p(floatFormat
);
629 p(boolBytes
); p(pointerBytes
);
630 if (version
== 0) p(padding
);
634 /// "Wrapped" PUP::er: forwards requests to another PUP::er.
635 class wrap_er
: public er
{
639 wrap_er(er
&p_
,unsigned int newFlags
=0) :er(p_
.getStateFlags()|newFlags
), p(p_
) {}
640 virtual size_t size(void) const { return p
.size(); }
642 virtual void impl_startSeek(seekBlock
&s
); /*Begin a seeking block*/
643 virtual size_t impl_tell(seekBlock
&s
); /*Give the current offset*/
644 virtual void impl_seek(seekBlock
&s
,size_t off
); /*Seek to the given offset*/
645 virtual void impl_endSeek(seekBlock
&s
);/*End a seeking block*/
648 //For translating some odd disk/memory representation into the
649 // current machine representation. (We really only need to
650 // translate during unpack-- "reader makes right".)
651 class xlater
: public wrap_er
{
653 typedef void (*dataConverterFn
)(int N
,const myByte
*in
,myByte
*out
,size_t nElem
);
655 //This table is indexed by dataType, and contains an appropriate
656 // conversion function to unpack a n-item array of the corresponding
657 // data type (possibly in-place).
658 dataConverterFn convertFn
[dataType_last
];
659 //Maps dataType to source machine's dataSize
660 size_t convertSize
[dataType_last
];
661 void setConverterInt(const machineInfo
&m
,const machineInfo
&cur
,
662 int isUnsigned
,int intType
,dataType dest
);
664 //Generic bottleneck: unpack n items of size itemSize from p.
665 virtual void bytes(void *p
,size_t n
,size_t itemSize
,dataType t
);
667 xlater(const machineInfo
&fromMachine
, er
&fromData
);
670 /*************** PUP::able support ***************/
671 //The base class of system-allocatable objects with pup routines
674 //A globally-unique, persistent identifier for an allocatable object
678 unsigned char hash
[len
];
680 PUP_ID(int val
) {for (int i
=0;i
<len
;i
++) hash
[i
]=val
;}
681 PUP_ID(const char *name
) {setName(name
);}
682 void setName(const char *name
);//Write name into hash
683 bool operator==(const PUP_ID
&other
) const {
684 for (int i
=0;i
<len
;i
++)
685 if (hash
[i
]!=other
.hash
[i
])
690 p((char *)hash
,sizeof(unsigned char)*len
);
692 void pup(er
&p
) const {
693 p((char *)hash
,sizeof(unsigned char)*len
);
699 able(CkMigrateMessage
*) {}
700 virtual ~able();//Virtual destructor may be needed by some child
703 //Constructor function registration:
704 typedef able
* (*constructor_function
)(void);
705 static PUP_ID
register_constructor(const char *className
,
706 constructor_function fn
);
707 static constructor_function
get_constructor(const PUP_ID
&id
);
708 virtual /*PUP::*/able
*clone(void) const;
711 virtual void pup(er
&p
);
712 virtual const PUP_ID
&get_PUP_ID(void) const=0;
715 #define SINGLE_ARG(...) __VA_ARGS__
717 //Declarations which create routines implemeting the | operator.
718 // Macros to be used inside a class body.
719 #define PUPable_operator_inside(className)\
720 friend inline void operator|(PUP::er &p,className &a) {a.pup(p);}\
721 friend inline void operator|(PUP::er &p,className* &a) {\
722 PUP::able *pa=a; p(&pa); a=(className *)pa;\
725 // Macros to be used outside a class body.
726 #define PUPable_operator_outside(className)\
727 inline void operator|(PUP::er &p,className &a) {a.pup(p);}\
728 inline void operator|(PUP::er &p,className* &a) {\
729 PUP::able *pa=a; p(&pa); a=(className *)pa;\
732 //Declarations to include in a PUP::able's body.
733 // Convenient, but only usable if class is not inside a namespace.
734 #define PUPable_decl(className) \
735 PUPable_decl_inside(className) \
736 PUPable_operator_inside(className)
738 #define PUPable_decl_template(className) \
739 PUPable_decl_inside_template(SINGLE_ARG(className)) \
740 PUPable_operator_inside(SINGLE_ARG(className))
742 //PUPable_decl for classes inside a namespace: inside body
743 #define PUPable_decl_inside(className) \
745 static PUP::able *call_PUP_constructor(void); \
746 static PUP::able::PUP_ID my_PUP_ID;\
748 virtual const PUP::able::PUP_ID &get_PUP_ID(void) const; \
749 static void register_PUP_ID(const char* name);
751 #define PUPable_decl_base_template(baseClassName, className) \
752 PUPable_decl_inside_base_template(SINGLE_ARG(baseClassName), \
753 SINGLE_ARG(className)) \
754 PUPable_operator_inside(SINGLE_ARG(className))
756 #define PUPable_decl_inside_template(className) \
758 static PUP::able* call_PUP_constructor(void) { \
759 return new className((CkMigrateMessage *)0);} \
760 static PUP::able::PUP_ID my_PUP_ID;\
762 virtual const PUP::able::PUP_ID &get_PUP_ID(void) const { \
763 return my_PUP_ID; } \
764 static void register_PUP_ID(const char* name) { \
765 my_PUP_ID=register_constructor(name,call_PUP_constructor);}
767 #define PUPable_decl_inside_base_template(baseClassName, className) \
769 static PUP::able *call_PUP_constructor(void) { \
770 return new className((CkMigrateMessage *)0); \
772 static PUP::able::PUP_ID my_PUP_ID; \
775 virtual const PUP::able::PUP_ID &get_PUP_ID(void) const { \
778 static void register_PUP_ID(const char *name) { \
780 baseClassName::register_constructor(name, call_PUP_constructor); \
783 //PUPable_decl for classes inside a namespace: in header at file scope
784 #define PUPable_decl_outside(className) \
785 PUPable_operator_outside(className)
787 //PUPable_decl for classes inside a namespace: in header at file scope
788 #define PUPable_decl_outside_template(templateParameters,className) \
789 template<templateParameters> inline void operator|(PUP::er &p,className &a) {a.pup(p);} \
790 template<templateParameters> inline void operator|(PUP::er &p,className* &a) { \
791 PUP::able *pa=a; p(&pa); a=(className *)pa; } \
792 template<templateParameters> PUP::able *className::call_PUP_constructor(void) { \
793 return new className((CkMigrateMessage *)0);} \
794 template<templateParameters> const PUP::able::PUP_ID &className::get_PUP_ID(void) const { \
795 return className::my_PUP_ID; } \
796 template<templateParameters> void className::register_PUP_ID(const char* name) { \
797 my_PUP_ID=register_constructor(name,className::call_PUP_constructor);}
800 //Declarations to include in an abstract PUP::able's body.
801 // Abstract PUP::ables do not need def or reg.
802 #define PUPable_abstract(className) \
804 virtual const PUP::able::PUP_ID &get_PUP_ID(void) const =0; \
805 PUPable_operator_inside(className)
807 //Definitions to include exactly once at file scope
808 #define PUPable_def(className) \
809 PUP::able *className::call_PUP_constructor(void) \
810 { return new className((CkMigrateMessage *)0);}\
811 const PUP::able::PUP_ID &className::get_PUP_ID(void) const\
812 { return className::my_PUP_ID; }\
813 PUP::able::PUP_ID className::my_PUP_ID;\
814 void className::register_PUP_ID(const char* name)\
815 {my_PUP_ID=register_constructor(name,\
816 className::call_PUP_constructor);}
818 //Definitions to include exactly once at file scope
819 #define PUPable_def_template(className) \
820 template<> PUP::able::PUP_ID className::my_PUP_ID = 0;
822 //Definitions to include exactly once at file scope
823 #define PUPable_def_template_nonInst(className) \
824 PUP::able::PUP_ID className::my_PUP_ID = 0;
826 //Code to execute exactly once at program start time
827 #define PUPable_reg(className) \
828 className::register_PUP_ID(#className);
829 #define PUPable_reg2(classIdentifier,className) \
830 classIdentifier::register_PUP_ID(className);
832 inline void operator|(er
&p
,able
&a
) {a
.pup(p
);}
833 inline void operator|(er
&p
,able
* &a
) {p(&a
);}
834 } //<- End namespace PUP
837 //Holds a pointer to a (possibly dynamically allocated) PUP::able.
838 // Extracting the pointer hands the deletion responsibility over.
839 // This is used by parameter marshalling, which doesn't work well
840 // with bare pointers.
841 // CkPointer<T> t is the parameter-marshalling equivalent of T *t
844 T
*allocated
; //Pointer that PUP dynamically allocated for us (recv only)
845 T
*ptr
; //Read-only pointer
847 CkPointer(const CkPointer
<T
> &) = delete;
848 void operator=(const CkPointer
<T
> &) = delete;
849 void operator=(CkPointer
<T
> &&) = delete;
851 T
*peek(void) {return ptr
;}
853 /// Used on the send side, and does *not* delete the object.
854 CkPointer(T
*src
) ///< Marshall this object.
856 allocated
=0; //Don't ever delete src
859 CkPointer(CkPointer
<T
> &&src
)
861 allocated
= src
.allocated
;
864 src
.allocated
= nullptr;
868 /// Begin completely empty: used on marshalling recv side.
873 ~CkPointer() { if (allocated
) delete allocated
; }
875 /// Extract the object held by this class.
876 /// Deleting the pointer is now the user's responsibility
877 inline operator T
* () { allocated
=0; return ptr
; }
879 inline void pup(PUP::er
&p
) {
880 bool ptrWasNull
=(ptr
==0);
882 PUP::able
*ptr_able
=ptr
; // T must inherit from PUP::able!
883 p
|ptr_able
; //Pack as a PUP::able *
887 { //PUP just allocated a new object for us--
888 // make sure it gets deleted eventually.
892 friend inline void operator|(PUP::er
&p
,CkPointer
<T
> &v
) {v
.pup(p
);}
894 #define PUPable_marshall CkPointer
896 //Like CkPointer, but keeps deletion responsibility forever.
897 // CkReference<T> t is the parameter-marshalling equivalent of T &t
899 class CkReference
: private CkPointer
<T
> {
901 /// Used on the send side, and does *not* delete the object.
902 CkReference(T
&src
) ///< Marshall this object.
903 :CkPointer
<T
>(&src
) { }
905 /// Begin completely empty: used on the recv side.
908 /// Look at the object held by this class. Does *not* hand over
909 /// deletion responsiblity.
910 inline operator T
& () { return *this->peek(); }
912 inline void pup(PUP::er
&p
) {CkPointer
<T
>::pup(p
);}
914 friend inline void operator|(PUP::er
&p
,CkReference
<T
> &v
) {v
.pup(p
);}
917 // For people that forget the "::"
918 typedef PUP::er PUPer
;
919 typedef PUP::able PUPable
;
921 /******** PUP via pipe: another way to access PUP::ers *****
922 The parameter marshalling system pups each variable v using just:
924 Thus we need a "void operator|(PUP::er &p,T &v)" for all types
925 that work with parameter marshalling.
930 Traits class: decide if the type T can be safely
931 pupped as raw bytes. This is true of classes that
932 do not contain pointers and do not need pup routines.
934 if (PUP::as_bytes<someClass>::value) { ... }
936 template<class T
> class as_bytes
{
937 #ifdef CK_DEFAULT_BITWISE_PUP /* OLD */
938 public: enum {value
=1};
939 #else /* normal case: don't pack as bytes by default */
940 public: enum {value
=0};
945 #ifdef CK_DEFAULT_BITWISE_PUP /* OLD compatability mode*/
946 /// Default operator| and PUParray: copy as bytes.
948 inline void operator|(PUP::er
&p
,T
&t
) {p((void *)&t
,sizeof(T
));}
950 inline void PUParray(PUP::er
&p
,T
*ta
,size_t n
) { p((void *)ta
,n
*sizeof(T
)); }
952 /* enable normal pup mode from CK_DEFAULT_BITWISE_PUP */
953 # define PUPmarshall(type) \
954 template<class T> inline void operator|(PUP::er &p,T &t) { t.pup(p); } \
955 template<class T> inline void PUParray(PUP::er &p,T *t,size_t n) { \
956 for (size_t i=0;i<n;i++) p|t[i]; \
959 #else /* !CK_DEFAULT_BITWISE_PUP */
961 // Defines is_pupable to allow enums to be pupped in pup_stl.h
964 template <typename
... Ts
>
968 template <typename
... Ts
>
969 using void_t
= typename make_void
<Ts
...>::type
;
971 template <typename T
, typename U
= void>
972 struct is_pupable
: std::false_type
{};
974 template <typename T
>
976 T
, void_t
<decltype(std::declval
<T
>().pup(std::declval
<PUP::er
&>()))>>
982 Default operator|: call pup routine (as long as T has a pup function).
984 template <class T
, typename
std::enable_if
<details::is_pupable
<T
>::value
, int>::type
= 0>
985 inline void operator|(PUP::er
&p
, T
&t
) {
986 p
.syncComment(PUP::sync_begin_object
);
988 p
.syncComment(PUP::sync_end_object
);
992 Default PUParray: pup each element.
995 inline void PUParray(PUP::er
&p
,T
*t
,size_t n
) {
996 p
.syncComment(PUP::sync_begin_array
);
997 for (size_t i
=0;i
<n
;i
++) {
998 p
.syncComment(PUP::sync_item
);
1001 p
.syncComment(PUP::sync_end_array
);
1004 /* PUPmarshall macro: now a deprecated no-op */
1005 # define PUPmarshall(type) /* empty, pup routines now the default */
1007 #define PUPmarshal(type) PUPmarshall(type) /*Support this common misspelling*/
1010 /// Copy this type as raw memory (like memcpy).
1011 #define PUPbytes(type) \
1012 namespace PUP { inline void operator|(PUP::er &p,type &t) {p((char *)&t,sizeof(type));} } \
1013 namespace PUP { inline void PUParray(PUP::er &p,type *ta,size_t n) { p((char *)ta,n*sizeof(type)); } } \
1014 namespace PUP { template<> class as_bytes<type> { \
1015 public: enum {value=1}; \
1017 #define PUPmarshallBytes(type) PUPbytes(type)
1019 /// Make PUP work with this function pointer type, copied as raw bytes.
1020 #define PUPfunctionpointer(fnPtrType) \
1021 inline void operator|(PUP::er &p,fnPtrType &t) {p((char *)&t,sizeof(fnPtrType));}
1023 /// Make PUP work with this enum type, copied as an "int".
1024 #define PUPenum(enumType) \
1025 inline void operator|(PUP::er &p,enumType &e) { int v=e; p|v; e=v; }
1030 For all builtin types, like "int",
1031 operator| and PUParray use p(t) and p(ta,n).
1033 #define PUP_BUILTIN_SUPPORT(type) \
1034 namespace PUP { inline void operator|(er &p,type &t) {p(t);} } \
1035 namespace PUP { inline void PUParray(er &p,type *ta,size_t n) { p(ta,n); } } \
1036 namespace PUP { template<> class as_bytes<type> { \
1037 public: enum {value=1}; \
1039 PUP_BUILTIN_SUPPORT(signed char)
1040 #if CMK_SIGNEDCHAR_DIFF_CHAR
1041 PUP_BUILTIN_SUPPORT(char)
1043 PUP_BUILTIN_SUPPORT(unsigned char)
1044 PUP_BUILTIN_SUPPORT(short)
1045 PUP_BUILTIN_SUPPORT(int)
1046 PUP_BUILTIN_SUPPORT(long)
1047 PUP_BUILTIN_SUPPORT(unsigned short)
1048 PUP_BUILTIN_SUPPORT(unsigned int)
1049 PUP_BUILTIN_SUPPORT(unsigned long)
1050 PUP_BUILTIN_SUPPORT(float)
1051 PUP_BUILTIN_SUPPORT(double)
1052 PUP_BUILTIN_SUPPORT(bool)
1053 #if CMK_LONG_DOUBLE_DEFINED
1054 PUP_BUILTIN_SUPPORT(long double)
1056 #ifdef CMK_PUP_LONG_LONG
1057 PUP_BUILTIN_SUPPORT(CMK_PUP_LONG_LONG
)
1058 PUP_BUILTIN_SUPPORT(unsigned CMK_PUP_LONG_LONG
)
1061 PUP_BUILTIN_SUPPORT(CmiInt16
)
1062 PUP_BUILTIN_SUPPORT(CmiUInt16
)
1066 //This macro is useful in simple pup routines:
1067 // It's just p|x, but it also documents the *name* of the variable.
1068 // You must have a PUP::er named p.
1069 #define PUPn(field) \
1070 do{ if (p.hasComments()) p.comment(#field); p|field; } while(0)
1072 //Like PUPn(x), above, but for arrays.
1073 #define PUPv(field,len) \
1074 do{ if (p.hasComments()) p.comment(#field); PUParray(p,field,len); } while(0)
1077 #endif //def __CK_PUP_H