Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #pragma once
11 :
12 : #include <vector>
13 : #include <map>
14 : #include <string>
15 :
16 : #include "hit/hit.h"
17 :
18 : #include "MooseUtils.h"
19 :
20 : #define combineParamNames1(X, Y) X##Y
21 : #define combineParamNames(X, Y) combineParamNames1(X, Y)
22 :
23 : /// Macro for registering a scalar parameter using the setScalarValue helper
24 : #define registerScalarParameter(type) \
25 : static char combineParamNames(dummyvar_reg_param, __COUNTER__) = \
26 : Moose::ParameterRegistry::get().add<type>( \
27 : [](type & value, const hit::Field & field) \
28 : { Moose::ParameterRegistration::setScalarValue<type>(value, field); })
29 : /// Macro for registering a vector parameter using the setVectorValue helper
30 : #define registerVectorParameter(type) \
31 : static char combineParamNames(dummyvar_reg_param, __COUNTER__) = \
32 : Moose::ParameterRegistry::get().add<std::vector<type>>( \
33 : [](std::vector<type> & value, const hit::Field & field) \
34 : { Moose::ParameterRegistration::setVectorValue<type>(value, field); })
35 : /// Macro for registering a double vector parameter using the setDoubleVectorValue helper
36 : #define registerDoubleVectorParameter(type) \
37 : static char combineParamNames(dummyvar_reg_param, __COUNTER__) = \
38 : Moose::ParameterRegistry::get().add<std::vector<std::vector<type>>>( \
39 : [](std::vector<std::vector<type>> & value, const hit::Field & field) \
40 : { Moose::ParameterRegistration::setDoubleVectorValue<type>(value, field); })
41 : /// Macro for registering a double vector parameter using the setTripleVectorValue helper
42 : #define registerTripleVectorParameter(type) \
43 : static char combineParamNames(dummyvar_reg_param, __COUNTER__) = \
44 : Moose::ParameterRegistry::get().add<std::vector<std::vector<std::vector<type>>>>( \
45 : [](std::vector<std::vector<std::vector<type>>> & value, const hit::Field & field) \
46 : { Moose::ParameterRegistration::setTripleVectorValue<type>(value, field); })
47 : /// Macro for registering a scalar, vector, double vector, and triple vector parameter
48 : #define registerParameter(type) \
49 : registerScalarParameter(type); \
50 : registerVectorParameter(type); \
51 : registerDoubleVectorParameter(type); \
52 : registerTripleVectorParameter(type)
53 : /// Macro for registering a map parameter of the given type using the setMapValue helper
54 : #define registerMapParameter(key_type, value_type) \
55 : static char combineParamNames(dummyvar_reg_param, __COUNTER__) = \
56 : Moose::ParameterRegistry::get().add<std::map<key_type, value_type>>( \
57 : [](std::map<key_type, value_type> & value, const hit::Field & field) \
58 : { Moose::ParameterRegistration::setMapValue<key_type, value_type>(value, field); })
59 :
60 : namespace Moose::ParameterRegistration
61 : {
62 :
63 : /**
64 : * Converts the given field node into a scalar of the given type.
65 : */
66 : template <class T>
67 : void setScalarValue(T & value, const hit::Field & field);
68 :
69 : /**
70 : * Converts the given field node into a vector of the given type.
71 : */
72 : template <class T>
73 : void setVectorValue(std::vector<T> & value, const hit::Field & field);
74 :
75 : /**
76 : * Converts the given field node into a vector-of-vectors of the given type.
77 : */
78 : template <class T>
79 : void setDoubleVectorValue(std::vector<std::vector<T>> & value, const hit::Field & field);
80 :
81 : /**
82 : * Converts the given field node into a triple-indexed vector of the given type.
83 : */
84 : template <class T>
85 : void setTripleVectorValue(std::vector<std::vector<std::vector<T>>> & value,
86 : const hit::Field & field);
87 :
88 : /**
89 : * Converts the given field node into a map with the given types.
90 : */
91 : template <class Key, class Value>
92 : void setMapValue(std::map<Key, Value> & value, const hit::Field & field);
93 :
94 : /// setScalarValue specialiation for bool
95 : template <>
96 : void setScalarValue(bool & value, const hit::Field & field);
97 :
98 : template <class T>
99 : void
100 1546807 : setScalarValue(T & value, const hit::Field & field)
101 : {
102 3093614 : const auto strval = field.param<std::string>();
103 : if constexpr (std::is_base_of_v<std::string, T>)
104 : {
105 1117231 : value = strval;
106 : }
107 : else
108 : {
109 429576 : if (!MooseUtils::convert<T>(strval, value, false))
110 10 : throw std::invalid_argument("invalid syntax for " + MooseUtils::prettyCppType<T>() +
111 : " parameter: " + field.fullpath() + "='" + strval + "'");
112 : }
113 1546807 : }
114 :
115 : template <class T>
116 : void
117 442212 : setVectorValue(std::vector<T> & value, const hit::Field & field)
118 : {
119 442212 : value.clear();
120 884424 : const auto base_values = field.param<std::vector<std::string>>();
121 : if constexpr (std::is_base_of_v<std::string, T>)
122 : {
123 372718 : std::copy(base_values.begin(), base_values.end(), std::back_inserter(value));
124 : }
125 : else
126 : {
127 69494 : value.resize(base_values.size());
128 216786 : for (const auto i : index_range(base_values))
129 : {
130 : if constexpr (std::is_same_v<bool, T>)
131 : {
132 2887 : if (base_values[i] == "1")
133 : {
134 40 : value[i] = true;
135 40 : continue;
136 : }
137 2847 : else if (base_values[i] == "0")
138 : {
139 40 : value[i] = false;
140 40 : continue;
141 : }
142 2807 : else if (bool bool_val; hit::toBool(base_values[i], &bool_val))
143 : {
144 2607 : value[i] = bool_val;
145 2607 : continue;
146 : }
147 : }
148 : else
149 : {
150 144607 : if (MooseUtils::convert<T>(base_values[i], value[i], false))
151 144605 : continue;
152 : }
153 :
154 404 : throw std::invalid_argument("invalid syntax for " + MooseUtils::prettyCppType<T>() +
155 : " vector parameter: " + field.fullpath() + "[" +
156 202 : std::to_string(i) + "]='" + base_values[i] + "'");
157 : }
158 : }
159 442212 : }
160 :
161 : template <class T>
162 : void
163 5797 : setDoubleVectorValue(std::vector<std::vector<T>> & value, const hit::Field & field)
164 : {
165 5797 : value.clear();
166 17391 : const auto strval = MooseUtils::trim(field.param<std::string>());
167 5797 : if (strval.empty())
168 30 : return;
169 :
170 : // split vector on ";" (the substrings are _not_ of type T yet)
171 : // The zero length here is intentional, as we want something like:
172 : // "abc; 123;" -> ["abc", "123", ""]
173 11534 : const auto tokens = MooseUtils::split(strval, ";");
174 :
175 5767 : value.resize(tokens.size());
176 16139 : for (const auto i : index_range(tokens))
177 : {
178 20744 : const auto token = MooseUtils::trim(tokens[i]);
179 20744 : if (!MooseUtils::tokenizeAndConvert<T>(token, value[i]))
180 2 : throw std::invalid_argument("invalid syntax for " + MooseUtils::prettyCppType<T>() +
181 : " double vector parameter: " + field.fullpath() + "[" +
182 : std::to_string(i) + "]='" + token + "'");
183 : }
184 5799 : }
185 :
186 : template <class T>
187 : void
188 641 : setTripleVectorValue(std::vector<std::vector<std::vector<T>>> & value, const hit::Field & field)
189 : {
190 641 : value.clear();
191 1282 : const auto value_string = field.param<std::string>();
192 641 : if (value_string.find_first_not_of(' ', 0) == std::string::npos)
193 2 : return;
194 :
195 : // Add a space between neighboring delim's, before the first delim if nothing is ahead of it, and
196 : // after the last delim if nothing is behind it.
197 639 : std::string buffer;
198 639 : buffer.push_back(value_string[0]);
199 639 : if (buffer[0] == '|' || buffer[0] == ';')
200 39 : buffer = ' ' + buffer;
201 78681 : for (std::string::size_type i = 1; i < value_string.size(); i++)
202 : {
203 78042 : const auto val = value_string[i];
204 78042 : const auto last_val = value_string[i - 1];
205 78042 : if ((last_val == '|' || last_val == ';') && (val == '|' || val == ';'))
206 91 : buffer.push_back(' ');
207 78042 : buffer.push_back(val);
208 : }
209 639 : if (buffer.back() == '|' || buffer.back() == ';')
210 17 : buffer.push_back(' ');
211 :
212 : // split vector at delim | to get a series of 2D subvectors
213 639 : std::vector<std::string> outer_tokens;
214 639 : MooseUtils::tokenize(buffer, outer_tokens, 1, "|");
215 639 : value.resize(outer_tokens.size());
216 3515 : for (const auto i : index_range(outer_tokens))
217 : {
218 1480 : const auto & inner_token = outer_tokens[i];
219 1480 : auto & inner_value = value[i];
220 :
221 : // Identify empty subvector first
222 1480 : if (inner_token.find_first_not_of(' ', 0) == std::string::npos)
223 : {
224 : mooseAssert(inner_value.empty(), "Should be empty");
225 82 : continue;
226 : }
227 :
228 : // split each 2D subvector at delim ; to get 1D sub-subvectors
229 : // NOTE: the 1D sub-subvectors are _not_ of type T yet
230 1398 : std::vector<std::string> inner_tokenized;
231 1398 : MooseUtils::tokenize(inner_token, inner_tokenized, 1, ";");
232 1398 : inner_value.resize(inner_tokenized.size());
233 4842 : for (const auto j : index_range(inner_tokenized))
234 : {
235 6888 : const auto token = MooseUtils::trim(inner_tokenized[j]);
236 6888 : if (!MooseUtils::tokenizeAndConvert<T>(token, inner_value[j]))
237 2 : throw std::invalid_argument("invalid syntax for " + MooseUtils::prettyCppType<T>() +
238 : " triple vector parameter: " + field.fullpath() + "[" +
239 : std::to_string(i) + "][" + std::to_string(j) + "]='" + token +
240 : "'");
241 : }
242 : }
243 645 : }
244 :
245 : template <class Key, class Value>
246 : void
247 460 : setMapValue(std::map<Key, Value> & value, const hit::Field & field)
248 : {
249 460 : value.clear();
250 :
251 920 : const auto string_vec = field.param<std::vector<std::string>>();
252 460 : auto it = string_vec.begin();
253 2386 : while (it != string_vec.end())
254 : {
255 1013 : const auto & string_key = *(it++);
256 1013 : if (it == string_vec.end())
257 2 : throw std::invalid_argument(
258 : "odd number of entries for map parameter '" + field.fullpath() +
259 : "'; there must be an even number or else you will end up with a key without a value");
260 1011 : const auto & string_value = *(it++);
261 :
262 1011 : std::pair<Key, Value> pr;
263 :
264 : // convert key
265 1011 : if (!MooseUtils::convert<Key>(string_key, pr.first, false))
266 2 : throw std::invalid_argument("invalid " + MooseUtils::prettyCppType<Key>() +
267 : " syntax for map parameter '" + field.fullpath() + "' key: '" +
268 : string_key + "'");
269 :
270 : // convert value
271 1009 : if (!MooseUtils::convert<Value>(string_value, pr.second, false))
272 2 : throw std::invalid_argument("invalid " + MooseUtils::prettyCppType<Value>() +
273 : " syntax for map parameter '" + field.fullpath() + "' value: '" +
274 : string_value + "'");
275 : // attempt insert
276 1007 : if (!value.insert(std::move(pr)).second)
277 2 : throw std::invalid_argument("duplicate entry for map parameter: '" + field.fullpath() +
278 : "'; key '" + string_key + "' appears multiple times");
279 : }
280 460 : }
281 :
282 : } // end of namespace Moose::ParameterRegistration
|