@@ -50,23 +50,107 @@ namespace attribute_read_result
5050 {};
5151} // namespace attribute_read_result
5252
53+ struct ProcessAttribute
54+ {
55+ virtual auto operator ()(Attributable &, char const *, Attribute const &)
56+ -> std::optional<error::ReadError> = 0;
57+ virtual ~ProcessAttribute () = default ;
58+ };
59+
60+ template <typename T>
61+ struct PostProcessConvertedAttribute
62+ {
63+ virtual auto operator ()(T val) -> std::optional<error::ReadError> = 0;
64+ virtual ~PostProcessConvertedAttribute () = default ;
65+ };
66+
67+ struct constructor_tag
68+ {};
69+ static constexpr constructor_tag constructor_tag_v = {};
70+
71+ template <typename T, typename Functor>
72+ struct PostProcessConvertedAttributeImpl : PostProcessConvertedAttribute<T>
73+ {
74+ template <typename T_, typename Functor_>
75+ friend auto makePostProcessConvertedAttribute (Functor_ &&fun)
76+ -> std::shared_ptr<PostProcessConvertedAttribute<T_>>;
77+
78+ template <typename Fun>
79+ PostProcessConvertedAttributeImpl (constructor_tag, Fun &&f)
80+ : fun{std::forward<Fun>(f)}
81+ {}
82+
83+ Functor fun;
84+ auto operator ()(T val) -> std::optional<error::ReadError> override
85+ {
86+ return fun (std::move (val));
87+ }
88+ };
89+
90+ template <typename T, typename Fun>
91+ auto makePostProcessConvertedAttribute (Fun &&fun)
92+ -> std::shared_ptr<PostProcessConvertedAttribute<T>>
93+ {
94+ auto functor = [fun_lambda = std::forward<Fun>(fun)](
95+ T val) -> std::optional<error::ReadError> {
96+ if constexpr (!std::is_void_v<std::invoke_result<Fun &&, T>>)
97+ {
98+ std::move (fun_lambda)(std::move (val));
99+ return std::nullopt ;
100+ }
101+ else
102+ {
103+ return std::move (fun_lambda)(std::move (val));
104+ }
105+ };
106+ return std::make_shared<
107+ PostProcessConvertedAttributeImpl<T, decltype (functor)>>(
108+ constructor_tag_v, std::move (functor));
109+ }
110+
111+ template <typename T>
112+ struct RequireType : ProcessAttribute
113+ {
114+ std::optional<std::shared_ptr<PostProcessConvertedAttribute<T>>>
115+ postProcess;
116+
117+ explicit RequireType () = default;
118+
119+ template <typename Functor>
120+ RequireType (constructor_tag, Functor &&fun)
121+ : postProcess(
122+ makePostProcessConvertedAttribute<T>(std::forward<Functor>(fun)))
123+ {}
124+
125+ auto operator ()(Attributable &, char const *, Attribute const &)
126+ -> std::optional<error::ReadError> override ;
127+ };
128+
129+ struct RequireVector : ProcessAttribute
130+ {
131+ auto operator ()(Attributable &, char const *, Attribute const &)
132+ -> std::optional<error::ReadError> override ;
133+ };
134+
135+ struct RequireScalar : ProcessAttribute
136+ {
137+ auto operator ()(Attributable &, char const *, Attribute const &)
138+ -> std::optional<error::ReadError> override ;
139+ };
140+
53141using AttributeReadResult = std::variant<
54142 attribute_read_result::Success,
55143 attribute_read_result::TypeUnmatched,
56144 error::ReadError>;
57145
58146struct AttributeReader
59147{
60- using process_attribute_type =
61- std::function<std::optional<error::ReadError>(
62- Attributable &, char const *, Attribute const &)>;
63-
64148 std::deque<Datatype> eligibleDatatypes;
65- std::optional<process_attribute_type > processAttribute;
149+ std::optional<std::shared_ptr<ProcessAttribute> > processAttribute;
66150
67151 AttributeReader (
68152 std::deque<Datatype> eligibleDatatypes_in,
69- std::optional<process_attribute_type > processAttribute_in);
153+ std::optional<std::shared_ptr<ProcessAttribute> > processAttribute_in);
70154
71155 auto operator ()(
72156 Attributable &record,
@@ -95,7 +179,6 @@ struct ConfigAttribute
95179
96180 template <typename RecordType, typename ValueType>
97181 using set_default_val_t = RecordType &(RecordType::*)(ValueType);
98- using process_attribute_type = AttributeReader::process_attribute_type;
99182
100183 ConfigAttribute (Attributable &child_in, char const *attrName_in);
101184
@@ -121,8 +204,8 @@ struct ConfigAttribute
121204
122205 [[nodiscard]] auto withReader (
123206 std::deque<Datatype> eligibleDatatypes,
124- std::optional<process_attribute_type> processAttribute = std:: nullopt )
125- -> ConfigAttribute &;
207+ std::optional<std::shared_ptr<ProcessAttribute>> processAttribute =
208+ std:: nullopt ) -> ConfigAttribute &;
126209
127210 void write ();
128211 void read ();
@@ -133,18 +216,14 @@ struct ConfigAttribute
133216// attributes in withReader()
134217namespace
135218{ // try converting to scalar values (e.g. when a vector of length 1 is given)
136- extern ConfigAttribute::process_attribute_type require_scalar;
219+ extern std::shared_ptr<ProcessAttribute> require_scalar;
137220 // try converting to vectors (e.g. when a scalar or an array is given)
138- extern ConfigAttribute::process_attribute_type require_vector;
139- template <typename T>
140- auto require_type (std::function<std::optional<error::ReadError>(T)>)
141- -> ConfigAttribute::process_attribute_type;
142- template <typename T>
143- auto require_type_noerr (std::function<void (T)>)
144- -> ConfigAttribute::process_attribute_type;
221+ extern std::shared_ptr<ProcessAttribute> require_vector;
222+ template <typename T, typename Fun>
223+ auto require_type (Fun &&) -> std::shared_ptr<ProcessAttribute>;
145224 // common case: directly use setAttribute
146225 template <typename T>
147- auto require_type () -> ConfigAttribute::process_attribute_type ;
226+ auto require_type () -> std::shared_ptr<ProcessAttribute> ;
148227
149228 auto get_float_types () -> std::deque<Datatype>;
150229 auto get_string_types () -> std::deque<Datatype>;
0 commit comments