standard_type.h
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2018 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 #ifndef LIBMESH_STANDARD_TYPE_H
20 #define LIBMESH_STANDARD_TYPE_H
21 
22 // Parallel includes
23 #include "libmesh/data_type.h"
24 
25 // libMesh Includes
26 #include "libmesh/libmesh_common.h"
27 #include "libmesh/auto_ptr.h"
28 
29 // C++ includes
30 #include <array>
31 #include <complex>
32 #include <memory>
33 #include <numeric>
34 #include <tuple>
35 #include <type_traits>
36 #include <utility>
37 #include <vector>
38 
39 namespace libMesh
40 {
41 
46 namespace Parallel
47 {
48 
49 //-------------------------------------------------------------------
50 
51 // Templated helper class to be used with static_assert.
52 template<typename T>
53 struct standardtype_dependent_false : std::false_type
54 {};
55 
63 template <typename T>
64 class StandardType : public DataType
65 {
66  // Get a slightly better compiler diagnostic
68  "Only specializations of StandardType may be used, did you forget to include a header file (e.g. parallel_algebra.h)?");
69 
70  /*
71  * The unspecialized class is useless, so we make its constructor
72  * private to catch mistakes at compile-time rather than link-time.
73  * Specializations should have a public constructor of the same
74  * form.
75  */
76 private:
77  StandardType(const T * example = nullptr);
78 };
79 
80 
81 
82 // ------------------------------------------------------------
83 // Declare StandardType specializations for C++ built-in types
84 
85 #ifdef LIBMESH_HAVE_MPI
86 
87 #define LIBMESH_STANDARD_TYPE(cxxtype,mpitype) \
88  template<> \
89  class StandardType<cxxtype> : public DataType \
90  { \
91  public: \
92  explicit \
93  StandardType(const cxxtype * = nullptr) : DataType(mpitype) {} \
94  }
95 
96 #else
97 
98 #define LIBMESH_STANDARD_TYPE(cxxtype,mpitype) \
99  template<> \
100  class StandardType<cxxtype> : public DataType \
101  { \
102  public: \
103  explicit \
104  StandardType(const cxxtype * = nullptr) : DataType() {} \
105  }
106 
107 #endif
108 
109 LIBMESH_STANDARD_TYPE(char,MPI_CHAR);
110 LIBMESH_STANDARD_TYPE(signed char,MPI_SIGNED_CHAR);
111 LIBMESH_STANDARD_TYPE(unsigned char,MPI_UNSIGNED_CHAR);
112 LIBMESH_STANDARD_TYPE(short int,MPI_SHORT);
113 LIBMESH_STANDARD_TYPE(unsigned short int,MPI_UNSIGNED_SHORT);
114 LIBMESH_STANDARD_TYPE(int,MPI_INT);
115 LIBMESH_STANDARD_TYPE(unsigned int,MPI_UNSIGNED);
116 LIBMESH_STANDARD_TYPE(long,MPI_LONG);
117 LIBMESH_STANDARD_TYPE(long long,MPI_LONG_LONG_INT);
118 LIBMESH_STANDARD_TYPE(unsigned long,MPI_UNSIGNED_LONG);
119 LIBMESH_STANDARD_TYPE(unsigned long long,MPI_UNSIGNED_LONG_LONG);
120 LIBMESH_STANDARD_TYPE(float,MPI_FLOAT);
121 LIBMESH_STANDARD_TYPE(double,MPI_DOUBLE);
122 LIBMESH_STANDARD_TYPE(long double,MPI_LONG_DOUBLE);
123 
124 template<typename T1, typename T2>
125 class StandardType<std::pair<T1, T2>> : public DataType
126 {
127 public:
128  explicit
129  StandardType(const std::pair<T1, T2> * example = nullptr) {
130  // We need an example for MPI_Address to use
131  static const std::pair<T1, T2> p;
132  if (!example)
133  example = &p;
134 
135 #ifdef LIBMESH_HAVE_MPI
136 
137  // Get the sub-data-types, and make sure they live long enough
138  // to construct the derived type
139  StandardType<T1> d1(&example->first);
140  StandardType<T2> d2(&example->second);
141 
142  MPI_Datatype types[] = { (data_type)d1, (data_type)d2 };
143  int blocklengths[] = {1,1};
144  MPI_Aint displs[2], start;
145 
146  libmesh_call_mpi
147  (MPI_Get_address (const_cast<std::pair<T1,T2> *>(example),
148  &start));
149  libmesh_call_mpi
150  (MPI_Get_address (const_cast<T1*>(&example->first),
151  &displs[0]));
152  libmesh_call_mpi
153  (MPI_Get_address (const_cast<T2*>(&example->second),
154  &displs[1]));
155  displs[0] -= start;
156  displs[1] -= start;
157 
158  // create a prototype structure
159  MPI_Datatype tmptype;
160  libmesh_call_mpi
161  (MPI_Type_create_struct (2, blocklengths, displs, types,
162  &tmptype));
163  libmesh_call_mpi
164  (MPI_Type_commit (&tmptype));
165 
166  // resize the structure type to account for padding, if any
167  libmesh_call_mpi
168  (MPI_Type_create_resized (tmptype, 0,
169  sizeof(std::pair<T1,T2>),
170  &_datatype));
171  libmesh_call_mpi
172  (MPI_Type_free (&tmptype));
173 
174  this->commit();
175 
176 #endif // LIBMESH_HAVE_MPI
177 
178  }
179 
180  StandardType(const StandardType<std::pair<T1, T2>> & t)
181  {
182  libmesh_call_mpi
183  (MPI_Type_dup (t._datatype, &_datatype));
184  }
185 
186  ~StandardType() { this->free(); }
187 };
188 
189 
190 // Helper functions for creating type/displacement arrays for tuples
191 //
192 // These are classes since we can't partially specialize functions
193 template<std::size_t n_minus_i>
195 {
196  template<typename... Types>
197  static void build(std::vector<std::unique_ptr<DataType>> & out_vec,
198  const std::tuple<Types...> & example);
199 };
200 
201 template <>
203 {
204  template<typename... Types>
205  static void build(std::vector<std::unique_ptr<DataType>> & /*out_vec*/,
206  const std::tuple<Types...> & /*example*/) {}
207 };
208 
209 template<std::size_t n_minus_i>
210 template<typename... Types>
212  (std::vector<std::unique_ptr<DataType>> & out_vec,
213  const std::tuple<Types...> & example)
214 {
215  typedef typename
216  std::tuple_element<sizeof...(Types)-n_minus_i, std::tuple<Types...>>::type
217  ith_type;
218 
219  out_vec.push_back
220  (libmesh_make_unique<
222  >(&std::get<sizeof...(Types)-n_minus_i>(example)));
223 
225 }
226 
227 
228 template<std::size_t n_minus_i>
230 {
231  template <typename OutArray, class... Types>
232  static void fill(OutArray & out,
233  const std::tuple<Types...> & example);
234 };
235 
236 template<>
238 {
239  template <typename OutArray, typename... Types>
240  static void fill(OutArray & /*out*/,
241  const std::tuple<Types...> & /*example*/) {}
242 };
243 
244 
245 template<std::size_t n_minus_i>
246 template<typename OutArray, typename... Types>
248  (OutArray & out_vec,
249  const std::tuple<Types...> & example)
250 {
251  libmesh_call_mpi
252  (MPI_Get_address
253  (&std::get<sizeof...(Types)-n_minus_i>(example),
254  &out_vec[sizeof...(Types)-n_minus_i]));
255 
257 }
258 
259 
260 template<typename... Types>
261 class StandardType<std::tuple<Types...>> : public DataType
262 {
263 public:
264  explicit
265  StandardType(const std::tuple<Types...> * example = nullptr) {
266  // We need an example for MPI_Address to use
267  static const std::tuple<Types...> t;
268  if (!example)
269  example = &t;
270 
271 #ifdef LIBMESH_HAVE_MPI
272  MPI_Aint start;
273 
274  libmesh_call_mpi
275  (MPI_Get_address (example, &start));
276 
277  const std::size_t tuplesize = sizeof...(Types);
278 
279  std::vector<std::unique_ptr<DataType>> subtypes;
280  BuildStandardTypeVector<sizeof...(Types)>::build(subtypes, *example);
281 
282  std::array<MPI_Aint, sizeof...(Types)> displs;
283  FillDisplacementArray<sizeof...(Types)>::fill(displs, *example);
284 
285  std::array<MPI_Datatype, sizeof...(Types)> types;
286  std::array<int, sizeof...(Types)> blocklengths;
287 
288  for (std::size_t i = 0; i != tuplesize; ++i)
289  {
290  displs[i] -= start;
291  types[i] = (data_type)(*subtypes[i]);
292  blocklengths[i] = 1;
293  }
294 
295  // create a prototype structure
296  MPI_Datatype tmptype;
297  libmesh_call_mpi
298  (MPI_Type_create_struct (tuplesize, blocklengths.data(), displs.data(), types.data(),
299  &tmptype));
300  libmesh_call_mpi
301  (MPI_Type_commit (&tmptype));
302 
303  // resize the structure type to account for padding, if any
304  libmesh_call_mpi
305  (MPI_Type_create_resized (tmptype, 0,
306  sizeof(std::tuple<Types...>),
307  &_datatype));
308  libmesh_call_mpi
309  (MPI_Type_free (&tmptype));
310 
311  this->commit();
312 
313 #endif // LIBMESH_HAVE_MPI
314 
315  }
316 
317  StandardType(const StandardType<std::tuple<Types...>> & t)
318  {
319  libmesh_call_mpi
320  (MPI_Type_dup (t._datatype, &_datatype));
321  }
322 
323  ~StandardType() { this->free(); }
324 };
325 
326 
327 template<typename T>
328 class StandardType<std::complex<T>> : public DataType
329 {
330 public:
331  explicit
332  StandardType(const std::complex<T> * /*example*/ = nullptr) :
333  DataType(StandardType<T>(nullptr), 2) {}
334 
335  ~StandardType() { this->free(); }
336 };
337 
338 
339 
340 } // namespace Parallel
341 
342 } // namespace libMesh
343 
344 #endif // LIBMESH_STANDARD_TYPE_H
StandardType(const std::complex< T > *=nullptr)
static void build(std::vector< std::unique_ptr< DataType >> &out_vec, const std::tuple< Types... > &example)
LIBMESH_STANDARD_TYPE(char, MPI_CHAR)
static void fill(OutArray &out, const std::tuple< Types... > &example)
MPI_Datatype data_type
Definition: data_type.h:46
StandardType(const StandardType< std::tuple< Types... >> &t)
StandardType(const StandardType< std::pair< T1, T2 >> &t)
static void build(std::vector< std::unique_ptr< DataType >> &, const std::tuple< Types... > &)
StandardType(const std::tuple< Types... > *example=nullptr)
StandardType(const std::pair< T1, T2 > *example=nullptr)
StandardType(const T *example=nullptr)
static void fill(OutArray &, const std::tuple< Types... > &)
OStreamProxy out(std::cout)
const Elem & get(const ElemType type_in)