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