Update references to hapi_src to hapi_impl and revert hapiRegisterCallbacks
[charm.git] / src / util / pup.h
blob99c43388460ab2736f9e9ca583d91cf21b2d0bab
1 /*
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.
18 A simple example is:
19 class foo {
20 private:
21 bool isBar;
22 int x;
23 char y;
24 unsigned long z;
25 CkVec<double> q;
26 public:
27 ...
28 void pup(PUP::er &p) {
29 PUPn(isBar);
30 PUPn(x);PUPn(y);PUPn(z);
31 PUPn(q);
35 A more complex example is:
36 class bar {
37 private:
38 foo f;
39 int nArr;//Length of array below
40 double *arr;//Heap-allocated array
41 public:
42 ...
44 void pup(PUP::er &p) {
45 PUPn(f); // <- automatically calls foo::pup
46 PUPn(nArr);
47 if (p.isUnpacking()) // <- must allocate array on other side.
48 arr=new double[nArr];
49 PUPv(arr,nArr); // <- special syntax for arrays of simple types
54 #ifndef __CK_PUP_H
55 #define __CK_PUP_H
57 #include <stdio.h> /*<- for "FILE *" */
58 #include <type_traits>
59 #include <utility>
61 #ifndef __cplusplus
62 #error "Use pup_c.h for C programs-- pup.h is for C++ programs"
63 #endif
65 #ifdef STANDALONE_PUP
66 #define CmiAbort(x) { printf(x); abort(); }
67 #else
68 #ifndef CHARM_H
69 # include "converse.h" // <- for CMK_* defines
70 #endif
71 extern "C" void CmiAbort(const char *msg);
72 #endif
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;
79 namespace PUP {
80 class er; // Forward declare for all sorts of things
82 /**
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 {};
88 namespace detail {
89 template <typename T, bool b = std::is_constructible<T, reconstruct>::value>
90 struct TemporaryObjectHolder { };
91 template <typename T>
92 struct TemporaryObjectHolder<T, true>
94 typename std::remove_cv<typename std::remove_reference<T>::type>::type t{reconstruct()};
96 template <typename T>
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) {
103 p | 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
111 #endif
114 //Item data types-- these are used to do byte swapping, etc.
115 typedef enum {
116 //(this list must exactly match that in PUPer_xlate)
117 Tchar=0,Tshort, Tint, Tlong, Tlonglong,
118 Tuchar,Tushort,Tuint,Tulong, Tulonglong,
119 #if CMK_HAS_INT16
120 Tint128, Tuint128,
121 #endif
122 Tfloat,Tdouble,Tlongdouble,
123 Tbool,
124 Tbyte,
125 Tsync,
126 Tpointer,
127 dataType_last //<- for setting table lengths, etc.
128 } dataType;
130 //This should be a 1-byte unsigned type
131 typedef unsigned char myByte;
133 //Forward declarations
134 class er;
135 class able;
137 //Used for out-of-order unpacking
138 class seekBlock {
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
143 er &p;
144 bool hasEnded;
145 public:
146 //Constructor
147 seekBlock(er &Np,int nSections);
148 //Destructor
149 ~seekBlock();
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)
154 void endBlock(void);
156 //An evil hack to avoid inheritance and virtual functions among seekers--
157 // stores the PUP::er specific block start information.
158 union {
159 size_t off;
160 long loff;
161 const myByte *cptr;
162 myByte *ptr;
163 void *vptr;
164 } data;
167 //The abstract base class: PUP::er.
168 class er {
169 private:
170 er(const er &p);//You don't want to copy PUP::er's.
171 protected:
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,
180 IS_PACKING =0x0200,
181 IS_UNPACKING=0x0400,
182 TYPE_MASK =0xFF00
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.
187 public:
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);}
215 #endif
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);}
227 #endif
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);}
232 #endif
233 #if CMK_HAS_INT16
234 void operator()(CmiInt16 &v) {(*this)(&v,1);}
235 void operator()(CmiUInt16 &v) {(*this)(&v,1);}
236 #endif
237 void operator()(void* &v,void* sig) {(*this)(&v,1,sig);}
239 //For arrays:
240 //Integral types:
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);}
246 #endif
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);}
273 #endif
275 //For bools:
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);}
284 #endif
285 #if CMK_HAS_INT16
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);}
290 #endif
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)
308 {object(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
323 if (hasComments()) {
324 synchronize(sync);
325 if (message) comment(message);
327 #else
328 /* empty, to avoid expensive virtual function calls */
329 #endif
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) {
348 (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) {
355 (void)msg;
356 (void)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.
371 enum {
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
391 sync_last
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 {
397 protected:
398 size_t nBytes;
399 //Generic bottleneck: n items of size itemSize
400 virtual void bytes(void *p,size_t n,size_t itemSize,dataType t);
401 public:
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;}
409 template <class T>
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
416 protected:
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*/
427 public:
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) {
436 buf += offset;
440 //For packing into a preallocated, presized memory buffer
441 class toMem : public mem {
442 protected:
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);
445 public:
446 //Write data to the given buffer
447 toMem(void *Nbuf):mem(IS_PACKING,(myByte *)Nbuf) {}
449 template <class T>
450 inline void toMemBuf(T &t,void *buf, size_t len) {
451 PUP::toMem p(buf);
452 p|t;
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 {
459 protected:
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);
462 public:
463 //Read data from the given buffer
464 fromMem(const void *Nbuf):mem(IS_UNPACKING,(myByte *)Nbuf) {}
466 template <class T>
467 inline void fromMemBuf(T &t,void *buf,size_t len) {
468 PUP::fromMem p(buf);
469 p|t;
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 {
476 protected:
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 {
490 protected:
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);
493 bool error;
494 public:
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 {
504 protected:
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);
507 public:
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 {
516 private:
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);
522 void endLine(void);
523 protected:
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
528 public:
529 virtual void comment(const char *message);
530 virtual void synchronize(unsigned int m);
531 protected:
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 {
537 private:
538 char line[1000];
539 size_t charCount; /*Total characters seen so far (not including NULL) */
540 protected:
541 virtual char *advance(char *cur);
542 public:
543 sizerText(void);
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 {
549 private:
550 char *buf;
551 size_t charCount; /*Total characters written so far (not including NULL) */
552 protected:
553 virtual char *advance(char *cur);
554 public:
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 {
562 protected:
563 FILE *f;
564 virtual void bytes(void *p,size_t n,size_t itemSize,dataType t);
565 public:
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 {
574 protected:
575 FILE *f;
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);
583 public:
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.
594 class machineInfo {
595 public:
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(...)
604 myByte doubleBytes;
605 myByte floatFormat;//0-- big endian IEEE. 1-- little endian IEEE.
607 myByte boolBytes;
608 myByte pointerBytes;
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 &current(void);
620 void pup(er &p) {
621 myByte padding;
623 p(magic, 4);
624 p(version);
625 if (version == 0) p(intBytes, 4);
626 else p(intBytes, 5);
627 p(intFormat);
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 {
636 protected:
637 er &p;
638 public:
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 {
652 protected:
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);
666 public:
667 xlater(const machineInfo &fromMachine, er &fromData);
670 /*************** PUP::able support ***************/
671 //The base class of system-allocatable objects with pup routines
672 class able {
673 public:
674 //A globally-unique, persistent identifier for an allocatable object
675 class PUP_ID {
676 public:
677 enum {len=8};
678 unsigned char hash[len];
679 PUP_ID() {}
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])
686 return false;
687 return true;
689 void pup(er &p) {
690 p((char *)hash,sizeof(unsigned char)*len);
692 void pup(er &p) const {
693 p((char *)hash,sizeof(unsigned char)*len);
697 protected:
698 able() {}
699 able(CkMigrateMessage *) {}
700 virtual ~able();//Virtual destructor may be needed by some child
702 public:
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;
710 //Target methods:
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) \
744 private: \
745 static PUP::able *call_PUP_constructor(void); \
746 static PUP::able::PUP_ID my_PUP_ID;\
747 public:\
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) \
757 private: \
758 static PUP::able* call_PUP_constructor(void) { \
759 return new className((CkMigrateMessage *)0);} \
760 static PUP::able::PUP_ID my_PUP_ID;\
761 public: \
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) \
768 private: \
769 static PUP::able *call_PUP_constructor(void) { \
770 return new className((CkMigrateMessage *)0); \
772 static PUP::able::PUP_ID my_PUP_ID; \
774 public: \
775 virtual const PUP::able::PUP_ID &get_PUP_ID(void) const { \
776 return my_PUP_ID; \
778 static void register_PUP_ID(const char *name) { \
779 my_PUP_ID = \
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) \
803 public:\
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
842 template <class T>
843 class CkPointer {
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;
850 protected:
851 T *peek(void) {return ptr;}
852 public:
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
857 ptr=src;
859 CkPointer(CkPointer<T> &&src)
861 allocated = src.allocated;
862 ptr = src.ptr;
864 src.allocated = nullptr;
865 src.ptr = nullptr;
868 /// Begin completely empty: used on marshalling recv side.
869 CkPointer(void) {
870 ptr=allocated=0;
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 *
884 ptr=(T *)ptr_able;
886 if (ptrWasNull)
887 { //PUP just allocated a new object for us--
888 // make sure it gets deleted eventually.
889 allocated=ptr;
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
898 template<class T>
899 class CkReference : private CkPointer<T> {
900 public:
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.
906 CkReference(void) {}
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:
923 p|v;
924 Thus we need a "void operator|(PUP::er &p,T &v)" for all types
925 that work with parameter marshalling.
928 namespace PUP {
929 /**
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.
933 Use this like:
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};
941 #endif
945 #ifdef CK_DEFAULT_BITWISE_PUP /* OLD compatability mode*/
946 /// Default operator| and PUParray: copy as bytes.
947 template <class T>
948 inline void operator|(PUP::er &p,T &t) {p((void *)&t,sizeof(T));}
949 template <class 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
962 namespace details {
964 template <typename... Ts>
965 struct make_void {
966 typedef void type;
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>
975 struct is_pupable<
976 T, void_t<decltype(std::declval<T>().pup(std::declval<PUP::er &>()))>>
977 : std::true_type {};
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);
987 t.pup(p);
988 p.syncComment(PUP::sync_end_object);
992 Default PUParray: pup each element.
994 template<class T>
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);
999 p|t[i];
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 */
1006 #endif
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}; \
1016 }; }
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}; \
1038 }; }
1039 PUP_BUILTIN_SUPPORT(signed char)
1040 #if CMK_SIGNEDCHAR_DIFF_CHAR
1041 PUP_BUILTIN_SUPPORT(char)
1042 #endif
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)
1055 #endif
1056 #ifdef CMK_PUP_LONG_LONG
1057 PUP_BUILTIN_SUPPORT(CMK_PUP_LONG_LONG)
1058 PUP_BUILTIN_SUPPORT(unsigned CMK_PUP_LONG_LONG)
1059 #endif
1060 #if CMK_HAS_INT16
1061 PUP_BUILTIN_SUPPORT(CmiInt16)
1062 PUP_BUILTIN_SUPPORT(CmiUInt16)
1063 #endif
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