openPMD-api
DatatypeHelpers.hpp
1 /* Copyright 2017-2021 Fabian Koller, Franz Poeschel, Axel Huebl
2  *
3  * This file is part of openPMD-api.
4  *
5  * openPMD-api is free software: you can redistribute it and/or modify
6  * it under the terms of of either the GNU General Public License or
7  * the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * openPMD-api is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License and the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * and the GNU Lesser General Public License along with openPMD-api.
19  * If not, see <http://www.gnu.org/licenses/>.
20  */
21 #pragma once
22 
23 #include "openPMD/Datatype.hpp"
24 
25 #include <string>
26 #include <type_traits>
27 #include <utility> // std::forward
28 
29 namespace openPMD
30 {
31 
32 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__)
33 #define OPENPMD_TEMPLATE_OPERATOR operator
34 #else
35 #define OPENPMD_TEMPLATE_OPERATOR template operator
36 #endif
37 
38 namespace detail
39 {
40  // std::void_t is C++17
41  template <typename>
42  using void_t = void;
43 
44  /*
45  * Check whether class T has a member "errorMsg" convertible
46  * to type std::string.
47  * Used to give helpful compile-time error messages with static_assert
48  * down in CallUndefinedDatatype.
49  */
50  template <typename T, typename = void>
52  {
53  static constexpr bool value = false;
54  };
55 
56  template <typename T>
58  T,
59  void_t<decltype(std::string(std::declval<T>().errorMsg))> >
60  {
61  static constexpr bool value = true;
62  };
63 
76  template <
77  int n,
78  typename ReturnType,
79  typename Action,
80  typename Placeholder,
81  typename... Args>
83  {
84  static ReturnType call(Action action, Args &&...)
85  {
86  static_assert(
88  "[switchType] Action needs either an errorMsg member of type "
89  "std::string or operator()<unsigned>() overloads.");
90  throw std::runtime_error(
91  "[" + std::string(action.errorMsg) + "] Unknown Datatype.");
92  }
93  };
94 
95  template <int n, typename ReturnType, typename Action, typename... Args>
97  n,
98  ReturnType,
99  Action,
100  // Enable this, if no error message member is found.
101  // action.template operator()<n>() will be called instead
102  typename std::enable_if<!HasErrorMessageMember<Action>::value>::type,
103  Args...>
104  {
105  static ReturnType call(Action action, Args &&...args)
106  {
107  return action.OPENPMD_TEMPLATE_OPERATOR()<n>(
108  std::forward<Args>(args)...);
109  }
110  };
111 } // namespace detail
112 
130 template <typename Action, typename... Args>
131 auto switchType(Datatype dt, Action action, Args &&...args)
132  -> decltype(action.OPENPMD_TEMPLATE_OPERATOR() < char > (std::forward<Args>(args)...))
133 {
134  using ReturnType =
135  decltype(action.OPENPMD_TEMPLATE_OPERATOR() < char > (std::forward<Args>(args)...));
136  switch (dt)
137  {
138  case Datatype::CHAR:
139  return action.OPENPMD_TEMPLATE_OPERATOR()<char>(
140  std::forward<Args>(args)...);
141  case Datatype::UCHAR:
142  return action.OPENPMD_TEMPLATE_OPERATOR()<unsigned char>(
143  std::forward<Args>(args)...);
144  case Datatype::SHORT:
145  return action.OPENPMD_TEMPLATE_OPERATOR()<short>(
146  std::forward<Args>(args)...);
147  case Datatype::INT:
148  return action.OPENPMD_TEMPLATE_OPERATOR()<int>(
149  std::forward<Args>(args)...);
150  case Datatype::LONG:
151  return action.OPENPMD_TEMPLATE_OPERATOR()<long>(
152  std::forward<Args>(args)...);
153  case Datatype::LONGLONG:
154  return action.OPENPMD_TEMPLATE_OPERATOR()<long long>(
155  std::forward<Args>(args)...);
156  case Datatype::USHORT:
157  return action.OPENPMD_TEMPLATE_OPERATOR()<unsigned short>(
158  std::forward<Args>(args)...);
159  case Datatype::UINT:
160  return action.OPENPMD_TEMPLATE_OPERATOR()<unsigned int>(
161  std::forward<Args>(args)...);
162  case Datatype::ULONG:
163  return action.OPENPMD_TEMPLATE_OPERATOR()<unsigned long>(
164  std::forward<Args>(args)...);
165  case Datatype::ULONGLONG:
166  return action.OPENPMD_TEMPLATE_OPERATOR()<unsigned long long>(
167  std::forward<Args>(args)...);
168  case Datatype::FLOAT:
169  return action.OPENPMD_TEMPLATE_OPERATOR()<float>(
170  std::forward<Args>(args)...);
171  case Datatype::DOUBLE:
172  return action.OPENPMD_TEMPLATE_OPERATOR()<double>(
173  std::forward<Args>(args)...);
174  case Datatype::LONG_DOUBLE:
175  return action.OPENPMD_TEMPLATE_OPERATOR()<long double>(
176  std::forward<Args>(args)...);
177  case Datatype::CFLOAT:
178  return action.OPENPMD_TEMPLATE_OPERATOR()<std::complex<float> >(
179  std::forward<Args>(args)...);
180  case Datatype::CDOUBLE:
181  return action.OPENPMD_TEMPLATE_OPERATOR()<std::complex<double> >(
182  std::forward<Args>(args)...);
183  case Datatype::CLONG_DOUBLE:
184  return action.OPENPMD_TEMPLATE_OPERATOR()<std::complex<long double> >(
185  std::forward<Args>(args)...);
186  case Datatype::STRING:
187  return action.OPENPMD_TEMPLATE_OPERATOR()<std::string>(
188  std::forward<Args>(args)...);
189  case Datatype::VEC_CHAR:
190  return action.OPENPMD_TEMPLATE_OPERATOR()<std::vector<char> >(
191  std::forward<Args>(args)...);
192  case Datatype::VEC_SHORT:
193  return action.OPENPMD_TEMPLATE_OPERATOR()<std::vector<short> >(
194  std::forward<Args>(args)...);
195  case Datatype::VEC_INT:
196  return action.OPENPMD_TEMPLATE_OPERATOR()<std::vector<int> >(
197  std::forward<Args>(args)...);
198  case Datatype::VEC_LONG:
199  return action.OPENPMD_TEMPLATE_OPERATOR()<std::vector<long> >(
200  std::forward<Args>(args)...);
201  case Datatype::VEC_LONGLONG:
202  return action.OPENPMD_TEMPLATE_OPERATOR()<std::vector<long long> >(
203  std::forward<Args>(args)...);
204  case Datatype::VEC_UCHAR:
205  return action.OPENPMD_TEMPLATE_OPERATOR()<std::vector<unsigned char> >(
206  std::forward<Args>(args)...);
207  case Datatype::VEC_USHORT:
208  return action.OPENPMD_TEMPLATE_OPERATOR()<std::vector<unsigned short> >(
209  std::forward<Args>(args)...);
210  case Datatype::VEC_UINT:
211  return action.OPENPMD_TEMPLATE_OPERATOR()<std::vector<unsigned int> >(
212  std::forward<Args>(args)...);
213  case Datatype::VEC_ULONG:
214  return action.OPENPMD_TEMPLATE_OPERATOR()<std::vector<unsigned long> >(
215  std::forward<Args>(args)...);
216  case Datatype::VEC_ULONGLONG:
217  return action
218  .OPENPMD_TEMPLATE_OPERATOR()<std::vector<unsigned long long> >(
219  std::forward<Args>(args)...);
220  case Datatype::VEC_FLOAT:
221  return action.OPENPMD_TEMPLATE_OPERATOR()<std::vector<float> >(
222  std::forward<Args>(args)...);
223  case Datatype::VEC_DOUBLE:
224  return action.OPENPMD_TEMPLATE_OPERATOR()<std::vector<double> >(
225  std::forward<Args>(args)...);
226  case Datatype::VEC_LONG_DOUBLE:
227  return action.OPENPMD_TEMPLATE_OPERATOR()<std::vector<long double> >(
228  std::forward<Args>(args)...);
229  case Datatype::VEC_CFLOAT:
230  return action
231  .OPENPMD_TEMPLATE_OPERATOR()<std::vector<std::complex<float> > >(
232  std::forward<Args>(args)...);
233  case Datatype::VEC_CDOUBLE:
234  return action
235  .OPENPMD_TEMPLATE_OPERATOR()<std::vector<std::complex<double> > >(
236  std::forward<Args>(args)...);
237  case Datatype::VEC_CLONG_DOUBLE:
238  return action.OPENPMD_TEMPLATE_OPERATOR()<
239  std::vector<std::complex<long double> > >(
240  std::forward<Args>(args)...);
241  case Datatype::VEC_STRING:
242  return action.OPENPMD_TEMPLATE_OPERATOR()<std::vector<std::string> >(
243  std::forward<Args>(args)...);
244  case Datatype::ARR_DBL_7:
245  return action.OPENPMD_TEMPLATE_OPERATOR()<std::array<double, 7> >(
246  std::forward<Args>(args)...);
247  case Datatype::BOOL:
248  return action.OPENPMD_TEMPLATE_OPERATOR()<bool>(
249  std::forward<Args>(args)...);
250  case Datatype::DATATYPE:
252  HIGHEST_DATATYPE,
253  ReturnType,
254  Action,
255  void,
256  Args &&...>::call(std::move(action), std::forward<Args>(args)...);
257  case Datatype::UNDEFINED:
259  LOWEST_DATATYPE,
260  ReturnType,
261  Action,
262  void,
263  Args &&...>::call(std::move(action), std::forward<Args>(args)...);
264  default:
265  throw std::runtime_error(
266  "Internal error: Encountered unknown datatype (switchType) ->" +
267  std::to_string(static_cast<int>(dt)));
268  }
269 }
270 
289 template <typename Action, typename... Args>
290 auto switchNonVectorType(Datatype dt, Action action, Args &&...args)
291  -> decltype(action.OPENPMD_TEMPLATE_OPERATOR() < char > (std::forward<Args>(args)...))
292 {
293  using ReturnType =
294  decltype(action.OPENPMD_TEMPLATE_OPERATOR() < char > (std::forward<Args>(args)...));
295  switch (dt)
296  {
297  case Datatype::CHAR:
298  return action.OPENPMD_TEMPLATE_OPERATOR()<char>(
299  std::forward<Args>(args)...);
300  case Datatype::UCHAR:
301  return action.OPENPMD_TEMPLATE_OPERATOR()<unsigned char>(
302  std::forward<Args>(args)...);
303  case Datatype::SHORT:
304  return action.OPENPMD_TEMPLATE_OPERATOR()<short>(
305  std::forward<Args>(args)...);
306  case Datatype::INT:
307  return action.OPENPMD_TEMPLATE_OPERATOR()<int>(
308  std::forward<Args>(args)...);
309  case Datatype::LONG:
310  return action.OPENPMD_TEMPLATE_OPERATOR()<long>(
311  std::forward<Args>(args)...);
312  case Datatype::LONGLONG:
313  return action.OPENPMD_TEMPLATE_OPERATOR()<long long>(
314  std::forward<Args>(args)...);
315  case Datatype::USHORT:
316  return action.OPENPMD_TEMPLATE_OPERATOR()<unsigned short>(
317  std::forward<Args>(args)...);
318  case Datatype::UINT:
319  return action.OPENPMD_TEMPLATE_OPERATOR()<unsigned int>(
320  std::forward<Args>(args)...);
321  case Datatype::ULONG:
322  return action.OPENPMD_TEMPLATE_OPERATOR()<unsigned long>(
323  std::forward<Args>(args)...);
324  case Datatype::ULONGLONG:
325  return action.OPENPMD_TEMPLATE_OPERATOR()<unsigned long long>(
326  std::forward<Args>(args)...);
327  case Datatype::FLOAT:
328  return action.OPENPMD_TEMPLATE_OPERATOR()<float>(
329  std::forward<Args>(args)...);
330  case Datatype::DOUBLE:
331  return action.OPENPMD_TEMPLATE_OPERATOR()<double>(
332  std::forward<Args>(args)...);
333  case Datatype::LONG_DOUBLE:
334  return action.OPENPMD_TEMPLATE_OPERATOR()<long double>(
335  std::forward<Args>(args)...);
336  case Datatype::CFLOAT:
337  return action.OPENPMD_TEMPLATE_OPERATOR()<std::complex<float> >(
338  std::forward<Args>(args)...);
339  case Datatype::CDOUBLE:
340  return action.OPENPMD_TEMPLATE_OPERATOR()<std::complex<double> >(
341  std::forward<Args>(args)...);
342  case Datatype::CLONG_DOUBLE:
343  return action.OPENPMD_TEMPLATE_OPERATOR()<std::complex<long double> >(
344  std::forward<Args>(args)...);
345  case Datatype::STRING:
346  return action.OPENPMD_TEMPLATE_OPERATOR()<std::string>(
347  std::forward<Args>(args)...);
348  case Datatype::BOOL:
349  return action.OPENPMD_TEMPLATE_OPERATOR()<bool>(
350  std::forward<Args>(args)...);
351  case Datatype::DATATYPE:
353  HIGHEST_DATATYPE,
354  ReturnType,
355  Action,
356  void,
357  Args &&...>::call(std::move(action), std::forward<Args>(args)...);
358  case Datatype::UNDEFINED:
360  LOWEST_DATATYPE,
361  ReturnType,
362  Action,
363  void,
364  Args &&...>::call(std::move(action), std::forward<Args>(args)...);
365  default:
366  throw std::runtime_error(
367  "Internal error: Encountered unknown datatype (switchType) ->" +
368  std::to_string(static_cast<int>(dt)));
369  }
370 }
371 #undef OPENPMD_TEMPLATE_OPERATOR
372 } // namespace openPMD
auto switchType(Datatype dt, Action action, Args &&...args) -> decltype(action. template operator()< char >(std::forward< Args >(args)...))
Generalizes switching over an openPMD datatype.
Definition: DatatypeHelpers.hpp:131
Purpose of this struct is to detect at compile time whether Action::template operator()<0>() exists...
Definition: DatatypeHelpers.hpp:82
STL namespace.
Datatype
Concrete datatype of an object available at runtime.
Definition: Datatype.hpp:45
Definition: Container.cpp:50
auto switchNonVectorType(Datatype dt, Action action, Args &&...args) -> decltype(action. template operator()< char >(std::forward< Args >(args)...))
Generalizes switching over an openPMD datatype.
Definition: DatatypeHelpers.hpp:290
Definition: DatatypeHelpers.hpp:51
Public definitions of openPMD-api.
Definition: Date.cpp:28