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