2929#include < complex>
3030#include < cstdint>
3131#include < iterator>
32+ #include < optional>
3233#include < stdexcept>
3334#include < string>
3435#include < type_traits>
@@ -117,6 +118,9 @@ class Attribute
117118 */
118119 template <typename U>
119120 U get () const ;
121+
122+ template <typename U>
123+ std::optional<U> getOptional () const ;
120124};
121125
122126template <typename T, typename U>
@@ -226,6 +230,110 @@ auto doConvert(T *pv) -> U
226230}
227231#endif
228232
233+ template <typename T, typename U>
234+ auto doConvertOptional (T *pv) -> std::optional<U>
235+ {
236+ (void )pv;
237+ if constexpr (std::is_convertible_v<T, U>)
238+ {
239+ return static_cast <U>(*pv);
240+ }
241+ else if constexpr (auxiliary::IsVector_v<T> && auxiliary::IsVector_v<U>)
242+ {
243+ if constexpr (std::is_convertible_v<
244+ typename T::value_type,
245+ typename U::value_type>)
246+ {
247+ U res{};
248+ res.reserve (pv->size ());
249+ std::copy (pv->begin (), pv->end (), std::back_inserter (res));
250+ return res;
251+ }
252+ else
253+ {
254+ return {};
255+ }
256+ }
257+ // conversion cast: array to vector
258+ // if a backend reports a std::array<> for something where
259+ // the frontend expects a vector
260+ else if constexpr (auxiliary::IsArray_v<T> && auxiliary::IsVector_v<U>)
261+ {
262+ if constexpr (std::is_convertible_v<
263+ typename T::value_type,
264+ typename U::value_type>)
265+ {
266+ U res{};
267+ res.reserve (pv->size ());
268+ std::copy (pv->begin (), pv->end (), std::back_inserter (res));
269+ return res;
270+ }
271+ else
272+ {
273+ return {};
274+ }
275+ }
276+ // conversion cast: vector to array
277+ // if a backend reports a std::vector<> for something where
278+ // the frontend expects an array
279+ else if constexpr (auxiliary::IsVector_v<T> && auxiliary::IsArray_v<U>)
280+ {
281+ if constexpr (std::is_convertible_v<
282+ typename T::value_type,
283+ typename U::value_type>)
284+ {
285+ U res{};
286+ if (res.size () != pv->size ())
287+ {
288+ throw std::runtime_error (
289+ " getCast: no vector to array conversion possible (wrong "
290+ " requested array size)." );
291+ }
292+ for (size_t i = 0 ; i < res.size (); ++i)
293+ {
294+ res[i] = static_cast <typename U::value_type>((*pv)[i]);
295+ }
296+ return res;
297+ }
298+ else
299+ {
300+ return {};
301+ }
302+ }
303+ // conversion cast: turn a single value into a 1-element vector
304+ else if constexpr (auxiliary::IsVector_v<U>)
305+ {
306+ if constexpr (std::is_convertible_v<T, typename U::value_type>)
307+ {
308+ U res{};
309+ res.reserve (1 );
310+ res.push_back (static_cast <typename U::value_type>(*pv));
311+ return res;
312+ }
313+ else
314+ {
315+ return {};
316+ }
317+ }
318+ else
319+ {
320+ return {};
321+ }
322+ #if defined(__INTEL_COMPILER)
323+ /*
324+ * ICPC has trouble with if constexpr, thinking that return statements are
325+ * missing afterwards. Deactivate the warning.
326+ * Note that putting a statement here will not help to fix this since it will
327+ * then complain about unreachable code.
328+ * https://community.intel.com/t5/Intel-C-Compiler/quot-if-constexpr-quot-and-quot-missing-return-statement-quot-in/td-p/1154551
329+ */
330+ #pragma warning(disable : 1011)
331+ }
332+ #pragma warning(default : 1011)
333+ #else
334+ }
335+ #endif
336+
229337/* * Retrieve a stored specific Attribute and cast if convertible.
230338 *
231339 * @throw std::runtime_error if stored object is not static castable to U.
@@ -245,10 +353,28 @@ inline U getCast(Attribute const &a)
245353 v);
246354}
247355
356+ template <typename U>
357+ inline std::optional<U> getCastOptional (Attribute const &a)
358+ {
359+ auto v = a.getResource ();
360+
361+ return std::visit (
362+ [](auto &&containedValue) -> U {
363+ using containedType = std::decay_t <decltype (containedValue)>;
364+ return doConvert<containedType, U>(&containedValue);
365+ },
366+ v);
367+ }
368+
248369template <typename U>
249370U Attribute::get () const
250371{
251372 return getCast<U>(Variant::getResource ());
252373}
253374
375+ template <typename U>
376+ std::optional<U> Attribute::getOptional () const
377+ {
378+ return getCastOptional<U>(Variant::getResource ());
379+ }
254380} // namespace openPMD
0 commit comments