GCC Code Coverage Report


Directory: ./
File: Core/getPotCustomized.hpp
Date: 2024-04-14 07:32:34
Exec Total Coverage
Lines: 24 39 61.5%
Branches: 29 132 22.0%

Line Branch Exec Source
1 // ______ ______ _ _ _____ ______
2 // | ____| ____| | (_)/ ____| | ____|
3 // | |__ | |__ | | _| (___ ___| |__
4 // | __| | __| | | | |\___ \ / __| __|
5 // | | | |____| |____| |____) | (__| |____
6 // |_| |______|______|_|_____/ \___|______|
7 // Finite Elements for Life Sciences and Engineering
8 //
9 // License: LGL2.1 License
10 // FELiScE default license: LICENSE in root folder
11 //
12 // Main authors: J. Foulon & J-F. Gerbeau & V. Martin
13 //
14
15 /*!
16 * \file getPotCustomized.hpp
17 * \authors David Froger
18 * \date 06/02/2011
19 *
20 * \brief Extend the file/command line parser Getpot capabilities to fit our needs.
21 *
22 * The main function is the overloaded get functions, that have some advantages
23 * to the base GetPot equivalent:
24 *
25 * - Both the command line and the data file are read with only one call to
26 * the get functions. For each data, a default value is first supply via a
27 * get function argument. If the data is present in the data file, this value
28 * override the default one. Finally, the command line will orrivide the current value
29 * if it specify this datum.
30 *
31 * - If the user specify a wrong option in the data file or on the command
32 * line, the error has to be detected. The list of the correct datum name is
33 * automatically constructed during the call to the get functions.
34 *
35 * - A "help" std::string is automatically constructed during the call to the get
36 * functions, intended to be displayed using --help on the command line.
37 *
38 * - A boolean type is added.
39 *
40 * - Reading enum is added.
41 *
42 * - Vector support is added for std::string, int, double and bool.
43 *
44 * - Recquire function that raise errors if name not found.
45 *
46 * - Combined with the moveToSection function, it avoid to have to repeat the
47 * section name for each datum.
48 *
49 * \note: Overloading is choosen for the get function. A template+specialization
50 * approach is not ideal, because bool and std::string are special cases.
51 *
52 * \note result values are named: result_SWIG_TYPED_OUT in the header only. It is
53 * used to provide additionnal informations to SWIG so it can generate
54 * particular Python wrapping on this argument. This should not be change to
55 * not break the Python wrapping.
56 *
57 * \warning: Data value std::string (for std::vector only) are casted to int or double
58 * using boost when they are read from the command line, but using another way
59 * (in GetPot) when read in the data file. Boost seams to be better that GetPort to
60 * detect cast errors.
61 *
62 * \todo: remove try/catch (or be sure that it does not alter global code
63 * performance).
64 *
65 * \todo: have consistent conversion std::string->int and std::string->double. For scalar,
66 * getpot is used, for std::vector, boost is used.
67 *
68 */
69
70 /* TODO: what does this documentation refer to?
71 * Read an enum in a data file
72 *
73 * Enumerations must start from zero, and be always incremented by one.
74 *
75 * \param[in] name Name of to parameter to read in data file.
76 * \param[in] numEnum Number of variable in the enum.
77 * \param[in] strEnum Mapping between the enum and its std::string representation
78 * \param[out] result Enum value, converted from the read enum
79 * std::string representation
80 *
81 * Example:
82 * -------
83 *
84 * datafile:
85 * [section]
86 * name = "foo"
87 *
88 * variables:
89 * enum FooBarBaz {foo,baz,bar}
90 * const char* strEnum[3] = {"foo","bar","baz"}
91 * FoobarBaz fbb;
92 *
93 * moveToSection("section");
94 * require(fbb,"name",3,strEnum) // fbb is foo
95 */
96
97 #ifndef _GET_POT_CUSTOMIZED_HPP
98 #define _GET_POT_CUSTOMIZED_HPP
99
100 // System includes
101 #include <vector>
102 #include <unordered_map>
103 #include <set>
104 #include <string>
105 #include <iostream>
106
107 // External includes
108 #include "Core/NoThirdPartyWarning/GetPot/getpot.hpp"
109
110 // Project includes
111 #include "Core/felisce.hpp"
112 #include "Core/util_string.hpp"
113
114 namespace felisce
115 {
116 // TODO: Move this class to another file
117 class ElementFieldDynamicValue {
118
119 public:
120 // components managed
121 static std::size_t numAllComp;
122 static Component allComp[3];
123
124 // init,delete functions
125 ElementFieldDynamicValue();
126 ElementFieldDynamicValue(const char* name);
127 ~ElementFieldDynamicValue();
128 void initialize(const char* name);
129
130 // std::set functions
131 void setElementFieldType(ElementFieldType elementFieldType);
132 void setTypeValueOfElementField(TypeValueOfElementField typeValueOfElementField, Component Comp);
133 void setNumComp(int numComp);
134 void setConstant(double constant, Component Comp);
135 void setFileName(std::string fileName, Component Comp);
136 void setFunctionName(std::string FunctionName, Component Comp);
137 void setCallbackXYZT(const CallbackXYZT &callbackXYZT, Component Comp);
138
139 // access functions
140 std::string name();
141 ElementFieldType elementFieldType();
142 TypeValueOfElementField typeValueOfElementField(Component Comp);
143 int numComp() const;
144 double constant(Component Comp);
145 std::string fileName(Component Comp);
146 std::string functionName(Component Comp);
147 CallbackXYZT callbackXYZT(Component Comp);
148
149 // others functions
150 void display();
151
152 private:
153 int numCompMax_;
154 std::string name_;
155 ElementFieldType elementFieldType_;
156 int numComp_;
157 TypeValueOfElementField typeValueOfElementField_[3];
158 double constant_[3];
159 std::string fileName_[3];
160 std::string functionName_[3];
161 CallbackXYZT callbackXYZT_[3];
162 bool isReady_[3];
163
164 int CompToIndex_(Component Comp);
165 };
166
167 class GetPotCustomized: public GetPot {
168
169 public:
170 GetPotCustomized();
171 ~GetPotCustomized();
172
173 void initialize(int argc,char **argv,std::string filename);
174
175 /*! \brief Get scalar value, provide a default one if not present in data file
176 */
177 void get(std::string& result_SWIG_TYPED_OUT, const char *name, const char * defaultValue, const char *help=nullptr);
178 void get(int & result_SWIG_TYPED_OUT, const char *name, int defaultValue, const char *help=nullptr);
179 void get(double& result_SWIG_TYPED_OUT, const char *name, double defaultValue, const char *help=nullptr);
180 void get(bool & result_SWIG_TYPED_OUT, const char *name, bool defaultValue, const char *help=nullptr);
181
182 template <class Enum>
183 void get(Enum &result_SWIG_TYPED_OUT, const char *name, Enum defaultValue,
184 int numEnum, const char **strEnum, const char *help=nullptr);
185
186 /*! \brief Get std::vector values, provide a default one if not present in data file
187 */
188 void get(std::vector<std::string>& result_SWIG_TYPED_OUT, const char *name, const char *defaultValue, const char *help=nullptr);
189 void get(std::vector<int> & result_SWIG_TYPED_OUT, const char *name, const char *defaultValue, const char *help=nullptr);
190 void get(std::vector<double>& result_SWIG_TYPED_OUT, const char *name, const char *defaultValue, const char *help=nullptr);
191 void get(std::vector<bool> & result_SWIG_TYPED_OUT, const char *name, const char *defaultValue, const char *help=nullptr);
192
193 template <class Enum>
194 void get(std::vector<Enum> &result_SWIG_TYPED_OUT, const char *name, const char *defaultValue,
195 int numEnum, const char **strEnum, const char *help=nullptr);
196
197 /*! \brief Get scalar value, but this is an error if not present in data file.
198 *
199 * \note GetPot provide only function to read data and use default value if
200 * data si no present. So we fist read the data as a std::string and check the
201 * std::string is not "", then we really read the data, providing a default value
202 * that will be overriden.
203 */
204 void require(std::string& result_SWIG_TYPED_OUT, const char *name, const char *help=nullptr);
205 void require(int & result_SWIG_TYPED_OUT, const char *name, const char *help=nullptr);
206 void require(double& result_SWIG_TYPED_OUT, const char *name, const char *help=nullptr);
207 void require(bool & result_SWIG_TYPED_OUT, const char *name, const char *help=nullptr);
208
209 template <class Enum>
210 void require(Enum &result_SWIG_TYPED_OUT, const char *name,
211 int numEnum, const char **strEnum, const char *help=nullptr);
212
213 void require(std::vector<std::string>& result_SWIG_TYPED_OUT, const char *name, const char *help=nullptr);
214 void require(std::vector<int> & result_SWIG_TYPED_OUT, const char *name, const char *help=nullptr);
215 void require(std::vector<double>& result_SWIG_TYPED_OUT, const char *name, const char *help=nullptr);
216 void require(std::vector<bool> & result_SWIG_TYPED_OUT, const char *name, const char *help=nullptr);
217
218 template <class Enum>
219 void require(std::vector<Enum> &result_SWIG_TYPED_OUT, const char *name,
220 int numEnum, const char **strEnum, const char *help=nullptr);
221
222 //ElementField
223 std::set<std::string> getElementFieldSection();
224 ElementFieldDynamicValue* getElementFieldDynamicValue(std::string section);
225 std::string elementFieldNameFromSection(std::string section);
226
227 /*! \brief Test whether an data is defined in the file or not
228 *
229 */
230 bool exists(const char *name);
231
232 /*! \brief call FEL_ERROR in name is not defined in current fileanme/section.
233 *
234 */
235 void raiseErrorIfNotExists(const char *name);
236
237 /*! \brief call FEL_ERROR if name is defined in current fileanme/section.
238 *
239 */
240 void raiseErrorIfExists(const char *name);
241
242 /*!
243 * \brief Move to a data file section to read data in.
244 */
245 void moveToSection(std::string section);
246
247 /*!
248 * \brief Check that the datum name supplied by the user in the data file and
249 * on the command line are correct.
250 *
251 * The is done using the lists of correct datum names, m_identifiedVariablesCl
252 * and m_identifiedVariablesFile
253 */
254 void checkUndefinedVariable();
255
256 /*!
257 * \brief Check that, in the current section, several std::vector datum have the same
258 * length.
259 */
260 void assertSameLength(int count, ...);
261
262 /*!
263 * \brief Return informations about Felisce datum, intented to be printed with
264 * --help, like a manpage.
265 */
266 std::unordered_map<std::string, std::vector<std::string> > getHelp();
267
268 void addToIdentifiedVariables(const char *name);
269
270 /*!
271 * \brief validate a parameter in data file can be converted to int.
272 *
273 * GetPot provide poor conversion checking, e.g. "foo" can be converted to 0.
274 * We use std::stod and std::stoi to provide more reliable data file reading.
275 */
276 void validateIntParam(const char* name);
277 void validateDoubleParam(const char* name);
278
279 private:
280 std::size_t getLength(const char *name);
281 std::string m_paramFromFile(const char *name);
282 std::string m_paramFromCl (const char *name);
283 template<class T>
284 void m_addToHelp(const char *name, const char *type, T defaultValue, const char *help);
285
286 GetPot* m_getpotFile;
287 GetPot* m_getpotCl;
288
289 std::string m_section;
290 std::string m_filename;
291 std::string prefixOptionFelisce;
292
293 std::vector<std::string> m_identifiedVariablesCl;
294 std::vector<std::string> m_identifiedVariablesFile;
295
296 std::unordered_map<std::string, std::vector<std::string> > m_help;
297 };
298
299 /* =========================================================================
300 * template implementation
301 *========================================================================*/
302
303 // get Enum
304
305 template <class Enum>
306 6 void GetPotCustomized::get(Enum &result_SWIG_TYPED_OUT, const char *name, Enum defaultValue,
307 int numEnum, const char **strEnum, const char *help) {
308
309 // check that defaultValue is correct
310
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if ((int) defaultValue >= numEnum) {
311 std::ostringstream msg;
312 msg << "Bad Data file '" << m_filename << "': "
313 << "In section '" << m_section << "', "
314 << "(int) defaultValue = " << int (defaultValue)
315 << " is greater or equal than numEnum = " << numEnum;
316 FEL_ERROR(msg.str().c_str());
317 }
318
319 6 const char *defaultValueStr = strEnum[(int) defaultValue];
320
321 // read name as a std::string
322 6 std::string resultStr;
323
324
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 std::string paramFromFile = m_paramFromFile(name);
325
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 std::string paramFromCl = m_paramFromCl(name);
326
327
3/6
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
6 resultStr = (*m_getpotFile)(paramFromFile.c_str() , defaultValueStr);
328
3/6
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 6 times.
✗ Branch 10 not taken.
6 resultStr = (*m_getpotCl) (paramFromCl.c_str(), resultStr.c_str());
329
330 // convert std::string to its value
331
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 int buf = ppcharIndex(numEnum,strEnum,resultStr.c_str());
332
333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (buf == -1) {
334 std::cout << "INFO: In section '" << m_section
335 << "' valid values for '" << name
336 << "' are:" << std::endl;
337
338 for (int istr=0 ; istr<numEnum ; istr++)
339 std::cout << " " << strEnum[istr] << std::endl;
340
341 std::ostringstream msg;
342 msg << "Bad data file '" << m_filename << "': "
343 << "In section '" << m_section << "', "
344 << "enum '" << name << "' "
345 << "has wrong value '" << resultStr << "'.";
346 FEL_ERROR(msg.str().c_str());
347 }
348
349 6 result_SWIG_TYPED_OUT = static_cast<Enum>(buf);
350
351
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 if (help != nullptr) m_addToHelp(name,"ENUM",defaultValueStr,help);
352 6 }
353
354 // get std::vector<Enum>
355
356 template <class Enum>
357 void GetPotCustomized::get(std::vector<Enum> &result_SWIG_TYPED_OUT, const char *name, const char *defaultValue,
358 int numEnum, const char **strEnum, const char *help) {
359 std::string onestring;
360
361 std::string paramFromFile = m_paramFromFile(name);
362 std::string paramFromCl = m_paramFromCl(name);
363
364 onestring = (*m_getpotFile)( paramFromFile.c_str(), defaultValue);
365 onestring = (*m_getpotCl) ( paramFromCl.c_str(), onestring.c_str());
366
367 // split "Comp1 Comp2 Comp3" into {"Comp1", "Comp2", "Comp3"}
368 std::vector<std::string> vecstring;
369 split(onestring,vecstring," \n\t");
370
371 // convert std::string element to Enum Element
372 Enum item;
373 for ( unsigned int i = 0; i < vecstring.size(); i++) {
374 item = (Enum) ppcharIndex(numEnum,strEnum,vecstring[i].c_str());
375
376 if ((int) item == -1) {
377 std::cout << "INFO: In section '" << m_section
378 << "' valid values for '" << name
379 << "' are:" << std::endl;
380
381 for (int istr=0 ; istr<numEnum ; istr++)
382 std::cout << " " << strEnum[istr] << std::endl;
383
384 std::ostringstream msg;
385 msg << "Bad data file '" << m_filename << "': "
386 << "In section '" << m_section << "', "
387 << "enum '" << name << "' "
388 << "has wrong value '" << vecstring[i].c_str() << "'.";
389 FEL_ERROR(msg.str().c_str());
390 }
391
392 result_SWIG_TYPED_OUT.push_back(item);
393 }
394
395 if (help != nullptr) m_addToHelp(name,"ENUM VECTOR",defaultValue,help);
396 }
397
398 // require enum
399
400 template <class Enum>
401 6 void GetPotCustomized::require(Enum &result_SWIG_TYPED_OUT, const char *name,
402 int numEnum, const char **strEnum, const char *help) {
403 6 raiseErrorIfNotExists(name);
404 6 get(result_SWIG_TYPED_OUT,name,(Enum) 0,numEnum,strEnum,help);
405 6 }
406
407 // require std::vector<enum>
408
409 template <class Enum>
410 void GetPotCustomized::require(std::vector<Enum> &result_SWIG_TYPED_OUT, const char *name,
411 int numEnum, const char **strEnum, const char *help) {
412 raiseErrorIfNotExists(name);
413 get(result_SWIG_TYPED_OUT,name,"",numEnum,strEnum,help);
414 }
415
416
417 template <class T>
418 637050 void GetPotCustomized::m_addToHelp(const char *name, const char *type, T defaultValue, const char *help) {
419
420
1/2
✓ Branch 1 taken 318525 times.
✗ Branch 2 not taken.
637050 std::ostringstream stream;
421
422
7/14
✓ Branch 1 taken 318525 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 318525 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 318525 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 318525 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 318525 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 318525 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 318525 times.
✗ Branch 20 not taken.
637050 stream << " --felisce-" << m_section << "-" << name << "=" << type << std::endl
423
3/6
✓ Branch 1 taken 318525 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 318525 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 318525 times.
✗ Branch 8 not taken.
637050 << " DEFAULT: " << defaultValue << std::endl
424
3/6
✓ Branch 1 taken 318525 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 318525 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 318525 times.
✗ Branch 8 not taken.
637050 << " " << help << std::endl
425 ;
426
427
3/6
✓ Branch 1 taken 318525 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 318525 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 318525 times.
✗ Branch 8 not taken.
637050 m_help[m_section].push_back( stream.str() );
428 637050 }
429
430 }
431
432 #endif
433