OPAL (Object Oriented Parallel Accelerator Library) 2022.1
OPAL
Message.h
Go to the documentation of this file.
1// -*- C++ -*-
2/***************************************************************************
3 *
4 * The IPPL Framework
5 *
6 ***************************************************************************/
7
8#ifndef MESSAGE_H
9#define MESSAGE_H
10
11/***************************************************************************
12 * Message - contains a list of items that comprise a set of data to be
13 * sent, or received from, another node in a parallel architecture. A person
14 * creates a Message object, loads it with data to be sent, and gives it
15 * to a Communicate object.
16 *
17 * The message consists of N 'MsgItem' objects, which each contain some
18 * data; data is added sequentially to a new message using the 'put'
19 * routine, and extracted using the 'get' routine. The messages are
20 * retrieved in a FIFO fashion - you put in messages, and get them out
21 * in the order in which they were put in. You can access MsgItem's via
22 * random access with the [] operator, but it is important
23 * to actually remove the data using 'get' as this will properly deal with
24 * copying data and freeing up memory (if necessary).
25 *
26 * Note on usage: A Message is primarily intended to be created once,
27 * given to a Communicate instance to transmit to another node, and then
28 * to be unpacked or otherwise read by the receiver. A received message
29 * may be forwarded to another node, but it cannot be combined with another
30 * or used to initialize a copy of the Message. This is due to the problems
31 * of resolving who needs to free up the storage used for the Message elements.
32 ***************************************************************************/
33
34#include <complex>
35#include <cstddef>
36#include <vector>
37#include <iostream>
38#include <cstring>
39#include <cstdlib>
40
41// forward declarations
42class Communicate;
43class Message;
44std::ostream& operator<<(std::ostream& o, const Message& m);
45
46// Macros
48// simple template traits class to tell if a type is a built-in type
49// or not. The classes have an enum which is 1 if the type is build-in,
50// 0 otherwise. The default case is 0, but specialized to 1 for other types.
51template <class T>
53{
54 enum { builtin = 0 };
55 enum { pointer = 0 };
56};
57
58#define DEFINE_BUILTIN_TRAIT_CLASS(T) \
59template <> \
60struct MessageTypeIntrinsic<T> { \
61 enum { builtin = 1 }; \
62 enum { pointer = 0 }; \
63}; \
64template <> \
65struct MessageTypeIntrinsic<T *> { \
66 enum { builtin = 1 }; \
67 enum { pointer = 1 }; \
68}; \
69template <int N> \
70struct MessageTypeIntrinsic<T[N]> { \
71 enum { builtin = 1 }; \
72 enum { pointer = 1 }; \
73};
74
75#define DEFINE_ALL_BUILTIN_TRAIT_CLASS(T) \
76DEFINE_BUILTIN_TRAIT_CLASS(T) \
77DEFINE_BUILTIN_TRAIT_CLASS(const T)
78
92
94// a class to put single items into a Message, which can be specialized
95// to the case of built-in types and other types.
96
97template <class T, bool builtin, bool pointer>
98struct PutSingleItem { };
99
100// specialization to a non-built-in type, which is never assumed to be a ptr
101template <class T>
102struct PutSingleItem<T, false, false>
103{
104 // put a value into a message
105 static Message& put(Message&, const T&);
106 // get a value out of a message
107 static Message& get(Message&, T&);
108 // version of put using a pair of iterators
109 static Message& put(Message&, T, T);
110 // version of put using a list of indices and an iterator
111 static Message& put(Message&, const std::vector<size_t>&, T);
112 // get_iter uses an output iterator
113 static Message& get_iter(Message&, T);
114};
115
116// specialization to a built-in type that is not a pointer
117template <class T>
118struct PutSingleItem<T, true, false>
119{
120 // put a value into a message
121 static Message& put(Message&, const T&);
122 // get a value out of a message
123 static Message& get(Message&, T&);
124};
125
126// specialization to a pointer to a built-in type. In this class, we
127// know that 'T' is a pointer type.
128template <class T>
129struct PutSingleItem<T, true, true>
130{
131 // put using a pair of pointers
132 static Message& put(Message&, T, T);
133 // get using a pointer
134 static Message& get(Message&, T);
135 // put using a list of indices and a pointer
136 static Message& put(Message&, const std::vector<size_t>&, T);
137 // get using an output iterator
138 static Message& get_iter(Message&, T);
139};
140
141
143{
144
145public:
146 // a class which stores a single message element. This will either store
147 // a reference to the data (if copy=false), make an internal copy (if
148 // copy=true, and it is large enough), or put the data into an internal
149 // fast buffer (the MsgItemBuf struct).
151 {
152 private:
153 // a very simple struct for storing MsgItem data
155 {
156 unsigned long long d1, d2, d3, d4;
157
159 MsgItemBuf(const MsgItemBuf& m) : d1(m.d1),d2(m.d2),d3(m.d3),d4(m.d4) {}
161 };
162
163 public:
164
165 // default constructor
166 MsgItem() : item(0), elements(0), bytesize(0), needDelete(false) { }
167
168 // regular constructor, with data to store
169 MsgItem(void *d, unsigned int elems, unsigned int totbytes,
170 bool needcopy, bool needdel) : item(&defbuf), elements(elems),
171 bytesize(totbytes), needDelete(needdel)
172 {
173 if (totbytes > 0 && d != 0)
174 {
175 if (needcopy)
176 {
177 if (totbytes <= sizeof(MsgItemBuf))
178 {
179 // copy data into internal buffer
180 needDelete = false;
181 }
182 else
183 {
184 // malloc and copy over data
185 item = malloc(totbytes);
186 needDelete = true;
187 }
188 memcpy(item, d, totbytes);
189 }
190 else
191 {
192 // we just store a reference, we do not copy
193 item = d;
194 }
195 }
196 else
197 {
198 // no data in message
199 item = 0;
200 elements = 0;
201 needDelete = false;
202 }
203 }
204
205 // copy constructor
208 {
209 // either we just copy the 'item' pointer, or we copy the default buf
210 if (m.item != &(m.defbuf))
211 item = m.item;
212 }
213
214 // destructor
216
217 // return our total byte size, number of elements, and elem size
218 unsigned int numBytes() const
219 {
220 return bytesize;
221 }
222 unsigned int numElems() const
223 {
224 return elements;
225 }
226 unsigned int elemSize() const
227 {
228 return (elements>0?bytesize/elements:0);
229 }
230
231 // will we need to delete our data?
232 bool willNeedDelete() const
233 {
234 return (needDelete && item != 0);
235 }
236
237 // cancel the need to delete the data
239 {
240 needDelete = false;
241 }
242
243 // return our item pointer
244 void *data()
245 {
246 return item;
247 }
248
249 // delete our data item
251 {
252 if (willNeedDelete())
253 free(item);
254 }
255
256 private:
257 // pointer to the item; must be newed/deleted, or pointing to defbuf
258 void *item;
259
260 // number of individual elements, and total storage size in bytes
261 unsigned int elements, bytesize;
262
263 // default storage space; used for speed
265
266 // do we need to delete this item storage?
268 };
269
270public:
271 //
272 // constructors and destructors
273 //
274
275 // 'default' constructor: just make an empty message, optionally requesting
276 // how many items we should preallocate space for
277 Message(unsigned int numelems = 8)
278 : numRemoved(0), DoCopy(true), DoDelete(true), comm(0), commdata(0)
279 {
280 MsgItemList.reserve(numelems);
281 }
282
283 // destructor: delete all items in this message, as if 'get' had been
284 // called for all the items
285 ~Message();
286
287 //
288 // global Message operations
289 //
290
291 // return number of items left in this message
292 size_t size() const
293 {
294 return (MsgItemList.size() - numRemoved);
295 }
296 size_t removed() const
297 {
298 return numRemoved;
299 }
300 bool empty() const
301 {
302 return (size() == 0);
303 }
304
305 // returns a reference to the Nth MsgItem. Note that 'n' refers
306 // to the index from te first unremoved item, and that 'get' and 'remove'
307 // will remove the top item.
308 MsgItem& item(size_t n)
309 {
310 return MsgItemList[n + numRemoved];
311 }
312 const MsgItem& item(size_t n) const
313 {
314 return MsgItemList[n+numRemoved];
315 }
316
317 // indicate that the next message item should be copied (t) or just
318 // remembered via a pointer (f)
319 Message& setCopy(const bool c)
320 {
321 DoCopy = c;
322 return *this;
323 }
324 bool willCopy() const
325 {
326 return DoCopy;
327 }
328
329 // indicate that the next message item memory should be deleted by this
330 // object when the Message is deleted (t)
331 Message& setDelete(const bool c)
332 {
333 DoDelete = c;
334 return *this;
335 }
336 bool willDelete() const
337 {
338 return DoDelete;
339 }
340
341 // clear the message; deletes all its items
342 Message& clear();
343
344 // return and remove the next item from this message ... if the item
345 // does not exist, NULL is returned. This is similar to get, except that
346 // just a void* pointer to the data is returned (instead of having the
347 // data copied into given storage), and this data is DEFINITELY a malloced
348 // block of data that the user must deallocate using 'free' (NOT delete).
349 // Like 'get', after this is called, the top MsgItem is removed.
350 // If you wish to just access the Nth item's item pointer, use
351 // item(N).item .
352 void *remove();
353
354 // tell this Message to call the special function 'cleanupMessage' with
355 // the provided pointer, in case the message is using buffer space
356 // allocated by the Communicate object. If no Communicate object has
357 // been provided, nothing is done
359 {
360 comm = c;
361 commdata = d;
362 }
363
364 //
365 // routines to get and put data out of/into the message.
366 //
367
368 // NOTES for 'put' routines:
369 // For intrinsic scalar values, there is one argument: the scalar item.
370 // For arrays, there are two arguments: the begining and (one-past-end)
371 // pointers (i.e. like iterators, but restricted to pointers).
372 // For any other arbitrary type, calling put will in turn call the method
373 // 'putMessage' in the provided object. 'putMessage' can then call put
374 // to put in the proper intrinsic-type objects.
375 //
376 // When putting in data, you can have the data copied over, or just have
377 // a pointer stored. If a pointer is stored (copy=F), you must also
378 // specify whether this Message object should be responsible for deleting
379 // the data (delstor=T), or should just leave the storage alone after the
380 // data has been retrieved with get. These flags are set by calling
381 // 'setCopy' and 'setDelete' with the desired setting. After an item
382 // has been 'put', the are set back to the default values 'copy=true' and
383 // 'delete=true'. You can use them in this way:
384 // Message msg;
385 // msg.setCopy(false).setDelete(false).put(data);
386 // copy and delstor are used to increase performance. They
387 // should be used in the following circumstances:
388 // a. Data to be sent/rec is in a location that will not change before the
389 // msg is used, but should not be affected after the Message is deleted.
390 // For this case, use copy=F, delstor=F.
391 // b. Data for a message has already had space allocated for it, and so
392 // does not need to be copied. Also, since the space has been allocated
393 // already, it must be freed when the msg is sent. For this case, use
394 // copy=F, delstor=T.
395 // c. For data that is in a volatile location, it must be copied to new
396 // storage, so use copy=T, and don't specify any value for delstor (it will
397 // be ignored if copy=T).
398
399 // general templated version of put
400 // for an arbitrary type, call the function 'putMessage' with this
401 // message so that it can put in data any way it wants. That function
402 // should return a reference to this message.
403 // 'putMessage' should be defined as:
404 // Message& putMessage(Message &);
405 template <class T>
406 Message& put(const T& val)
407 {
408 return PutSingleItem<T,
411 }
412
413 // specialized versions of put for character strings
414 /*
415 Message &put(char *d) { // null-terminated string
416 return putmsg((void *)d, sizeof(char), strlen(d) + 1);
417 }
418 */
419 Message &put(const char *d) // null-terminated string
420 {
421 return putmsg((void *)d, sizeof(char), strlen(d) + 1);
422 }
423 // specialized version for string class
424 Message& put(const std::string& s)
425 {
426 int len = s.length() + 1;
427 put(len);
428 put(s.c_str());
429 return *this;
430 }
431
432 // general templated version of put for two iterators
433 // Template put using a pair of iterators. This version is called by
434 // the public 'put' with two iterators after getting the proper type
435 // of the data pointed to by the iterators
436 template <class ForwardIterator>
437 Message& put(ForwardIterator beg, ForwardIterator end)
438 {
439 return PutSingleItem<ForwardIterator,
442 *this, beg, end);
443 }
444
445 // for using an indirection list
446 // Template put using an indirection list. This version is called by
447 // the public 'put' with an indirection list and a RandomAccessIterator
448 // after getting the proper type of the data pointed to by the iterator
449 template <class RandomAccessIterator>
450 Message& put(const std::vector<size_t>& indices,
451 RandomAccessIterator beg)
452 {
453 return PutSingleItem<RandomAccessIterator,
456 indices, beg);
457 }
458
459 // general put routine; called by other cases
460 // arguments are the item, its element size (in bytes),
461 // and how many items total to copy (if 0, this is a scalar).
462 Message &putmsg(void *, int, int = 0);
463
464
465 // general templated version of get, for a ref or a pointer
466 // for an arbitrary type, call the function 'getMessage' with this
467 // message so that it can get data any way it wants. That function
468 // should return a reference to this message.
469 // 'getMessage' should be defined as:
470 // Message& getMessage(Message &);
471 // NOTE: the argument is a const ref, but will be cast to non-const,
472 // to eliminate warning messages about anachronisms.
474 // general templated version of get.
475 template <class T>
476 Message& get(const T& cval)
477 {
478 T& val = const_cast<T&>(cval);
479 return PutSingleItem<T,
482 }
483
484 // specialized version for string class
485 Message& get(const std::string& s)
486 {
487 std::string& ncs = const_cast<std::string&>(s);
488 int len = 0;
489 get(len);
490 char* cstring = new char[len];
491 get(cstring);
492 ncs = cstring;
493 delete [] cstring;
494 return *this;
495 }
496
497 // this version of get just removes the data without copying it
499 {
500 return getmsg(0);
501 }
502
503 // an iterator-based version of get, which uses a general
504 // iterator approach to copy the data out of the storage into
505 // the space pointed to by the given iterator
507 // Template get using a pair of iterators. This version is called by
508 // the public 'get' with two iterators after getting the proper type
509 // of the data pointed to by the iterators
510 template <class OutputIterator>
511 Message& get_iter(OutputIterator o)
512 {
513 return PutSingleItem<OutputIterator,
516 }
517
518 // general get routine; called by other cases
519 // arguments are the location where to write the data, and the type
520 // of the data.
521 Message &getmsg(void *);
522
523private:
524 // MsgItem's that are in this message
525 std::vector<MsgItem> MsgItemList;
526
527 // number of elements that have been removed (via get or remove)
529
530 // should we copy the next added item? if not, just store pointer
531 bool DoCopy;
532
533 // should we be responsible for deleting the next item?
535
536 // a Communicate object which should be informed when this object is
537 // deleted, and a comm-supplied object that it might need
539 void *commdata;
540
541 // delete the data in the top MsgItem, and remove that item from the top
542 // (by incrementing numRemoved)
543 void deleteMsgItem();
544};
545
546
547// General template for the put routine:
548template<class T>
549inline void putMessage(Message &m, const T &t)
550{
551 m.put(t);
552}
553
554// for using a pair of iterators
555template<class ForwardIterator>
556inline void putMessage(Message &m, ForwardIterator beg, ForwardIterator end)
557{
558 m.put(beg, end);
559}
560
561// for using an indirection list
562template <class RandomAccessIterator>
563inline void putMessage(Message &m, const std::vector<size_t> &v,
564 RandomAccessIterator r)
565{
566 m.put(v, r);
567}
568
569
570// General template for the get routine:
571template<class T>
572inline void getMessage(Message &m, T &t)
573{
574 m.get(t);
575}
576
577// this templated version of getMessage is for arbitrary pointers
578template<class T>
579inline void getMessage(Message &m, T *t)
580{
581 m.get_iter(t);
582}
583
584// this templated version of getMessage is for arbitrary pointers
585template<class T>
586inline void getMessage(Message &m, T *t, T *)
587{
588 m.get_iter(t);
589}
590
591// an iterator-based version of get, which uses a general
592// iterator approach to copy the data out of the storage into
593// the space pointed to by the given iterator
594template<class OutputIterator>
595inline void getMessage_iter(Message &m, OutputIterator o)
596{
597 m.get_iter(o);
598}
599
600#include "Message/Message.hpp"
601
602#endif // MESSAGE_H
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
elements
Definition: IndexMap.cpp:163
void putMessage(Message &m, const T &t)
Definition: Message.h:549
#define DEFINE_ALL_BUILTIN_TRAIT_CLASS(T)
Definition: Message.h:75
void getMessage_iter(Message &m, OutputIterator o)
Definition: Message.h:595
void getMessage(Message &m, T &t)
Definition: Message.h:572
std::ostream & operator<<(std::ostream &o, const Message &m)
MMatrix< m_complex > complex(MMatrix< double > real)
Definition: MMatrix.cpp:396
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:45
bool willDelete() const
Definition: Message.h:336
size_t size() const
Definition: Message.h:292
Message & get_iter(OutputIterator o)
Definition: Message.h:511
void deleteMsgItem()
Message & putmsg(void *, int, int=0)
Message & setCopy(const bool c)
Definition: Message.h:319
Message & put(const char *d)
Definition: Message.h:419
size_t numRemoved
Definition: Message.h:528
Message & put(const std::string &s)
Definition: Message.h:424
const MsgItem & item(size_t n) const
Definition: Message.h:312
Message & getmsg(void *)
void * commdata
Definition: Message.h:539
Message & put(const T &val)
Definition: Message.h:406
Message & clear()
Message & put(ForwardIterator beg, ForwardIterator end)
Definition: Message.h:437
Message & get(const std::string &s)
Definition: Message.h:485
Message & get()
Definition: Message.h:498
Message(unsigned int numelems=8)
Definition: Message.h:277
bool DoDelete
Definition: Message.h:534
Message & put(const std::vector< size_t > &indices, RandomAccessIterator beg)
Definition: Message.h:450
std::vector< MsgItem > MsgItemList
Definition: Message.h:525
bool DoCopy
Definition: Message.h:531
void * remove()
size_t removed() const
Definition: Message.h:296
bool empty() const
Definition: Message.h:300
MsgItem & item(size_t n)
Definition: Message.h:308
Message & setDelete(const bool c)
Definition: Message.h:331
void useCommunicate(Communicate *c, void *d)
Definition: Message.h:358
bool willCopy() const
Definition: Message.h:324
Message & get(const T &cval)
Definition: Message.h:476
Communicate * comm
Definition: Message.h:538
unsigned int numBytes() const
Definition: Message.h:218
MsgItemBuf defbuf
Definition: Message.h:264
MsgItem(void *d, unsigned int elems, unsigned int totbytes, bool needcopy, bool needdel)
Definition: Message.h:169
void deleteData()
Definition: Message.h:250
void cancelDelete()
Definition: Message.h:238
unsigned int elemSize() const
Definition: Message.h:226
bool willNeedDelete() const
Definition: Message.h:232
unsigned int bytesize
Definition: Message.h:261
unsigned int numElems() const
Definition: Message.h:222
MsgItem(const MsgItem &m)
Definition: Message.h:206
void * data()
Definition: Message.h:244
unsigned int elements
Definition: Message.h:261
unsigned long long d2
Definition: Message.h:156
unsigned long long d1
Definition: Message.h:156
MsgItemBuf(const MsgItemBuf &m)
Definition: Message.h:159
unsigned long long d4
Definition: Message.h:156
unsigned long long d3
Definition: Message.h:156