44#include " openPMD/Mesh.hpp"
55#include " openPMD/backend/Attributable.hpp"
66#include " openPMD/backend/Attribute.hpp"
7+ #include " openPMD/backend/ScientificDefaults_auxiliary.hpp"
78
89#include < deque>
9- #include < iostream>
1010#include < optional>
1111#include < string>
1212#include < type_traits>
1313#include < variant>
14- #include < vector>
15-
16- namespace openPMD ::detail
17- {
18- template <typename F, typename SFINAE = void >
19- struct IsCallable
20- {
21- static constexpr bool value = false ;
22- using type = F;
23- };
24-
25- template <typename F>
26- struct IsCallable <F, std::void_t <decltype (std::declval<F>()())>>
27- {
28- static constexpr bool value = true ;
29- using type = decltype (std::declval<F>()());
30- };
31-
32- template <typename F>
33- constexpr bool IsCallable_v = IsCallable<F>::value;
34- template <typename F>
35- using CallResult_t = typename IsCallable<F>::type;
36- } // namespace openPMD::detail
3714
3815namespace openPMD ::internal
3916{
40- namespace
41- {
42- template <typename T>
43- inline auto write_val_to_stderr (T const &val) -> std::ostream &;
44- inline auto write_to_stderr (Attribute const &a) -> std::ostream &;
45-
46- // Helper functions used in ScientificDefaults implementations
47- inline auto setMeshGeometryFromString (Mesh &mesh, std::string val)
48- -> std::optional<error::ReadError>;
49- inline auto setMeshDataOrderFromChar (Mesh &mesh, char val)
50- -> std::optional<error::ReadError>;
51- inline auto createDefaultAxisLabels (uint64_t dimensionality)
52- -> std::vector<std::string>;
53- inline auto
54- createDefaultVector (uint64_t dimensionality, double defaultValue)
55- -> std::vector<double >;
56- } // namespace
57-
58- namespace attribute_read_result
59- {
60- struct TypeUnmatched
61- {
62- std::deque<Datatype> expectedDatatypes;
63- };
64- struct Success
65- {};
66- } // namespace attribute_read_result
6717
6818/*
6919 * The structs below implement the typical routines for parsing an attribute.
7020 * This implies validation and conversion.
7121 */
7222
73- /*
74- * General interface for attribute processing used in struct AttributeReader.
75- */
76- struct ProcessAttribute
77- {
78- virtual auto operator ()(Attributable &, char const *, Attribute const &)
79- -> std::optional<error::ReadError> = 0;
80- virtual ~ProcessAttribute () = default ;
81- };
82-
8323/*
8424 * Interface for validating an attribute whose type has already been determined.
8525 */
@@ -100,18 +40,38 @@ struct PostProcessConvertedAttributeImpl : PostProcessConvertedAttribute<T>
10040 using handler_t = std::optional<error::ReadError> (*)(RecordType &, T);
10141 handler_t reader;
10242
103- PostProcessConvertedAttributeImpl (
104- RecordType record_in, handler_t reader_in);
43+ PostProcessConvertedAttributeImpl (RecordType record_in, handler_t reader_in)
44+ : record(std::move(record_in)), reader(reader_in)
45+ {}
10546
106- auto operator ()(T val) -> std::optional<error::ReadError> override ;
47+ auto operator ()(T val) -> std::optional<error::ReadError> override
48+ {
49+ return (*reader)(record, std::move (val));
50+ }
10751};
10852
10953template <typename T, typename RecordType>
11054auto makePostProcessConvertedAttribute (
11155 RecordType &&record,
11256 std::optional<error::ReadError> (*handler)(
11357 std::remove_reference_t <RecordType> &, T))
114- -> std::shared_ptr<PostProcessConvertedAttribute<T>>;
58+ -> std::shared_ptr<PostProcessConvertedAttribute<T>>
59+ {
60+ return std::make_shared<PostProcessConvertedAttributeImpl<
61+ T,
62+ std::remove_reference_t <RecordType>>>(
63+ std::forward<RecordType>(record), handler);
64+ }
65+
66+ /*
67+ * General interface for attribute processing used in struct AttributeReader.
68+ */
69+ struct ProcessAttribute
70+ {
71+ virtual auto operator ()(Attributable &, char const *, Attribute const &)
72+ -> std::optional<error::ReadError> = 0;
73+ virtual ~ProcessAttribute () = default ;
74+ };
11575
11676/*
11777 * Validate an attribute by requiring one specific type T, and by optionally
@@ -129,12 +89,49 @@ struct RequireType : ProcessAttribute
12989 RequireType (
13090 RecordType &&record,
13191 std::optional<error::ReadError> (*handler)(
132- std::remove_reference_t <RecordType> &, T));
92+ std::remove_reference_t <RecordType> &, T))
93+ : postProcess(makePostProcessConvertedAttribute(
94+ std::forward<RecordType>(record), handler))
95+ {}
13396
134- auto operator ()(Attributable &, char const *, Attribute const &)
135- -> std::optional<error::ReadError> override ;
97+ auto operator ()(
98+ Attributable &record, char const *attrName, Attribute const &attr)
99+ -> std::optional<error::ReadError> override
100+ {
101+ auto converted_or_error = attr.getOrError <T>();
102+ return std::visit (
103+ auxiliary::overloaded{
104+ [&](T casted_val) -> std::optional<error::ReadError> {
105+ if (this ->postProcess .has_value ())
106+ {
107+ return (**this ->postProcess )(std::move (casted_val));
108+ }
109+ else
110+ {
111+ record.setAttribute <T>(attrName, std::move (casted_val));
112+ return std::nullopt ;
113+ }
114+ },
115+ [](std::runtime_error const &err)
116+ -> std::optional<error::ReadError> {
117+ std::string msg = " Expected a scalar type: " ;
118+ msg += err.what ();
119+ return error::ReadError (
120+ error::AffectedObject::Attribute,
121+ error::Reason::UnexpectedContent,
122+ std::nullopt ,
123+ std::move (msg));
124+ }},
125+ converted_or_error);
126+ }
136127};
137128
129+ // Postprocessing handlers
130+ auto setMeshGeometryFromString (Mesh &mesh, std::string val)
131+ -> std::optional<error::ReadError>;
132+ auto setMeshDataOrderFromChar (Mesh &mesh, char val)
133+ -> std::optional<error::ReadError>;
134+
138135/*
139136 * Validate an attribute by requiring a vector type, potentially wrapping
140137 * scalar values into a vector.
@@ -159,6 +156,16 @@ struct RequireScalar : ProcessAttribute
159156 -> std::optional<error::ReadError> override ;
160157};
161158
159+ namespace attribute_read_result
160+ {
161+ struct TypeUnmatched
162+ {
163+ std::deque<Datatype> expectedDatatypes;
164+ };
165+ struct Success
166+ {};
167+ } // namespace attribute_read_result
168+
162169using AttributeReadResult = std::variant<
163170 attribute_read_result::Success,
164171 attribute_read_result::TypeUnmatched,
@@ -184,12 +191,6 @@ struct AttributeReader
184191 std::deque<Datatype> unmatched_so_far) -> AttributeReadResult;
185192};
186193
187- enum class WriteOrRead : std::uint8_t
188- {
189- Write,
190- Read
191- };
192-
193194// ///////////////////
194195// ConfigAttribute //
195196// //////////////////
@@ -220,7 +221,7 @@ struct ConfigAttribute
220221 RecordType,
221222 std::conditional_t <
222223 std::is_void_v<S>,
223- detail ::CallResult_t<GetDefaultValue>,
224+ auxiliary ::CallResult_t<GetDefaultValue>,
224225 S>> setDefaultVal) -> ConfigAttribute &;
225226
226227 template <typename DefaultValue>
@@ -239,21 +240,24 @@ struct ConfigAttribute
239240
240241// below are some helpers that may be used as processing functions for
241242// attributes in withReader()
242- namespace
243- { // try converting to scalar values (e.g. when a vector of length 1 is given)
244- extern std::shared_ptr<ProcessAttribute> require_scalar;
245- // try converting to vectors (e.g. when a scalar or an array is given)
246- extern std::shared_ptr<ProcessAttribute> require_vector;
247- template <typename T, typename RecordType>
248- auto require_type (
249- std::optional<error::ReadError> (*)(
250- std::remove_reference_t <RecordType> &, T))
251- -> std::shared_ptr<ProcessAttribute>;
252- // common case: directly use setAttribute
253- template <typename T>
254- auto require_type () -> std::shared_ptr<ProcessAttribute>;
255-
256- inline auto get_float_types () -> std::deque<Datatype>;
257- inline auto get_string_types () -> std::deque<Datatype>;
258- } // namespace
243+
244+ // try converting to scalar values (e.g. when a vector of length 1 is given)
245+ extern std::shared_ptr<ProcessAttribute> require_scalar;
246+ // try converting to vectors (e.g. when a scalar or an array is given)
247+ extern std::shared_ptr<ProcessAttribute> require_vector;
248+
249+ template <typename T, typename RecordType>
250+ auto require_type (
251+ std::optional<error::ReadError> (*)(
252+ std::remove_reference_t <RecordType> &, T))
253+ -> std::shared_ptr<ProcessAttribute>;
254+ // common case: directly use setAttribute
255+ template <typename T>
256+ auto require_type () -> std::shared_ptr<ProcessAttribute>;
257+
258+ auto get_float_types () -> std::deque<Datatype>;
259+ auto get_string_types () -> std::deque<Datatype>;
260+
259261} // namespace openPMD::internal
262+
263+ #include " openPMD/backend/ScientificDefaults_impl.tpp"
0 commit comments