3434#include < string>
3535#include < type_traits>
3636#include < utility>
37+ #include < variant>
3738#include < vector>
3839
3940namespace openPMD
@@ -136,202 +137,101 @@ class Attribute
136137 std::optional<U> getOptional () const ;
137138};
138139
139- template <typename T, typename U>
140- auto doConvert (T *pv) -> U
140+ namespace detail
141141{
142- ( void )pv;
143- if constexpr ( std::is_convertible_v<T, U>)
142+ template < typename T, typename U>
143+ auto doConvert (T *pv) -> std::variant<U, std::runtime_error>
144144 {
145- return static_cast <U>(*pv);
146- }
147- else if constexpr (auxiliary::IsVector_v<T> && auxiliary::IsVector_v<U>)
148- {
149- if constexpr (std::is_convertible_v<
150- typename T::value_type,
151- typename U::value_type>)
145+ (void )pv;
146+ if constexpr (std::is_convertible_v<T, U>)
152147 {
153- U res{};
154- res.reserve (pv->size ());
155- std::copy (pv->begin (), pv->end (), std::back_inserter (res));
156- return res;
148+ return static_cast <U>(*pv);
157149 }
158- else
159- {
160- throw std::runtime_error (" getCast: no vector cast possible." );
161- }
162- }
163- // conversion cast: array to vector
164- // if a backend reports a std::array<> for something where
165- // the frontend expects a vector
166- else if constexpr (auxiliary::IsArray_v<T> && auxiliary::IsVector_v<U>)
167- {
168- if constexpr (std::is_convertible_v<
169- typename T::value_type,
170- typename U::value_type>)
171- {
172- U res{};
173- res.reserve (pv->size ());
174- std::copy (pv->begin (), pv->end (), std::back_inserter (res));
175- return res;
176- }
177- else
178- {
179- throw std::runtime_error (
180- " getCast: no array to vector conversion possible." );
181- }
182- }
183- // conversion cast: vector to array
184- // if a backend reports a std::vector<> for something where
185- // the frontend expects an array
186- else if constexpr (auxiliary::IsVector_v<T> && auxiliary::IsArray_v<U>)
187- {
188- if constexpr (std::is_convertible_v<
189- typename T::value_type,
190- typename U::value_type>)
150+ else if constexpr (auxiliary::IsVector_v<T> && auxiliary::IsVector_v<U>)
191151 {
192- U res{};
193- if (res.size () != pv->size ())
152+ if constexpr (std::is_convertible_v<
153+ typename T::value_type,
154+ typename U::value_type>)
194155 {
195- throw std::runtime_error (
196- " getCast: no vector to array conversion possible (wrong "
197- " requested array size)." );
156+ U res{};
157+ res.reserve (pv->size ());
158+ std::copy (pv->begin (), pv->end (), std::back_inserter (res));
159+ return res;
198160 }
199- for ( size_t i = 0 ; i < res. size (); ++i)
161+ else
200162 {
201- res[i] = static_cast < typename U::value_type>((*pv)[i] );
163+ return std::runtime_error ( " getCast: no vector cast possible. " );
202164 }
203- return res;
204- }
205- else
206- {
207- throw std::runtime_error (
208- " getCast: no vector to array conversion possible." );
209- }
210- }
211- // conversion cast: turn a single value into a 1-element vector
212- else if constexpr (auxiliary::IsVector_v<U>)
213- {
214- if constexpr (std::is_convertible_v<T, typename U::value_type>)
215- {
216- U res{};
217- res.reserve (1 );
218- res.push_back (static_cast <typename U::value_type>(*pv));
219- return res;
220- }
221- else
222- {
223- throw std::runtime_error (
224- " getCast: no scalar to vector conversion possible." );
225- }
226- }
227- else
228- {
229- throw std::runtime_error (" getCast: no cast possible." );
230- }
231- #if defined(__INTEL_COMPILER)
232- /*
233- * ICPC has trouble with if constexpr, thinking that return statements are
234- * missing afterwards. Deactivate the warning.
235- * Note that putting a statement here will not help to fix this since it will
236- * then complain about unreachable code.
237- * https://community.intel.com/t5/Intel-C-Compiler/quot-if-constexpr-quot-and-quot-missing-return-statement-quot-in/td-p/1154551
238- */
239- #pragma warning(disable : 1011)
240- }
241- #pragma warning(default : 1011)
242- #else
243- }
244- #endif
245-
246- template <typename T, typename U>
247- auto doConvertOptional (T *pv) -> std::optional<U>
248- {
249- (void )pv;
250- if constexpr (std::is_convertible_v<T, U>)
251- {
252- return static_cast <U>(*pv);
253- }
254- else if constexpr (auxiliary::IsVector_v<T> && auxiliary::IsVector_v<U>)
255- {
256- if constexpr (std::is_convertible_v<
257- typename T::value_type,
258- typename U::value_type>)
259- {
260- U res{};
261- res.reserve (pv->size ());
262- std::copy (pv->begin (), pv->end (), std::back_inserter (res));
263- return res;
264165 }
265- else
166+ // conversion cast: array to vector
167+ // if a backend reports a std::array<> for something where
168+ // the frontend expects a vector
169+ else if constexpr (auxiliary::IsArray_v<T> && auxiliary::IsVector_v<U>)
266170 {
267- return {};
268- }
269- }
270- // conversion cast: array to vector
271- // if a backend reports a std::array<> for something where
272- // the frontend expects a vector
273- else if constexpr (auxiliary::IsArray_v<T> && auxiliary::IsVector_v<U>)
274- {
275- if constexpr (std::is_convertible_v<
276- typename T::value_type,
277- typename U::value_type>)
278- {
279- U res{};
280- res.reserve (pv->size ());
281- std::copy (pv->begin (), pv->end (), std::back_inserter (res));
282- return res;
283- }
284- else
285- {
286- return {};
287- }
288- }
289- // conversion cast: vector to array
290- // if a backend reports a std::vector<> for something where
291- // the frontend expects an array
292- else if constexpr (auxiliary::IsVector_v<T> && auxiliary::IsArray_v<U>)
293- {
294- if constexpr (std::is_convertible_v<
295- typename T::value_type,
296- typename U::value_type>)
297- {
298- U res{};
299- if (res.size () != pv->size ())
171+ if constexpr (std::is_convertible_v<
172+ typename T::value_type,
173+ typename U::value_type>)
300174 {
301- throw std::runtime_error (
302- " getCast: no vector to array conversion possible (wrong "
303- " requested array size)." );
175+ U res{};
176+ res.reserve (pv->size ());
177+ std::copy (pv->begin (), pv->end (), std::back_inserter (res));
178+ return res;
304179 }
305- for ( size_t i = 0 ; i < res. size (); ++i)
180+ else
306181 {
307- res[i] = static_cast <typename U::value_type>((*pv)[i]);
182+ return std::runtime_error (
183+ " getCast: no array to vector conversion possible." );
308184 }
309- return res;
310185 }
311- else
186+ // conversion cast: vector to array
187+ // if a backend reports a std::vector<> for something where
188+ // the frontend expects an array
189+ else if constexpr (auxiliary::IsVector_v<T> && auxiliary::IsArray_v<U>)
312190 {
313- return {};
191+ if constexpr (std::is_convertible_v<
192+ typename T::value_type,
193+ typename U::value_type>)
194+ {
195+ U res{};
196+ if (res.size () != pv->size ())
197+ {
198+ return std::runtime_error (
199+ " getCast: no vector to array conversion possible "
200+ " (wrong "
201+ " requested array size)." );
202+ }
203+ for (size_t i = 0 ; i < res.size (); ++i)
204+ {
205+ res[i] = static_cast <typename U::value_type>((*pv)[i]);
206+ }
207+ return res;
208+ }
209+ else
210+ {
211+ return std::runtime_error (
212+ " getCast: no vector to array conversion possible." );
213+ }
314214 }
315- }
316- // conversion cast: turn a single value into a 1-element vector
317- else if constexpr (auxiliary::IsVector_v<U>)
318- {
319- if constexpr (std::is_convertible_v<T, typename U::value_type>)
215+ // conversion cast: turn a single value into a 1-element vector
216+ else if constexpr (auxiliary::IsVector_v<U>)
320217 {
321- U res{};
322- res.reserve (1 );
323- res.push_back (static_cast <typename U::value_type>(*pv));
324- return res;
218+ if constexpr (std::is_convertible_v<T, typename U::value_type>)
219+ {
220+ U res{};
221+ res.reserve (1 );
222+ res.push_back (static_cast <typename U::value_type>(*pv));
223+ return res;
224+ }
225+ else
226+ {
227+ return std::runtime_error (
228+ " getCast: no scalar to vector conversion possible." );
229+ }
325230 }
326231 else
327232 {
328- return {} ;
233+ return std::runtime_error ( " getCast: no cast possible. " ) ;
329234 }
330- }
331- else
332- {
333- return {};
334- }
335235#if defined(__INTEL_COMPILER)
336236/*
337237 * ICPC has trouble with if constexpr, thinking that return statements are
@@ -341,47 +241,58 @@ auto doConvertOptional(T *pv) -> std::optional<U>
341241 * https://community.intel.com/t5/Intel-C-Compiler/quot-if-constexpr-quot-and-quot-missing-return-statement-quot-in/td-p/1154551
342242 */
343243#pragma warning(disable : 1011)
344- }
244+ }
345245#pragma warning(default : 1011)
346246#else
347- }
247+ }
348248#endif
249+ } // namespace detail
349250
350- /* * Retrieve a stored specific Attribute and cast if convertible.
351- *
352- * @throw std::runtime_error if stored object is not static castable to U.
353- * @tparam U Type of the object to be casted to.
354- * @return Copy of the retrieved object, casted to type U.
355- */
356251template <typename U>
357- inline U getCast ( Attribute const &a)
252+ U Attribute::get () const
358253{
359- auto v = a.getResource ();
360-
254+ auto eitherValueOrError = std::visit (
255+ [](auto &&containedValue) -> std::variant<U, std::runtime_error> {
256+ using containedType = std::decay_t <decltype (containedValue)>;
257+ return detail::doConvert<containedType, U>(&containedValue);
258+ },
259+ Variant::getResource ());
361260 return std::visit (
362261 [](auto &&containedValue) -> U {
363- using containedType = std::decay_t <decltype (containedValue)>;
364- return doConvert<containedType, U>(&containedValue);
262+ using T = std::decay_t <decltype (containedValue)>;
263+ if constexpr (std::is_same_v<T, std::runtime_error>)
264+ {
265+ throw std::move (containedValue);
266+ }
267+ else
268+ {
269+ return std::move (containedValue);
270+ }
365271 },
366- v);
367- }
368-
369- template <typename U>
370- U Attribute::get () const
371- {
372- return getCast<U>(Variant::getResource ());
272+ std::move (eitherValueOrError));
373273}
374274
375275template <typename U>
376276std::optional<U> Attribute::getOptional () const
377277{
378- auto v = Variant::getResource ();
379-
380- return std::visit (
381- [](auto &&containedValue) -> U {
278+ auto eitherValueOrError = std::visit (
279+ [](auto &&containedValue) -> std::variant<U, std::runtime_error> {
382280 using containedType = std::decay_t <decltype (containedValue)>;
383- return doConvert<containedType, U>(&containedValue);
281+ return detail::doConvert<containedType, U>(&containedValue);
282+ },
283+ Variant::getResource ());
284+ return std::visit (
285+ [](auto &&containedValue) -> std::optional<U> {
286+ using T = std::decay_t <decltype (containedValue)>;
287+ if constexpr (std::is_same_v<T, std::runtime_error>)
288+ {
289+ return std::nullopt ;
290+ }
291+ else
292+ {
293+ return {std::move (containedValue)};
294+ }
384295 },
385- v );
296+ std::move (eitherValueOrError) );
386297}
387298} // namespace openPMD
0 commit comments