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