dune-common  2.9.0
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:
3 // SPDX-FileCopyrightInfo: Copyright (C) DUNE Project contributors, see file LICENSE.md in module root
4 // SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
20 #ifndef DUNE_COMMON_PARALLEL_MPIPACK_HH
21 #define DUNE_COMMON_PARALLEL_MPIPACK_HH
22 
23 #include <vector>
24 #if HAVE_MPI
25 #include <mpi.h>
28 
29 
30 namespace Dune {
31 
32  class MPIPack {
33  std::vector<char> _buffer;
34  int _position;
35  MPI_Comm _comm;
36 
37  friend struct MPIData<MPIPack>;
38  friend struct MPIData<const MPIPack>;
39  public:
40  MPIPack(Communication<MPI_Comm> comm, std::size_t size = 0)
41  : _buffer(size)
42  , _position(0)
43  , _comm(comm)
44  {}
45 
46  // Its not valid to copy a MPIPack but you can move it
47  MPIPack(const MPIPack&) = delete;
48  MPIPack& operator = (const MPIPack& other) = delete;
49  MPIPack(MPIPack&&) = default;
50  MPIPack& operator = (MPIPack&& other) = default;
51 
57  template<class T>
58  void pack(const T& data){
59  auto mpidata = getMPIData(data);
60  int size = getPackSize(mpidata.size(), _comm, mpidata.type());
61  constexpr bool has_static_size = decltype(getMPIData(std::declval<T&>()))::static_size;
62  if(!has_static_size)
63  size += getPackSize(1, _comm, MPI_INT);
64  if (_position + size > 0 && size_t(_position + size) > _buffer.size()) // resize buffer if necessary
65  _buffer.resize(_position + size);
66  if(!has_static_size){
67  int size = mpidata.size();
68  MPI_Pack(&size, 1, MPI_INT, _buffer.data(), _buffer.size(),
69  &_position, _comm);
70  }
71  MPI_Pack(mpidata.ptr(), mpidata.size(),
72  mpidata.type(), _buffer.data(), _buffer.size(),
73  &_position, _comm);
74  }
75 
80  template<class T>
81  auto /*void*/ unpack(T& data)
82  -> std::enable_if_t<decltype(getMPIData(data))::static_size, void>
83  {
84  auto mpidata = getMPIData(data);
85  MPI_Unpack(_buffer.data(), _buffer.size(), &_position,
86  mpidata.ptr(), mpidata.size(),
87  mpidata.type(), _comm);
88  }
89 
94  template<class T>
95  auto /*void*/ unpack(T& data)
96  -> std::enable_if_t<!decltype(getMPIData(data))::static_size, void>
97  {
98  auto mpidata = getMPIData(data);
99  int size = 0;
100  MPI_Unpack(_buffer.data(), _buffer.size(), &_position,
101  &size, 1,
102  MPI_INT, _comm);
103  mpidata.resize(size);
104  MPI_Unpack(_buffer.data(), _buffer.size(), &_position,
105  mpidata.ptr(), mpidata.size(),
106  mpidata.type(), _comm);
107  }
108 
109 
111  template<typename T>
112  friend MPIPack& operator << (MPIPack& p, const T& t){
113  p.pack(t);
114  return p;
115  }
116 
118  template<typename T>
119  friend MPIPack& operator >> (MPIPack& p, T& t){
120  p.unpack(t);
121  return p;
122  }
123 
125  template<typename T>
126  MPIPack& read(T& t){
127  unpack(t);
128  return *this;
129  }
130 
132  template<typename T>
133  MPIPack& write(const T& t){
134  pack(t);
135  return *this;
136  }
137 
141  void resize(size_t size){
142  _buffer.resize(size);
143  }
144 
147  void enlarge(int s) {
148  _buffer.resize(_buffer.size() + s);
149  }
150 
153  size_t size() const {
154  return _buffer.size();
155  }
156 
160  void seek(int p){
161  _position = p;
162  }
163 
167  int tell() const{
168  return _position;
169  }
170 
173  bool eof() const{
174  return std::size_t(_position)==_buffer.size();
175  }
176 
180  static int getPackSize(int len, const MPI_Comm& comm, const MPI_Datatype& dt){
181  int size;
182  MPI_Pack_size(len, dt, comm, &size);
183  return size;
184  }
185 
186  friend bool operator==(const MPIPack& a, const MPIPack& b) {
187  return a._buffer == b._buffer && a._comm == b._comm;
188  }
189  friend bool operator!=(const MPIPack& a, const MPIPack& b) {
190  return !(a==b);
191  }
192 
193  };
194 
195  template<class P>
196  struct MPIData<P, std::enable_if_t<std::is_same<std::remove_const_t<P>, MPIPack>::value>> {
197  protected:
198  friend auto getMPIData<P>(P& t);
199  MPIData(P& t) :
200  data_(t)
201  {}
202  public:
203  static constexpr bool static_size = std::is_const<P>::value;
204 
205  void* ptr() {
206  return (void*) data_._buffer.data();
207  }
208 
209  int size() {
210  return data_.size();
211  }
212 
213  MPI_Datatype type() const{
214  return MPI_PACKED;
215  }
216 
217  void resize(int size){
218  data_.resize(size);
219  }
220  protected:
221  P& data_;
222  };
223 
224 } // end namespace Dune
225 
226 #endif
227 #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:13
auto getMPIData(T &t)
Definition: mpidata.hh:43
Specialization of Communication for MPI.
Definition: mpicommunication.hh:108
Definition: mpidata.hh:50
T & data_
Definition: mpidata.hh:53
int size() const
Definition: mpidata.hh:67
static constexpr bool static_size
Definition: mpidata.hh:65
Definition: mpipack.hh:32
MPIPack & operator=(const MPIPack &other)=delete
void enlarge(int s)
Enlarges the internal buffer.
Definition: mpipack.hh:147
MPIPack & write(const T &t)
Packs the data into the object. Enlarges the internal buffer if necessary.
Definition: mpipack.hh:133
friend MPIPack & operator>>(MPIPack &p, T &t)
Unpacks data from the object.
Definition: mpipack.hh:119
friend bool operator!=(const MPIPack &a, const MPIPack &b)
Definition: mpipack.hh:189
size_t size() const
Returns the size of the internal buffer.
Definition: mpipack.hh:153
MPIPack(Communication< MPI_Comm > comm, std::size_t size=0)
Definition: mpipack.hh:40
void pack(const T &data)
Packs the data into the object. Enlarges the internal buffer if necessary.
Definition: mpipack.hh:58
MPIPack & read(T &t)
Unpacks data from the object.
Definition: mpipack.hh:126
auto unpack(T &data) -> std::enable_if_t<!decltype(getMPIData(data))::static_size, void >
Unpacks data from the object.
Definition: mpipack.hh:95
auto unpack(T &data) -> std::enable_if_t< decltype(getMPIData(data))::static_size, void >
Unpacks data from the object.
Definition: mpipack.hh:81
friend bool operator==(const MPIPack &a, const MPIPack &b)
Definition: mpipack.hh:186
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:160
bool eof() const
Checks whether the end of the buffer is reached.
Definition: mpipack.hh:173
void resize(size_t size)
Resizes the internal buffer.
Definition: mpipack.hh:141
int tell() const
Gets the position in the buffer where the next pack/unpack operation should take place.
Definition: mpipack.hh:167
friend MPIPack & operator<<(MPIPack &p, const T &t)
Packs the data into the object. Enlarges the internal buffer if necessary.
Definition: mpipack.hh:112
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:180