11#pragma once
22
3- #include " openPMD/Datatype.hpp"
43#include " openPMD/Error.hpp"
5- #include " openPMD/IO/AbstractIOHandler.hpp"
6- #include " openPMD/Mesh.hpp"
7- #include " openPMD/auxiliary/StringManip.hpp"
4+ #include " openPMD/backend/Attributable.hpp"
85#include " openPMD/backend/Attribute.hpp"
9- #include " openPMD/backend/Variant_internal.hpp"
106
11- #include < functional >
7+ #include < deque >
128#include < iostream>
139#include < type_traits>
1410#include < variant>
@@ -40,30 +36,8 @@ namespace openPMD::internal
4036namespace
4137{
4238 template <typename T>
43- auto write_val_to_stderr (T const &val) -> std::ostream &
44- {
45- if constexpr (auxiliary::IsVector_v<T> || auxiliary::IsArray_v<T>)
46- {
47- auxiliary::write_vec_to_stream (std::cerr, val);
48- }
49- else if constexpr (std::is_same_v<T, unit_representations::AsMap>)
50- {
51- std::cerr << " Unit_Map" ;
52- }
53- else
54- {
55- std::cerr << val;
56- }
57- return std::cerr;
58- }
59- auto write_to_stderr (Attribute const &a) -> std::ostream &
60- {
61- std::visit (
62- [](auto const &val) { write_val_to_stderr (val); },
63- a.getVariant <attribute_types>());
64- return std::cerr;
65- }
66-
39+ auto write_val_to_stderr (T const &val) -> std::ostream &;
40+ auto write_to_stderr (Attribute const &a) -> std::ostream &;
6741} // namespace
6842
6943namespace attribute_read_result
@@ -81,49 +55,24 @@ using AttributeReadResult = std::variant<
8155 attribute_read_result::TypeUnmatched,
8256 error::ReadError>;
8357
84- struct NewAttributeReader
58+ struct AttributeReader
8559{
86- std::deque<Datatype> eligibleDatatypes;
8760 using process_attribute_type =
8861 std::function<std::optional<error::ReadError>(
8962 Attributable &, char const *, Attribute const &)>;
63+
64+ std::deque<Datatype> eligibleDatatypes;
9065 std::optional<process_attribute_type> processAttribute;
9166
92- NewAttributeReader (
67+ AttributeReader (
9368 std::deque<Datatype> eligibleDatatypes_in,
94- std::optional<process_attribute_type> processAttribute_in)
95- : eligibleDatatypes(std::move(eligibleDatatypes_in))
96- , processAttribute(std::move(processAttribute_in))
97- {}
69+ std::optional<process_attribute_type> processAttribute_in);
9870
9971 auto operator ()(
10072 Attributable &record,
10173 char const *attrName,
10274 Attribute const &a,
103- std::deque<Datatype> unmatched_so_far) -> AttributeReadResult
104- {
105- if (std::find (
106- eligibleDatatypes.begin (), eligibleDatatypes.end (), a.dtype ) ==
107- eligibleDatatypes.end ())
108- {
109- auto res = attribute_read_result::TypeUnmatched{
110- std::move (unmatched_so_far)};
111- for (auto dt : this ->eligibleDatatypes )
112- {
113- res.expectedDatatypes .push_back (dt);
114- }
115- return res;
116- }
117- if (processAttribute.has_value ())
118- {
119- auto maybe_error = (*processAttribute)(record, attrName, a);
120- if (maybe_error.has_value ())
121- {
122- return *maybe_error;
123- }
124- }
125- return attribute_read_result::Success{};
126- }
75+ std::deque<Datatype> unmatched_so_far) -> AttributeReadResult;
12776};
12877
12978enum class WriteOrRead : std::uint8_t
@@ -140,13 +89,13 @@ struct ConfigAttribute
14089{
14190 Attributable &child;
14291 char const *attrName;
143- std::function<void (Attributable &)> initDefaultAttribute;
92+ std::optional<std:: function<void (Attributable &)> > initDefaultAttribute;
14493 // processed "from left to right"
145- std::deque<NewAttributeReader> attributeReaders;
94+ std::deque<AttributeReader> attributeReaders;
95+
96+ using process_attribute_type = AttributeReader::process_attribute_type;
14697
147- ConfigAttribute (Attributable &child_in, char const *attrName_in)
148- : child(child_in), attrName(attrName_in)
149- {}
98+ ConfigAttribute (Attributable &child_in, char const *attrName_in);
15099
151100 ConfigAttribute (ConfigAttribute const &) = delete ;
152101 ConfigAttribute (ConfigAttribute &&) = delete ;
@@ -161,141 +110,37 @@ struct ConfigAttribute
161110 std::conditional_t <
162111 std::is_void_v<S>,
163112 detail::CallResult_t<GetDefaultValue>,
164- S>)) -> ConfigAttribute &
165- {
166- initDefaultAttribute = [getDefaultVal_lambda = std::move (getDefaultVal),
167- setDefaultVal](Attributable &attr) {
168- RecordType *record = dynamic_cast <RecordType *>(&attr);
169- if (!record)
170- {
171- throw error::Internal (" dynamic cast failure" );
172- }
173- if constexpr (detail::IsCallable_v<GetDefaultValue>)
174- {
175- ((*record).*setDefaultVal)(getDefaultVal_lambda ());
176- }
177- else
178- {
179- ((*record).*setDefaultVal)(std::move (getDefaultVal_lambda));
180- }
181- };
182- return *this ;
183- }
113+ S>)) -> ConfigAttribute &;
184114
185115 template <typename DefaultValue>
186116 [[nodiscard]] auto withGenericSetter (DefaultValue &&defaultVal)
187- -> ConfigAttribute &
188- {
189- initDefaultAttribute = [this ,
190- defaultVal_lambda =
191- std::forward<DefaultValue &&>(defaultVal)](
192- Attributable &attr) {
193- attr.setAttribute (this ->attrName , std::move (defaultVal_lambda));
194- };
195- return *this ;
196- }
117+ -> ConfigAttribute &;
197118
198119 [[nodiscard]] auto withReader (
199120 std::deque<Datatype> eligibleDatatypes,
200- std::optional<NewAttributeReader::process_attribute_type>
201- processAttribute = std::nullopt ) -> ConfigAttribute &
202- {
203- this ->attributeReaders .emplace_back (
204- std::move (eligibleDatatypes), std::move (processAttribute));
205- return *this ;
206- }
121+ std::optional<process_attribute_type> processAttribute = std::nullopt )
122+ -> ConfigAttribute &;
207123
208- void write ()
209- {
210- if (this ->child .containsAttribute (this ->attrName ))
211- {
212- return ;
213- }
214- this ->initDefaultAttribute (this ->child );
215- }
216-
217- void read ()
218- {
219- if (attributeReaders.empty ())
220- {
221- // No readers emplaced for this attribute
222- return ;
223- }
224- AttributeReadResult res = attribute_read_result::TypeUnmatched{};
225- Parameter<Operation::READ_ATT> aRead;
226- aRead.name = this ->attrName ;
227- auto IOHandler = this ->child .IOHandler ();
228- IOHandler->enqueue (IOTask (&this ->child , aRead));
229- try
230- {
231- IOHandler->flush (defaultFlushParams);
232- }
233- catch (error::ReadError const &e)
234- {
235- std::cerr << " Could not read expected attribute '" << this ->attrName
236- << " ' in '" << this ->child .myPath ().openPMDPath ()
237- << " . Will initialize it with a default value. "
238- " Original error: "
239- << e.what () << std::endl;
240- this ->initDefaultAttribute (this ->child );
241- return ;
242- }
243-
244- Attribute attribute (Attribute::from_any, std::move (*aRead.m_resource ));
245- for (auto &attributeReader : attributeReaders)
246- {
124+ void write ();
125+ void read ();
126+ void operator ()(WriteOrRead wor);
127+ };
247128
248- if (auto *not_matched =
249- std::get_if<attribute_read_result::TypeUnmatched>(&res))
250- {
251- res = attributeReader (
252- this ->child ,
253- this ->attrName ,
254- attribute,
255- std::move (not_matched->expectedDatatypes ));
256- }
257- else
258- {
259- break ;
260- }
261- }
262- auto dt = attribute.dtype ;
263- std::visit (
264- auxiliary::overloaded{
265- [&](attribute_read_result::TypeUnmatched &&type_unmatched) {
266- std::cerr << " Unexpected type '" << dt
267- << " ' for attribute '" << this ->attrName
268- << " ' in '" << this ->child .myPath ().openPMDPath ()
269- << " ' with value '" ;
270- write_to_stderr (attribute) << " '. Expected one of " ;
271- auxiliary::write_vec_to_stream (
272- std::cerr, type_unmatched.expectedDatatypes )
273- << " or convertible to such a type." << std::endl;
274- },
275- [&](error::ReadError const &err) {
276- std::cerr << " Unexpected error while trying to read "
277- " attribute '"
278- << this ->attrName << " ' in '"
279- << this ->child .myPath ().openPMDPath ()
280- << " '' with value '" ;
281- write_to_stderr (attribute)
282- << " ': " << err.what () << std::endl;
283- },
284- [](attribute_read_result::Success) { /* no-op */ }},
285- std::move (res));
286- }
129+ // below are some helpers that may be used as processing functions for
130+ // attributes in withReader()
131+ namespace
132+ { // try converting to scalar values (e.g. when a vector of length 1 is given)
133+ extern ConfigAttribute::process_attribute_type require_scalar;
134+ // try converting to vectors (e.g. when a scalar or an array is given)
135+ extern ConfigAttribute::process_attribute_type require_vector;
136+ // F: T -> void
137+ template <typename T, typename F>
138+ auto require_type (F &&) -> ConfigAttribute::process_attribute_type;
139+ // common case: directly use setAttribute
140+ template <typename T>
141+ auto require_type () -> ConfigAttribute::process_attribute_type;
287142
288- void operator ()(WriteOrRead wor)
289- {
290- switch (wor)
291- {
292- case WriteOrRead::Write:
293- write ();
294- break ;
295- case WriteOrRead::Read:
296- read ();
297- break ;
298- }
299- }
300- };
143+ auto get_float_types () -> std::deque<Datatype>;
144+ auto get_string_types () -> std::deque<Datatype>;
145+ } // namespace
301146} // namespace openPMD::internal
0 commit comments