1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2020 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19
20 #ifndef LIBMESH_PARAMETERS_H
21 #define LIBMESH_PARAMETERS_H
22
23 // Local includes
24 #include "libmesh/libmesh_common.h"
25 #include "libmesh/reference_counted_object.h"
26 #include "libmesh/print_trace.h"
27
28 // C++ includes
29 #include <cstddef>
30 #include <map>
31 #include <sstream>
32 #include <string>
33 #include <typeinfo>
34 #include <vector>
35
36 namespace libMesh
37 {
38 /**
39 * Helper functions for printing scalar, vector and vector<vector> types. Called from Parameters::Parameter<T>::print(...).
40 */
41 template<typename P>
42 void print_helper(std::ostream & os, const P * param);
43
44 template<typename P>
45 void print_helper(std::ostream & os, const std::vector<P> * param);
46
47 template<typename P>
48 void print_helper(std::ostream & os, const std::vector<std::vector<P>> * param);
49
50 template<typename P1, typename P2, typename C, typename A>
51 void print_helper(std::ostream & os, const std::map<P1, P2, C, A> * param);
52
53 /**
54 * This class provides the ability to map between
55 * arbitrary, user-defined strings and several data
56 * types. This can be used to provide arbitrary
57 * user-specified options.
58 *
59 * \author Benjamin S. Kirk
60 * \date 2004
61 */
62 class Parameters
63 {
64 public:
65
66 /**
67 * Default constructor. Does nothing.
68 */
Parameters()69 Parameters () {}
70
71 /**
72 * Copy constructor.
73 */
74 Parameters (const Parameters &);
75
76 /**
77 * Destructor. Clears any allocated memory.
78 */
79 virtual ~Parameters ();
80
81 /**
82 * Assignment operator. Removes all parameters in \p this
83 * and inserts copies of all parameters from \p source
84 */
85 virtual Parameters & operator= (const Parameters & source);
86
87 /**
88 * Addition/Assignment operator. Inserts copies of all parameters
89 * from \p source. Any parameters of the same name already in \p
90 * this are replaced.
91 */
92 virtual Parameters & operator+= (const Parameters & source);
93
94 /**
95 * \returns \p true if a parameter of type \p T
96 * with a specified name exists, \p false otherwise.
97 *
98 * If RTTI has been disabled then we return \p true
99 * if a parameter of specified name exists regardless of its type.
100 */
101 template <typename T>
102 bool have_parameter (const std::string &) const;
103
104 /**
105 * \returns A constant reference to the specified parameter
106 * value. Requires, of course, that the parameter exists.
107 */
108 template <typename T>
109 const T & get (const std::string &) const;
110
111 /**
112 * Inserts a new Parameter into the object but does not return
113 * a writable reference. The value of the newly inserted
114 * parameter may not be valid.
115 */
116 template <typename T>
117 void insert (const std::string &);
118
119 /**
120 * \returns A writable reference to the specified parameter.
121 * This method will create the parameter if it does not exist,
122 * so it can be used to define parameters which will later be
123 * accessed with the \p get() member.
124 */
125 template <typename T>
126 T & set (const std::string &);
127
128 /**
129 * Overridable function to set any extended attributes for
130 * classes inheriting from this class.
131 */
set_attributes(const std::string &,bool)132 virtual void set_attributes(const std::string &, bool /*inserted_only*/) {}
133
134 /**
135 * Removes the specified parameter from the list, if it exists.
136 */
137 void remove (const std::string &);
138
139 /**
140 * \returns The total number of parameters.
141 */
n_parameters()142 std::size_t n_parameters () const { return _values.size(); }
143
144 #ifdef LIBMESH_HAVE_RTTI
145 /**
146 * \returns The number of parameters of the requested type.
147 */
148 template <typename T>
149 unsigned int n_parameters () const;
150 #endif // LIBMESH_HAVE_RTTI
151
152 /**
153 * Clears internal data structures & frees any allocated memory.
154 */
155 virtual void clear ();
156
157 /**
158 * Prints the contents, by default to libMesh::out.
159 */
160 void print (std::ostream & os=libMesh::out) const;
161
162 /**
163 * Abstract definition of a parameter value.
164 */
165 class Value : public ReferenceCountedObject<Value>
166 {
167 public:
168
169 /**
170 * Destructor.
171 */
~Value()172 virtual ~Value() {}
173
174 #ifdef LIBMESH_HAVE_RTTI
175 /**
176 * String identifying the type of parameter stored.
177 * Must be reimplemented in derived classes.
178 */
179 virtual std::string type () const = 0;
180 #endif // LIBMESH_HAVE_RTTI
181
182 /**
183 * Prints the parameter value to the specified stream.
184 * Must be reimplemented in derived classes.
185 */
186 virtual void print(std::ostream &) const = 0;
187
188 /**
189 * Clone this value. Useful in copy-construction.
190 * Must be reimplemented in derived classes.
191 */
192 virtual Value * clone () const = 0;
193 };
194
195 /**
196 * Concrete definition of a parameter value
197 * for a specified type.
198 */
199 template <typename T>
200 class Parameter : public Value
201 {
202 public:
203
204 /**
205 * \returns A read-only reference to the parameter value.
206 */
get()207 const T & get () const { return _value; }
208
209 /**
210 * \returns A writable reference to the parameter value.
211 */
set()212 T & set () { return _value; }
213
214 #ifdef LIBMESH_HAVE_RTTI
215 /**
216 * String identifying the type of parameter stored.
217 */
218 virtual std::string type () const override;
219 #endif // LIBMESH_HAVE_RTTI
220
221 /**
222 * Prints the parameter value to the specified stream.
223 */
224 virtual void print(std::ostream &) const override;
225
226 /**
227 * Clone this value. Useful in copy-construction.
228 */
229 virtual Value * clone () const override;
230
231 private:
232 /**
233 * Stored parameter value.
234 */
235 T _value;
236 };
237
238 /**
239 * Parameter map iterator.
240 */
241 typedef std::map<std::string, Value *>::iterator iterator;
242
243 /**
244 * Constant parameter map iterator.
245 */
246 typedef std::map<std::string, Value *>::const_iterator const_iterator;
247
248 /**
249 * Iterator pointing to the beginning of the set of parameters.
250 */
251 iterator begin();
252
253 /**
254 * Iterator pointing to the beginning of the set of parameters.
255 */
256 const_iterator begin() const;
257
258 /**
259 * Iterator pointing to the end of the set of parameters
260 */
261 iterator end();
262
263 /**
264 * Iterator pointing to the end of the set of parameters
265 */
266 const_iterator end() const;
267
268 protected:
269
270 /**
271 * Data structure to map names with values.
272 */
273 std::map<std::string, Value *> _values;
274
275 };
276
277 // ------------------------------------------------------------
278 // Parameters::Parameter<> class inline methods
279
280 // This only works with Run-Time Type Information, even though
281 // typeid(T) *should* be determinable at compile time regardless...
282 #ifdef LIBMESH_HAVE_RTTI
283 template <typename T>
284 inline
type()285 std::string Parameters::Parameter<T>::type () const
286 {
287 return demangle(typeid(T).name());
288 }
289 #endif
290
291 template <typename T>
292 inline
print(std::ostream & os)293 void Parameters::Parameter<T>::print (std::ostream & os) const
294 {
295 // Call helper function overloaded for basic scalar and vector types
296 print_helper(os, static_cast<const T *>(&_value));
297 }
298
299 template <typename T>
300 inline
clone()301 Parameters::Value * Parameters::Parameter<T>::clone () const
302 {
303 Parameter<T> * copy = new Parameter<T>;
304
305 libmesh_assert(copy);
306
307 copy->_value = _value;
308
309 return copy;
310 }
311
312
313 // ------------------------------------------------------------
314 // Parameters class inline methods
315 inline
clear()316 void Parameters::clear () // since this is inline we must define it
317 { // before its first use (for some compilers)
318 while (!_values.empty())
319 {
320 Parameters::iterator it = _values.begin();
321
322 delete it->second;
323 it->second = nullptr;
324
325 _values.erase(it);
326 }
327 }
328
329
330
331 inline
332 Parameters & Parameters::operator= (const Parameters & source)
333 {
334 this->clear();
335 *this += source;
336
337 return *this;
338 }
339
340 inline
341 Parameters & Parameters::operator+= (const Parameters & source)
342 {
343 for (const auto & pr : source._values)
344 {
345 if (_values.find(pr.first) != _values.end())
346 delete _values[pr.first];
347 _values[pr.first] = pr.second->clone();
348 }
349
350 return *this;
351 }
352
353 inline
Parameters(const Parameters & p)354 Parameters::Parameters (const Parameters & p)
355 {
356 *this = p;
357 }
358
359
360
361 inline
~Parameters()362 Parameters::~Parameters ()
363 {
364 this->clear ();
365 }
366
367
368
369 inline
print(std::ostream & os)370 void Parameters::print (std::ostream & os) const
371 {
372 Parameters::const_iterator it = _values.begin();
373
374 os << "Name\t Type\t Value\n"
375 << "---------------------\n";
376 while (it != _values.end())
377 {
378 os << " " << it->first
379 #ifdef LIBMESH_HAVE_RTTI
380 << "\t " << it->second->type()
381 #endif // LIBMESH_HAVE_RTTI
382 << "\t "; it->second->print(os);
383 os << '\n';
384
385 ++it;
386 }
387 }
388
389
390
391 // Declare this now that Parameters::print() is defined.
392 // By declaring this early we can use it in subsequent
393 // methods. Required for gcc-4.0.2 -- 11/30/2005, BSK
394 inline
395 std::ostream & operator << (std::ostream & os, const Parameters & p)
396 {
397 p.print(os);
398 return os;
399 }
400
401
402
403 template <typename T>
404 inline
have_parameter(const std::string & name)405 bool Parameters::have_parameter (const std::string & name) const
406 {
407 Parameters::const_iterator it = _values.find(name);
408
409 if (it != _values.end())
410 #ifdef LIBMESH_HAVE_RTTI
411 if (dynamic_cast<const Parameter<T> *>(it->second) != nullptr)
412 #else // LIBMESH_HAVE_RTTI
413 if (cast_ptr<const Parameter<T> *>(it->second) != nullptr)
414 #endif // LIBMESH_HAVE_RTTI
415 return true;
416
417 return false;
418 }
419
420
421
422 template <typename T>
423 inline
get(const std::string & name)424 const T & Parameters::get (const std::string & name) const
425 {
426 if (!this->have_parameter<T>(name))
427 {
428 std::ostringstream oss;
429
430 oss << "ERROR: no";
431 #ifdef LIBMESH_HAVE_RTTI
432 oss << ' ' << demangle(typeid(T).name());
433 #endif
434 oss << " parameter named \""
435 << name << "\" found.\n\n"
436 << "Known parameters:\n"
437 << *this;
438
439 libmesh_error_msg(oss.str());
440 }
441
442 Parameters::const_iterator it = _values.find(name);
443
444 libmesh_assert(it != _values.end());
445 libmesh_assert(it->second);
446
447 return cast_ptr<Parameter<T> *>(it->second)->get();
448 }
449
450 template <typename T>
451 inline
insert(const std::string & name)452 void Parameters::insert (const std::string & name)
453 {
454 if (!this->have_parameter<T>(name))
455 _values[name] = new Parameter<T>;
456
457 set_attributes(name, true);
458 }
459
460
461 template <typename T>
462 inline
set(const std::string & name)463 T & Parameters::set (const std::string & name)
464 {
465 if (!this->have_parameter<T>(name))
466 _values[name] = new Parameter<T>;
467
468 set_attributes(name, false);
469
470 return cast_ptr<Parameter<T> *>(_values[name])->set();
471 }
472
473 inline
remove(const std::string & name)474 void Parameters::remove (const std::string & name)
475 {
476 Parameters::iterator it = _values.find(name);
477
478 if (it != _values.end())
479 {
480 delete it->second;
481 it->second = nullptr;
482
483 _values.erase(it);
484 }
485 }
486
487
488
489 #ifdef LIBMESH_HAVE_RTTI
490 template <typename T>
491 inline
n_parameters()492 unsigned int Parameters::n_parameters () const
493 {
494 unsigned int cnt = 0;
495
496 Parameters::const_iterator it = _values.begin();
497 const Parameters::const_iterator vals_end = _values.end();
498
499 for (; it != vals_end; ++it)
500 if (dynamic_cast<Parameter<T> *>(it->second) != nullptr)
501 cnt++;
502
503 return cnt;
504 }
505 #endif
506
507 inline
begin()508 Parameters::iterator Parameters::begin()
509 {
510 return _values.begin();
511 }
512
513 inline
begin()514 Parameters::const_iterator Parameters::begin() const
515 {
516 return _values.begin();
517 }
518
519 inline
end()520 Parameters::iterator Parameters::end()
521 {
522 return _values.end();
523 }
524
525 inline
end()526 Parameters::const_iterator Parameters::end() const
527 {
528 return _values.end();
529 }
530
531 //non-member scalar print function
532 template<typename P>
print_helper(std::ostream & os,const P * param)533 void print_helper(std::ostream & os, const P * param)
534 {
535 os << *param;
536 }
537
538 template<>
539 inline
print_helper(std::ostream & os,const char * param)540 void print_helper(std::ostream & os, const char * param)
541 {
542 // Specialization so that we don't print out unprintable characters
543 os << static_cast<int>(*param);
544 }
545
546 template<>
547 inline
print_helper(std::ostream & os,const unsigned char * param)548 void print_helper(std::ostream & os, const unsigned char * param)
549 {
550 // Specialization so that we don't print out unprintable characters
551 os << static_cast<int>(*param);
552 }
553
554 //non-member vector print function
555 template<typename P>
print_helper(std::ostream & os,const std::vector<P> * param)556 void print_helper(std::ostream & os, const std::vector<P> * param)
557 {
558 for (const auto & p : *param)
559 os << p << " ";
560 }
561
562 //non-member vector<vector> print function
563 template<typename P>
print_helper(std::ostream & os,const std::vector<std::vector<P>> * param)564 void print_helper(std::ostream & os, const std::vector<std::vector<P>> * param)
565 {
566 for (const auto & pv : *param)
567 for (const auto & p : pv)
568 os << p << " ";
569 }
570
571 //non-member map print function
572 template<typename P1, typename P2, typename C, typename A>
print_helper(std::ostream & os,const std::map<P1,P2,C,A> * param)573 void print_helper(std::ostream & os, const std::map<P1, P2, C, A> * param)
574 {
575 os << '{';
576 std::size_t sz = param->size();
577 for (auto KV : *param)
578 {
579 os << '\'' << KV.first << "\' => \'" << KV.second << '\'';
580 if (--sz)
581 os << ", ";
582 }
583 os << '}';
584 }
585
586
587 } // namespace libMesh
588
589 #endif // LIBMESH_PARAMETERS_H
590