34
34
#include < string>
35
35
#include < type_traits>
36
36
#include < utility>
37
+ #include < variant>
37
38
#include < vector>
38
39
39
40
namespace openPMD
@@ -134,202 +135,101 @@ class Attribute
134
135
std::optional<U> getOptional () const ;
135
136
};
136
137
137
- template <typename T, typename U>
138
- auto doConvert (T *pv) -> U
138
+ namespace detail
139
139
{
140
- ( void )pv;
141
- if constexpr ( std::is_convertible_v<T, U>)
140
+ template < typename T, typename U>
141
+ auto doConvert (T *pv) -> std::variant<U, std::runtime_error>
142
142
{
143
- return static_cast <U>(*pv);
144
- }
145
- else if constexpr (auxiliary::IsVector_v<T> && auxiliary::IsVector_v<U>)
146
- {
147
- if constexpr (std::is_convertible_v<
148
- typename T::value_type,
149
- typename U::value_type>)
143
+ (void )pv;
144
+ if constexpr (std::is_convertible_v<T, U>)
150
145
{
151
- U res{};
152
- res.reserve (pv->size ());
153
- std::copy (pv->begin (), pv->end (), std::back_inserter (res));
154
- return res;
146
+ return static_cast <U>(*pv);
155
147
}
156
- else
157
- {
158
- throw std::runtime_error (" getCast: no vector cast possible." );
159
- }
160
- }
161
- // conversion cast: array to vector
162
- // if a backend reports a std::array<> for something where
163
- // the frontend expects a vector
164
- else if constexpr (auxiliary::IsArray_v<T> && auxiliary::IsVector_v<U>)
165
- {
166
- if constexpr (std::is_convertible_v<
167
- typename T::value_type,
168
- typename U::value_type>)
169
- {
170
- U res{};
171
- res.reserve (pv->size ());
172
- std::copy (pv->begin (), pv->end (), std::back_inserter (res));
173
- return res;
174
- }
175
- else
176
- {
177
- throw std::runtime_error (
178
- " getCast: no array to vector conversion possible." );
179
- }
180
- }
181
- // conversion cast: vector to array
182
- // if a backend reports a std::vector<> for something where
183
- // the frontend expects an array
184
- else if constexpr (auxiliary::IsVector_v<T> && auxiliary::IsArray_v<U>)
185
- {
186
- if constexpr (std::is_convertible_v<
187
- typename T::value_type,
188
- typename U::value_type>)
148
+ else if constexpr (auxiliary::IsVector_v<T> && auxiliary::IsVector_v<U>)
189
149
{
190
- U res{};
191
- if (res.size () != pv->size ())
150
+ if constexpr (std::is_convertible_v<
151
+ typename T::value_type,
152
+ typename U::value_type>)
192
153
{
193
- throw std::runtime_error (
194
- " getCast: no vector to array conversion possible (wrong "
195
- " requested array size)." );
154
+ U res{};
155
+ res.reserve (pv->size ());
156
+ std::copy (pv->begin (), pv->end (), std::back_inserter (res));
157
+ return res;
196
158
}
197
- for ( size_t i = 0 ; i < res. size (); ++i)
159
+ else
198
160
{
199
- res[i] = static_cast < typename U::value_type>((*pv)[i] );
161
+ return std::runtime_error ( " getCast: no vector cast possible. " );
200
162
}
201
- return res;
202
163
}
203
- else
164
+ // conversion cast: array to vector
165
+ // if a backend reports a std::array<> for something where
166
+ // the frontend expects a vector
167
+ else if constexpr (auxiliary::IsArray_v<T> && auxiliary::IsVector_v<U>)
204
168
{
205
- throw std::runtime_error (
206
- " getCast: no vector to array conversion possible." );
207
- }
208
- }
209
- // conversion cast: turn a single value into a 1-element vector
210
- else if constexpr (auxiliary::IsVector_v<U>)
211
- {
212
- if constexpr (std::is_convertible_v<T, typename U::value_type>)
213
- {
214
- U res{};
215
- res.reserve (1 );
216
- res.push_back (static_cast <typename U::value_type>(*pv));
217
- return res;
218
- }
219
- else
220
- {
221
- throw std::runtime_error (
222
- " getCast: no scalar to vector conversion possible." );
223
- }
224
- }
225
- else
226
- {
227
- throw std::runtime_error (" getCast: no cast possible." );
228
- }
229
- #if defined(__INTEL_COMPILER)
230
- /*
231
- * ICPC has trouble with if constexpr, thinking that return statements are
232
- * missing afterwards. Deactivate the warning.
233
- * Note that putting a statement here will not help to fix this since it will
234
- * then complain about unreachable code.
235
- * https://community.intel.com/t5/Intel-C-Compiler/quot-if-constexpr-quot-and-quot-missing-return-statement-quot-in/td-p/1154551
236
- */
237
- #pragma warning(disable : 1011)
238
- }
239
- #pragma warning(default : 1011)
240
- #else
241
- }
242
- #endif
243
-
244
- template <typename T, typename U>
245
- auto doConvertOptional (T *pv) -> std::optional<U>
246
- {
247
- (void )pv;
248
- if constexpr (std::is_convertible_v<T, U>)
249
- {
250
- return static_cast <U>(*pv);
251
- }
252
- else if constexpr (auxiliary::IsVector_v<T> && auxiliary::IsVector_v<U>)
253
- {
254
- if constexpr (std::is_convertible_v<
255
- typename T::value_type,
256
- typename U::value_type>)
257
- {
258
- U res{};
259
- res.reserve (pv->size ());
260
- std::copy (pv->begin (), pv->end (), std::back_inserter (res));
261
- return res;
262
- }
263
- else
264
- {
265
- return {};
266
- }
267
- }
268
- // conversion cast: array to vector
269
- // if a backend reports a std::array<> for something where
270
- // the frontend expects a vector
271
- else if constexpr (auxiliary::IsArray_v<T> && auxiliary::IsVector_v<U>)
272
- {
273
- if constexpr (std::is_convertible_v<
274
- typename T::value_type,
275
- typename U::value_type>)
276
- {
277
- U res{};
278
- res.reserve (pv->size ());
279
- std::copy (pv->begin (), pv->end (), std::back_inserter (res));
280
- return res;
281
- }
282
- else
283
- {
284
- return {};
285
- }
286
- }
287
- // conversion cast: vector to array
288
- // if a backend reports a std::vector<> for something where
289
- // the frontend expects an array
290
- else if constexpr (auxiliary::IsVector_v<T> && auxiliary::IsArray_v<U>)
291
- {
292
- if constexpr (std::is_convertible_v<
293
- typename T::value_type,
294
- typename U::value_type>)
295
- {
296
- U res{};
297
- if (res.size () != pv->size ())
169
+ if constexpr (std::is_convertible_v<
170
+ typename T::value_type,
171
+ typename U::value_type>)
298
172
{
299
- throw std::runtime_error (
300
- " getCast: no vector to array conversion possible (wrong "
301
- " requested array size)." );
173
+ U res{};
174
+ res.reserve (pv->size ());
175
+ std::copy (pv->begin (), pv->end (), std::back_inserter (res));
176
+ return res;
302
177
}
303
- for ( size_t i = 0 ; i < res. size (); ++i)
178
+ else
304
179
{
305
- res[i] = static_cast <typename U::value_type>((*pv)[i]);
180
+ return std::runtime_error (
181
+ " getCast: no array to vector conversion possible." );
306
182
}
307
- return res;
308
183
}
309
- else
184
+ // conversion cast: vector to array
185
+ // if a backend reports a std::vector<> for something where
186
+ // the frontend expects an array
187
+ else if constexpr (auxiliary::IsVector_v<T> && auxiliary::IsArray_v<U>)
310
188
{
311
- return {};
189
+ if constexpr (std::is_convertible_v<
190
+ typename T::value_type,
191
+ typename U::value_type>)
192
+ {
193
+ U res{};
194
+ if (res.size () != pv->size ())
195
+ {
196
+ return std::runtime_error (
197
+ " getCast: no vector to array conversion possible "
198
+ " (wrong "
199
+ " requested array size)." );
200
+ }
201
+ for (size_t i = 0 ; i < res.size (); ++i)
202
+ {
203
+ res[i] = static_cast <typename U::value_type>((*pv)[i]);
204
+ }
205
+ return res;
206
+ }
207
+ else
208
+ {
209
+ return std::runtime_error (
210
+ " getCast: no vector to array conversion possible." );
211
+ }
312
212
}
313
- }
314
- // conversion cast: turn a single value into a 1-element vector
315
- else if constexpr (auxiliary::IsVector_v<U>)
316
- {
317
- if constexpr (std::is_convertible_v<T, typename U::value_type>)
213
+ // conversion cast: turn a single value into a 1-element vector
214
+ else if constexpr (auxiliary::IsVector_v<U>)
318
215
{
319
- U res{};
320
- res.reserve (1 );
321
- res.push_back (static_cast <typename U::value_type>(*pv));
322
- return res;
216
+ if constexpr (std::is_convertible_v<T, typename U::value_type>)
217
+ {
218
+ U res{};
219
+ res.reserve (1 );
220
+ res.push_back (static_cast <typename U::value_type>(*pv));
221
+ return res;
222
+ }
223
+ else
224
+ {
225
+ return std::runtime_error (
226
+ " getCast: no scalar to vector conversion possible." );
227
+ }
323
228
}
324
229
else
325
230
{
326
- return {} ;
231
+ return std::runtime_error ( " getCast: no cast possible. " ) ;
327
232
}
328
- }
329
- else
330
- {
331
- return {};
332
- }
333
233
#if defined(__INTEL_COMPILER)
334
234
/*
335
235
* ICPC has trouble with if constexpr, thinking that return statements are
@@ -342,44 +242,55 @@ auto doConvertOptional(T *pv) -> std::optional<U>
342
242
}
343
243
#pragma warning(default : 1011)
344
244
#else
345
- }
245
+ }
346
246
#endif
247
+ } // namespace detail
347
248
348
- /* * Retrieve a stored specific Attribute and cast if convertible.
349
- *
350
- * @throw std::runtime_error if stored object is not static castable to U.
351
- * @tparam U Type of the object to be casted to.
352
- * @return Copy of the retrieved object, casted to type U.
353
- */
354
249
template <typename U>
355
- inline U getCast ( Attribute const &a)
250
+ U Attribute::get () const
356
251
{
357
- auto v = a.getResource ();
358
-
252
+ auto eitherValueOrError = std::visit (
253
+ [](auto &&containedValue) -> std::variant<U, std::runtime_error> {
254
+ using containedType = std::decay_t <decltype (containedValue)>;
255
+ return detail::doConvert<containedType, U>(&containedValue);
256
+ },
257
+ Variant::getResource ());
359
258
return std::visit (
360
259
[](auto &&containedValue) -> U {
361
- using containedType = std::decay_t <decltype (containedValue)>;
362
- return doConvert<containedType, U>(&containedValue);
260
+ using T = std::decay_t <decltype (containedValue)>;
261
+ if constexpr (std::is_same_v<T, std::runtime_error>)
262
+ {
263
+ throw containedValue;
264
+ }
265
+ else
266
+ {
267
+ return std::forward<T>(containedValue);
268
+ }
363
269
},
364
- v);
365
- }
366
-
367
- template <typename U>
368
- U Attribute::get () const
369
- {
370
- return getCast<U>(Variant::getResource ());
270
+ std::move (eitherValueOrError));
371
271
}
372
272
373
273
template <typename U>
374
274
std::optional<U> Attribute::getOptional () const
375
275
{
376
- auto v = Variant::getResource ();
377
-
378
- return std::visit (
379
- [](auto &&containedValue) -> U {
276
+ auto eitherValueOrError = std::visit (
277
+ [](auto &&containedValue) -> std::variant<U, std::runtime_error> {
380
278
using containedType = std::decay_t <decltype (containedValue)>;
381
- return doConvert<containedType, U>(&containedValue);
279
+ return detail::doConvert<containedType, U>(&containedValue);
280
+ },
281
+ Variant::getResource ());
282
+ return std::visit (
283
+ [](auto &&containedValue) -> std::optional<U> {
284
+ using T = std::decay_t <decltype (containedValue)>;
285
+ if constexpr (std::is_same_v<T, std::runtime_error>)
286
+ {
287
+ return std::nullopt;
288
+ }
289
+ else
290
+ {
291
+ return {std::forward<T>(containedValue)};
292
+ }
382
293
},
383
- v );
294
+ std::move (eitherValueOrError) );
384
295
}
385
296
} // namespace openPMD
0 commit comments