23 #include "openPMD/Datatype.hpp"
24 #include "openPMD/auxiliary/TypeTraits.hpp"
25 #include "openPMD/auxiliary/Variant.hpp"
29 #include "openPMD/DatatypeMacros.hpp"
39 #include <type_traits>
71 #define OPENPMD_ATTRIBUTE_CONSTRUCTOR_FROM_VARIANT(TYPE) \
72 Attribute(TYPE val) : Variant(resource(std::move(val))) \
75 OPENPMD_FOREACH_DATATYPE(OPENPMD_ATTRIBUTE_CONSTRUCTOR_FROM_VARIANT)
77 #undef OPENPMD_ATTRIBUTE_CONSTRUCTOR_FROM_VARIANT
102 template <
typename U>
108 template <
typename T,
typename U>
109 auto doConvert(T
const *pv) -> std::variant<U, std::runtime_error>
112 if constexpr (std::is_convertible_v<T, U>)
114 return {
static_cast<U
>(*pv)};
117 std::is_same_v<T, std::string> && auxiliary::IsChar_v<U>)
121 return static_cast<U
>(pv->at(0));
126 std::runtime_error(
"getCast: cast from string to char only "
127 "possible if string has length 1.")};
131 auxiliary::IsChar_v<T> && std::is_same_v<U, std::string>)
133 return std::string(1, *pv);
135 else if constexpr (auxiliary::IsVector_v<T> && auxiliary::IsVector_v<U>)
138 res.reserve(pv->size());
139 if constexpr (std::is_convertible_v<
140 typename T::value_type,
141 typename U::value_type>)
143 std::copy(pv->begin(), pv->end(), std::back_inserter(res));
149 for (
auto const &val : *pv)
151 auto conv = doConvert<
152 typename T::value_type,
153 typename U::value_type>(&val);
155 std::get_if<typename U::value_type>(&conv);
158 res.push_back(std::move(*conv_val));
162 auto exception = std::get<std::runtime_error>(conv);
163 return {std::runtime_error(
165 "getCast: no vector cast possible, recursive "
176 else if constexpr (auxiliary::IsArray_v<T> && auxiliary::IsVector_v<U>)
179 res.reserve(pv->size());
180 if constexpr (std::is_convertible_v<
181 typename T::value_type,
182 typename U::value_type>)
184 std::copy(pv->begin(), pv->end(), std::back_inserter(res));
190 for (
auto const &val : *pv)
192 auto conv = doConvert<
193 typename T::value_type,
194 typename U::value_type>(&val);
196 std::get_if<typename U::value_type>(&conv);
199 res.push_back(std::move(*conv_val));
203 auto exception = std::get<std::runtime_error>(conv);
204 return {std::runtime_error(
206 "getCast: no array to vector conversion "
207 "possible, recursive error: ") +
217 else if constexpr (auxiliary::IsVector_v<T> && auxiliary::IsArray_v<U>)
220 if constexpr (std::is_convertible_v<
221 typename T::value_type,
222 typename U::value_type>)
224 if (res.size() != pv->size())
226 return std::runtime_error(
227 "getCast: no vector to array conversion possible "
229 "requested array size).");
231 for (
size_t i = 0; i < res.size(); ++i)
233 res[i] =
static_cast<typename U::value_type
>((*pv)[i]);
240 for (
size_t i = 0; i <= res.size(); ++i)
242 auto const &val = (*pv)[i];
243 auto conv = doConvert<
244 typename T::value_type,
245 typename U::value_type>(&val);
247 std::get_if<typename U::value_type>(&conv);
250 res[i] = std::move(*conv_val);
254 auto exception = std::get<std::runtime_error>(conv);
255 return {std::runtime_error(
257 "getCast: no vector to array conversion "
258 "possible, recursive error: ") +
266 else if constexpr (auxiliary::IsVector_v<U>)
270 if constexpr (std::is_convertible_v<T, typename U::value_type>)
272 res.push_back(
static_cast<typename U::value_type
>(*pv));
278 auto conv = doConvert<T, typename U::value_type>(pv);
279 if (
auto conv_val = std::get_if<typename U::value_type>(&conv);
282 res.push_back(std::move(*conv_val));
287 auto exception = std::get<std::runtime_error>(conv);
288 return {std::runtime_error(
289 std::string(
"getCast: no scalar to vector conversion "
290 "possible, recursive error: ") +
297 return {std::runtime_error(
"getCast: no cast possible.")};
299 #if defined(__INTEL_COMPILER)
307 #pragma warning(disable : 1011)
309 #pragma warning(default : 1011)
315 template <
typename U>
316 U Attribute::get()
const
318 auto eitherValueOrError = std::visit(
319 [](
auto &&containedValue) -> std::variant<U, std::runtime_error> {
320 using containedType = std::decay_t<decltype(containedValue)>;
321 return detail::doConvert<containedType, U>(&containedValue);
323 Variant::getResource());
325 [](
auto &&containedValue) -> U {
326 using T = std::decay_t<decltype(containedValue)>;
327 if constexpr (std::is_same_v<T, std::runtime_error>)
329 throw std::move(containedValue);
333 return std::move(containedValue);
336 std::move(eitherValueOrError));
339 template <
typename U>
340 std::optional<U> Attribute::getOptional()
const
342 auto eitherValueOrError = std::visit(
343 [](
auto &&containedValue) -> std::variant<U, std::runtime_error> {
344 using containedType = std::decay_t<decltype(containedValue)>;
345 return detail::doConvert<containedType, U>(&containedValue);
347 Variant::getResource());
349 [](
auto &&containedValue) -> std::optional<U> {
350 using T = std::decay_t<decltype(containedValue)>;
351 if constexpr (std::is_same_v<T, std::runtime_error>)
357 return {std::move(containedValue)};
360 std::move(eitherValueOrError));
364 #include "openPMD/UndefDatatypeMacros.hpp"
Variant datatype supporting at least all formats for attributes specified in the openPMD standard.
Definition: Attribute.hpp:56
U get() const
Retrieve a stored specific Attribute and cast if convertible.
Definition: Attribute.hpp:316
std::optional< U > getOptional() const
Retrieve a stored specific Attribute and cast if convertible.
Definition: Attribute.hpp:340
Generic object to store a set of datatypes in without losing type safety.
Definition: Variant.hpp:40
Variant(resource r)
Construct a lightweight wrapper around a generic object that indicates the concrete datatype of the s...
Definition: Variant.hpp:54
Public definitions of openPMD-api.
Definition: Date.cpp:29