dune-common  2.7.1
mpipack.hh
Go to the documentation of this file.
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
18 #ifndef DUNE_COMMON_PARALLEL_MPIPACK_HH
19 #define DUNE_COMMON_PARALLEL_MPIPACK_HH
20 
21 #include <vector>
22 #if HAVE_MPI
23 #include <mpi.h>
26 
27 
28 namespace Dune {
29 
30  class MPIPack {
31  std::vector<char> _buffer;
32  int _position;
33  MPI_Comm _comm;
34 
35  friend struct MPIData<MPIPack>;
36  friend struct MPIData<const MPIPack>;
37  public:
38  MPIPack(Communication<MPI_Comm> comm, std::size_t size = 0)
39  : _buffer(size)
40  , _position(0)
41  , _comm(comm)
42  {}
43 
44  // Its not valid to copy a MPIPack but you can move it
45  MPIPack(const MPIPack&) = delete;
46  MPIPack& operator = (const MPIPack& other) = delete;
47  MPIPack(MPIPack&&) = default;
48  MPIPack& operator = (MPIPack&& other) = default;
49 
55  template<class T>
56  void pack(const T& data){
57  auto mpidata = getMPIData(data);
58  int size = getPackSize(mpidata.size(), _comm, mpidata.type());
59  constexpr bool has_static_size = decltype(getMPIData(std::declval<T&>()))::static_size;
60  if(!has_static_size)
61  size += getPackSize(1, _comm, MPI_INT);
62  if (_position + size > 0 && size_t(_position + size) > _buffer.size()) // resize buffer if necessary
63  _buffer.resize(_position + size);
64  if(!has_static_size){
65  int size = mpidata.size();
66  MPI_Pack(&size, 1, MPI_INT, _buffer.data(), _buffer.size(),
67  &_position, _comm);
68  }
69  MPI_Pack(mpidata.ptr(), mpidata.size(),
70  mpidata.type(), _buffer.data(), _buffer.size(),
71  &_position, _comm);
72  }
73 
78  template<class T>
79  auto /*void*/ unpack(T& data)
80  -> std::enable_if_t<decltype(getMPIData(data))::static_size, void>
81  {
82  auto mpidata = getMPIData(data);
83  MPI_Unpack(_buffer.data(), _buffer.size(), &_position,
84  mpidata.ptr(), mpidata.size(),
85  mpidata.type(), _comm);
86  }
87 
92  template<class T>
93  auto /*void*/ unpack(T& data)
94  -> std::enable_if_t<!decltype(getMPIData(data))::static_size, void>
95  {
96  auto mpidata = getMPIData(data);
97  int size = 0;
98  MPI_Unpack(_buffer.data(), _buffer.size(), &_position,
99  &size, 1,
100  MPI_INT, _comm);
101  mpidata.resize(size);
102  MPI_Unpack(_buffer.data(), _buffer.size(), &_position,
103  mpidata.ptr(), mpidata.size(),
104  mpidata.type(), _comm);
105  }
106 
107 
109  template<typename T>
110  friend MPIPack& operator << (MPIPack& p, const T& t){
111  p.pack(t);
112  return p;
113  }
114 
116  template<typename T>
117  friend MPIPack& operator >> (MPIPack& p, T& t){
118  p.unpack(t);
119  return p;
120  }
121 
123  template<typename T>
124  MPIPack& read(T& t){
125  unpack(t);
126  return *this;
127  }
128 
130  template<typename T>
131  MPIPack& write(const T& t){
132  pack(t);
133  return *this;
134  }
135 
139  void resize(size_t size){
140  _buffer.resize(size);
141  }
142 
145  void enlarge(int s) {
146  _buffer.resize(_buffer.size() + s);
147  }
148 
151  size_t size() const {
152  return _buffer.size();
153  }
154 
158  void seek(int p){
159  _position = p;
160  }
161 
165  int tell() const{
166  return _position;
167  }
168 
171  bool eof() const{
172  return std::size_t(_position)==_buffer.size();
173  }
174 
178  static int getPackSize(int len, const MPI_Comm& comm, const MPI_Datatype& dt){
179  int size;
180  MPI_Pack_size(len, dt, comm, &size);
181  return size;
182  }
183 
184  friend bool operator==(const MPIPack& a, const MPIPack& b) {
185  return a._buffer == b._buffer && a._comm == b._comm;
186  }
187  friend bool operator!=(const MPIPack& a, const MPIPack& b) {
188  return !(a==b);
189  }
190 
191  };
192 
193  template<class P>
194  struct MPIData<P, std::enable_if_t<std::is_same<std::remove_const_t<P>, MPIPack>::value>> {
195  protected:
196  friend auto getMPIData<P>(P& t);
197  MPIData(P& t) :
198  data_(t)
199  {}
200  public:
201  static constexpr bool static_size = std::is_const<P>::value;
202 
203  void* ptr() {
204  return (void*) data_._buffer.data();
205  }
206 
207  int size() {
208  return data_.size();
209  }
210 
211  MPI_Datatype type() const{
212  return MPI_PACKED;
213  }
214 
215  void resize(int size){
216  data_.resize(size);
217  }
218  protected:
219  P& data_;
220  };
221 
222 } // end namespace Dune
223 
224 #endif
225 #endif
Implements an utility class that provides MPI's collective communication methods.
Interface class to translate objects to a MPI_Datatype, void* and size used for MPI calls.
Dune namespace.
Definition: alignedallocator.hh:14
auto getMPIData(T &t)
Definition: mpidata.hh:41
Specialization of Communication for MPI.
Definition: mpicommunication.hh:106
Definition: mpidata.hh:48
T & data_
Definition: mpidata.hh:51
int size() const
Definition: mpidata.hh:65
static constexpr bool static_size
Definition: mpidata.hh:63
Definition: mpipack.hh:30
MPIPack & operator=(const MPIPack &other)=delete
void enlarge(int s)
Enlarges the internal buffer.
Definition: mpipack.hh:145
MPIPack & write(const T &t)
Packs the data into the object. Enlarges the internal buffer if necessary.
Definition: mpipack.hh:131
friend MPIPack & operator>>(MPIPack &p, T &t)
Unpacks data from the object.
Definition: mpipack.hh:117
friend bool operator!=(const MPIPack &a, const MPIPack &b)
Definition: mpipack.hh:187
size_t size() const
Returns the size of the internal buffer.
Definition: mpipack.hh:151
MPIPack(Communication< MPI_Comm > comm, std::size_t size=0)
Definition: mpipack.hh:38
void pack(const T &data)
Packs the data into the object. Enlarges the internal buffer if necessary.
Definition: mpipack.hh:56
MPIPack & read(T &t)
Unpacks data from the object.
Definition: mpipack.hh:124
auto unpack(T &data) -> std::enable_if_t<!decltype(getMPIData(data))::static_size, void >
Unpacks data from the object.
Definition: mpipack.hh:93
auto unpack(T &data) -> std::enable_if_t< decltype(getMPIData(data))::static_size, void >
Unpacks data from the object.
Definition: mpipack.hh:79
friend bool operator==(const MPIPack &a, const MPIPack &b)
Definition: mpipack.hh:184
MPIPack(const MPIPack &)=delete
void seek(int p)
Sets the position in the buffer where the next pack/unpack operation should take place.
Definition: mpipack.hh:158
bool eof() const
Checks whether the end of the buffer is reached.
Definition: mpipack.hh:171
void resize(size_t size)
Resizes the internal buffer.
Definition: mpipack.hh:139
int tell() const
Gets the position in the buffer where the next pack/unpack operation should take place.
Definition: mpipack.hh:165
friend MPIPack & operator<<(MPIPack &p, const T &t)
Packs the data into the object. Enlarges the internal buffer if necessary.
Definition: mpipack.hh:110
MPIPack(MPIPack &&)=default
static int getPackSize(int len, const MPI_Comm &comm, const MPI_Datatype &dt)
Returns the size of the data needed to store the data in an MPIPack. See MPI_Pack_size.
Definition: mpipack.hh:178