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 namespace detail
32 {
33  // std::void_t is C++17
34  template <typename>
35  using void_t = void;
36 
37  /*
38  * Check whether class T has a member "errorMsg" convertible
39  * to type std::string.
40  * Used to give helpful compile-time error messages with static_assert
41  * down in CallUndefinedDatatype.
42  */
43  template <typename T, typename = void>
45  {
46  static constexpr bool value = false;
47  };
48 
49  template <typename T>
50  struct HasErrorMessageMember<T, void_t<decltype(std::string(T::errorMsg))> >
51  {
52  static constexpr bool value = true;
53  };
54 
66  template <int n, typename ReturnType, typename Action, typename... Args>
68  {
69  static ReturnType call(Args &&...args)
70  {
72  {
73  throw std::runtime_error(
74  "[" + std::string(Action::errorMsg) +
75  "] Unknown Datatype.");
76  }
77  else
78  {
79  return Action::template call<n>(std::forward<Args>(args)...);
80  }
81  throw std::runtime_error("Unreachable!");
82  }
83  };
84 } // namespace detail
85 
100 template <typename Action, typename... Args>
101 auto switchType(Datatype dt, Args &&...args)
102  -> decltype(Action::template call<char>(std::forward<Args>(args)...))
103 {
104  using ReturnType =
105  decltype(Action::template call<char>(std::forward<Args>(args)...));
106  switch (dt)
107  {
108  case Datatype::CHAR:
109  return Action::template call<char>(std::forward<Args>(args)...);
110  case Datatype::UCHAR:
111  return Action::template call<unsigned char>(
112  std::forward<Args>(args)...);
113  case Datatype::SCHAR:
114  return Action::template call<signed char>(std::forward<Args>(args)...);
115  case Datatype::SHORT:
116  return Action::template call<short>(std::forward<Args>(args)...);
117  case Datatype::INT:
118  return Action::template call<int>(std::forward<Args>(args)...);
119  case Datatype::LONG:
120  return Action::template call<long>(std::forward<Args>(args)...);
121  case Datatype::LONGLONG:
122  return Action::template call<long long>(std::forward<Args>(args)...);
123  case Datatype::USHORT:
124  return Action::template call<unsigned short>(
125  std::forward<Args>(args)...);
126  case Datatype::UINT:
127  return Action::template call<unsigned int>(std::forward<Args>(args)...);
128  case Datatype::ULONG:
129  return Action::template call<unsigned long>(
130  std::forward<Args>(args)...);
131  case Datatype::ULONGLONG:
132  return Action::template call<unsigned long long>(
133  std::forward<Args>(args)...);
134  case Datatype::FLOAT:
135  return Action::template call<float>(std::forward<Args>(args)...);
136  case Datatype::DOUBLE:
137  return Action::template call<double>(std::forward<Args>(args)...);
138  case Datatype::LONG_DOUBLE:
139  return Action::template call<long double>(std::forward<Args>(args)...);
140  case Datatype::CFLOAT:
141  return Action::template call<std::complex<float> >(
142  std::forward<Args>(args)...);
143  case Datatype::CDOUBLE:
144  return Action::template call<std::complex<double> >(
145  std::forward<Args>(args)...);
146  case Datatype::CLONG_DOUBLE:
147  return Action::template call<std::complex<long double> >(
148  std::forward<Args>(args)...);
149  case Datatype::STRING:
150  return Action::template call<std::string>(std::forward<Args>(args)...);
151  case Datatype::VEC_CHAR:
152  return Action::template call<std::vector<char> >(
153  std::forward<Args>(args)...);
154  case Datatype::VEC_SHORT:
155  return Action::template call<std::vector<short> >(
156  std::forward<Args>(args)...);
157  case Datatype::VEC_INT:
158  return Action::template call<std::vector<int> >(
159  std::forward<Args>(args)...);
160  case Datatype::VEC_LONG:
161  return Action::template call<std::vector<long> >(
162  std::forward<Args>(args)...);
163  case Datatype::VEC_LONGLONG:
164  return Action::template call<std::vector<long long> >(
165  std::forward<Args>(args)...);
166  case Datatype::VEC_UCHAR:
167  return Action::template call<std::vector<unsigned char> >(
168  std::forward<Args>(args)...);
169  case Datatype::VEC_SCHAR:
170  return Action::template call<std::vector<signed char> >(
171  std::forward<Args>(args)...);
172  case Datatype::VEC_USHORT:
173  return Action::template call<std::vector<unsigned short> >(
174  std::forward<Args>(args)...);
175  case Datatype::VEC_UINT:
176  return Action::template call<std::vector<unsigned int> >(
177  std::forward<Args>(args)...);
178  case Datatype::VEC_ULONG:
179  return Action::template call<std::vector<unsigned long> >(
180  std::forward<Args>(args)...);
181  case Datatype::VEC_ULONGLONG:
182  return Action::template call<std::vector<unsigned long long> >(
183  std::forward<Args>(args)...);
184  case Datatype::VEC_FLOAT:
185  return Action::template call<std::vector<float> >(
186  std::forward<Args>(args)...);
187  case Datatype::VEC_DOUBLE:
188  return Action::template call<std::vector<double> >(
189  std::forward<Args>(args)...);
190  case Datatype::VEC_LONG_DOUBLE:
191  return Action::template call<std::vector<long double> >(
192  std::forward<Args>(args)...);
193  case Datatype::VEC_CFLOAT:
194  return Action::template call<std::vector<std::complex<float> > >(
195  std::forward<Args>(args)...);
196  case Datatype::VEC_CDOUBLE:
197  return Action::template call<std::vector<std::complex<double> > >(
198  std::forward<Args>(args)...);
199  case Datatype::VEC_CLONG_DOUBLE:
200  return Action::template call<std::vector<std::complex<long double> > >(
201  std::forward<Args>(args)...);
202  case Datatype::VEC_STRING:
203  return Action::template call<std::vector<std::string> >(
204  std::forward<Args>(args)...);
205  case Datatype::ARR_DBL_7:
206  return Action::template call<std::array<double, 7> >(
207  std::forward<Args>(args)...);
208  case Datatype::BOOL:
209  return Action::template call<bool>(std::forward<Args>(args)...);
210  case Datatype::UNDEFINED:
211  return detail::
212  CallUndefinedDatatype<0, ReturnType, Action, Args &&...>::call(
213  std::forward<Args>(args)...);
214  default:
215  throw std::runtime_error(
216  "Internal error: Encountered unknown datatype (switchType) ->" +
217  std::to_string(static_cast<int>(dt)));
218  }
219 }
220 
236 template <typename Action, typename... Args>
237 auto switchNonVectorType(Datatype dt, Args &&...args)
238  -> decltype(Action::template call<char>(std::forward<Args>(args)...))
239 {
240  using ReturnType =
241  decltype(Action::template call<char>(std::forward<Args>(args)...));
242  switch (dt)
243  {
244  case Datatype::CHAR:
245  return Action::template call<char>(std::forward<Args>(args)...);
246  case Datatype::UCHAR:
247  return Action::template call<unsigned char>(
248  std::forward<Args>(args)...);
249  case Datatype::SCHAR:
250  return Action::template call<signed char>(std::forward<Args>(args)...);
251  case Datatype::SHORT:
252  return Action::template call<short>(std::forward<Args>(args)...);
253  case Datatype::INT:
254  return Action::template call<int>(std::forward<Args>(args)...);
255  case Datatype::LONG:
256  return Action::template call<long>(std::forward<Args>(args)...);
257  case Datatype::LONGLONG:
258  return Action::template call<long long>(std::forward<Args>(args)...);
259  case Datatype::USHORT:
260  return Action::template call<unsigned short>(
261  std::forward<Args>(args)...);
262  case Datatype::UINT:
263  return Action::template call<unsigned int>(std::forward<Args>(args)...);
264  case Datatype::ULONG:
265  return Action::template call<unsigned long>(
266  std::forward<Args>(args)...);
267  case Datatype::ULONGLONG:
268  return Action::template call<unsigned long long>(
269  std::forward<Args>(args)...);
270  case Datatype::FLOAT:
271  return Action::template call<float>(std::forward<Args>(args)...);
272  case Datatype::DOUBLE:
273  return Action::template call<double>(std::forward<Args>(args)...);
274  case Datatype::LONG_DOUBLE:
275  return Action::template call<long double>(std::forward<Args>(args)...);
276  case Datatype::CFLOAT:
277  return Action::template call<std::complex<float> >(
278  std::forward<Args>(args)...);
279  case Datatype::CDOUBLE:
280  return Action::template call<std::complex<double> >(
281  std::forward<Args>(args)...);
282  case Datatype::CLONG_DOUBLE:
283  return Action::template call<std::complex<long double> >(
284  std::forward<Args>(args)...);
285  case Datatype::STRING:
286  return Action::template call<std::string>(std::forward<Args>(args)...);
287  case Datatype::BOOL:
288  return Action::template call<bool>(std::forward<Args>(args)...);
289  case Datatype::UNDEFINED:
290  return detail::
291  CallUndefinedDatatype<0, ReturnType, Action, Args &&...>::call(
292  std::forward<Args>(args)...);
293  default:
294  throw std::runtime_error(
295  "Internal error: Encountered unknown datatype (switchType) ->" +
296  std::to_string(static_cast<int>(dt)));
297  }
298 }
299 } // namespace openPMD
auto switchType(Datatype dt, Args &&...args) -> decltype(Action::template call< char >(std::forward< Args >(args)...))
Generalizes switching over an openPMD datatype.
Definition: DatatypeHelpers.hpp:101
Purpose of this struct is to detect at compile time whether Action::template operator()<0>() exists...
Definition: DatatypeHelpers.hpp:67
STL namespace.
Datatype
Concrete datatype of an object available at runtime.
Definition: Datatype.hpp:45
auto switchNonVectorType(Datatype dt, Args &&...args) -> decltype(Action::template call< char >(std::forward< Args >(args)...))
Generalizes switching over an openPMD datatype.
Definition: DatatypeHelpers.hpp:237
Definition: Container.cpp:51
Definition: DatatypeHelpers.hpp:44
Public definitions of openPMD-api.