LCOV - code coverage report
Current view: top level - src/IO - ParmParse.H (source / functions) Hit Total Coverage
Test: coverage_merged.info Lines: 110 156 70.5 %
Date: 2024-11-18 05:28:54 Functions: 81 117 69.2 %

          Line data    Source code
       1             : //
       2             : // This is a thin wrapper to the amrex::ParmParse class
       3             : // This class exists to add some additional parsing capability, 
       4             : // e.g. parsing Set::Matrix and Set::Vector data types.
       5             : //
       6             : // :ref:`IO::ParmParse` uses static :code:`Parse()` functions to 
       7             : // perform cascading class-based input parsing.
       8             : // See the :ref:`autodoc` section for instructions on adding documentation.
       9             : // 
      10             : // :bdg-warning-line:`This is standard infrastructure code; make sure you know what you ard doing before you change it.`
      11             : //
      12             : // .. _query-directives:
      13             : //
      14             : // **Query directives**
      15             : //
      16             : // Alamo uses different query directives to standardize reading inputs and automatic documentation.
      17             : // The type of query that is used (query vs query_required, etc) triggers different handlers and different
      18             : // automatic documentation procedures.
      19             : // For instance, the use of a :code:`query_default` causes a default value to be set and added to the metadata
      20             : // file, and it also serves as a flag for the autodoc system to document that a default value is available.
      21             : // The following table is a reference for the different kinds of query directives.
      22             : //
      23             : //
      24             : // .. table::
      25             : //    :widths: 1 99
      26             : //
      27             : //    +---------------------------------+-----------------------------------------------------------------+
      28             : //    | BC Type                         | Description                                                     |
      29             : //    +=================================+=================================================================+
      30             : //    | :bdg-warning:`query`            | Standard IO for bool, string, Set::Scalarthat does not enforce  |
      31             : //    |                                 | defaults or required values. Not recommended for general use.   |
      32             : //    +---------------------------------+-----------------------------------------------------------------+
      33             : //    | :bdg-success:`query_required`   | Similar to query, but will abort if no value is specified.      |
      34             : //    |                                 | Required values are indicated by :bdg-danger-line:`required`.   |
      35             : //    +---------------------------------+-----------------------------------------------------------------+
      36             : //    | :bdg-success:`query_default`    | Similar to query, but will fill with default value if no value  |
      37             : //    |                                 | is provided. Will also add default value to metadata.           |
      38             : //    |                                 | Default values are indicated by green badge values, e.g.        |
      39             : //    |                                 | :bdg-success:`0.0`.                                             |
      40             : //    +---------------------------------+-----------------------------------------------------------------+
      41             : //    | :bdg-success:`query_validate`   | For strings, read in a value and enforce that the value is one  |
      42             : //    |                                 | of a supplied number of values. Optionally make required, or    |
      43             : //    |                                 | set the default value to the first supplied value.              | 
      44             : //    |                                 | Acceptable options are indicated by blue badge values, e.g.     | 
      45             : //    |                                 | :bdg-primary:`1.0`, :bdg-primary:`2.0`. If a default value is   | 
      46             : //    |                                 | available, it is indicated by a green badge, e.g.               | 
      47             : //    |                                 | :bdg-success:`1.0`.                                             | 
      48             : //    +---------------------------------+-----------------------------------------------------------------+
      49             : //    | :bdg-success:`query_file`       | Read in a string that defines a file name.                      |
      50             : //    |                                 | Check to make sure that the file exists and is a regular file,  |
      51             : //    |                                 | and print an informative error message if not (this can be      |
      52             : //    |                                 | disabled).                                                      |
      53             : //    |                                 | Also, copy the file to the output directory, with the full path |
      54             : //    |                                 | preserved by replacing / with _.                                |
      55             : //    |                                 | (This can also be disabled, but doing so is discouraged.)       |
      56             : //    |                                 | Default values are not allowed.                                 |
      57             : //    |                                 | File paths are indicated by :bdg-secondary-line:`file path`.    |
      58             : //    +---------------------------------+-----------------------------------------------------------------+
      59             : //    | :bdg-primary:`queryarr`         | Read in an array of numbers into either a standard vector or    |
      60             : //    |                                 | into a :code:`Set::Vector` or :code:`Set::Scalar`.              |
      61             : //    |                                 | No defaults or existence checking is performed.                 |
      62             : //    +---------------------------------+-----------------------------------------------------------------+
      63             : //    | :bdg-primary:`queryclass`       | Read a class object with a specified prefix.                    |
      64             : //    |                                 | How that class is read in is determined by its :code:`Parse`    |
      65             : //    |                                 | function.                                                       |
      66             : //    +---------------------------------+-----------------------------------------------------------------+
      67             : // 
      68             : // .. _query_locator_macros:
      69             : //
      70             : // **Query macros**
      71             : //
      72             : // A set of preprocessor macros are defined so that you can call a query function using :code:`pp_` instead
      73             : // of :code:`pp.`.
      74             : // For instance, the following two can be used interchangeably:
      75             : //
      76             : // .. code-block:: cpp
      77             : //
      78             : //     pp.query_required("myvar",myvar); /* function version */
      79             : //     pp_query_required("myvar",myvar); /* preprocessor macro version - preferred*/
      80             : // 
      81             : // Using the preprocessor macros enables code location information to be passed to the parser, so that
      82             : // more informative error messages will be printed out.
      83             : // Note that **the ParmParse object must always be called** :code:`pp` **for this to work**.
      84             : // 
      85             : //
      86             : 
      87             : #ifndef IO_PARMPARSE
      88             : #define IO_PARMPARSE
      89             : 
      90             : #include <filesystem>
      91             : #include <exception>
      92             : #include <list>
      93             : 
      94             : #include "Util/Util.H"
      95             : #include "Set/Set.H"
      96             : #include "AMReX_ParmParse.H"
      97             : 
      98             : 
      99             : #define pp_query_required(...) pp.query_required(__VA_ARGS__,INFO)
     100             : #define pp_query_default(...) pp.query_default(__VA_ARGS__,INFO)
     101             : #define pp_query_validate(...) pp.query_validate(__VA_ARGS__,INFO)
     102             : #define pp_query_file(...) pp.query_file(__VA_ARGS__,INFO)
     103             : #define pp_queryarr(...) pp.queryarr(__VA_ARGS__,INFO)
     104             : #define pp_queryarr_required(...) pp.queryarr_required(__VA_ARGS__,INFO)
     105             : #define pp_query(...) pp.query(__VA_ARGS__)
     106             : #define pp_queryclass(...) pp.queryclass(__VA_ARGS__,INFO)
     107             : #define pp_forbid(...) pp.forbid(__VA_ARGS__,INFO)
     108             : 
     109             : 
     110             : namespace IO
     111             : {
     112             : class ParmParse : public amrex::ParmParse
     113             : {
     114             : private:
     115         780 :     void Define() 
     116             :     {
     117         780 :         if (checked_for_input_files) return;
     118          33 :         int k = 0;
     119          66 :         std::string inputfile = "";
     120          33 :         while (this->querykth("input",k,inputfile)) 
     121             :         {
     122           0 :             Util::Message(INFO,"Including inputs from "+inputfile);
     123           0 :             this->addfile(inputfile);
     124           0 :             k++;
     125             :         }
     126          33 :         checked_for_input_files = true;
     127             :     }
     128             :     static bool checked_for_input_files;
     129             :     
     130             : public:
     131         587 :     ParmParse(std::string arg) : amrex::ParmParse::ParmParse(arg) {Define();} ;
     132         193 :     ParmParse() : amrex::ParmParse::ParmParse() {Define();} ;
     133        4654 :     std::string getPrefix() const {return m_prefix;};
     134         396 :     void ignore(std::string name)
     135             :     {
     136         396 :         (void)amrex::ParmParse::contains(name.c_str());
     137         396 :     }
     138             : 
     139           2 :     void forbid(std::string name, std::string explanation,
     140             :                 std::string file = "", std::string func = "", int line = -1)
     141             :     {
     142           2 :         if (amrex::ParmParse::contains(full(name).c_str()))
     143             :         {
     144           0 :             Util::ParmParseException(INFO,file,func,line,full(name),full(name)," forbidden: ", explanation);
     145             :         }
     146           6 :         std::set<std::string> subs = amrex::ParmParse::getEntries(full(name));
     147           2 :         if (subs.size())
     148             :         {
     149           0 :             Util::ParmParseException(INFO,file,func,line,full(name),full(name)," forbidden: ", explanation);
     150             :         }
     151           2 :     }
     152             : 
     153        1694 :     bool contains(std::string name)
     154             :     {
     155        1694 :         if (amrex::ParmParse::contains(name.c_str()))
     156         546 :             return true;
     157        1148 :         if (amrex::ParmParse::contains(full(name).c_str()))
     158           0 :             return true;
     159             :         {
     160        2296 :             std::set<std::string> subs = amrex::ParmParse::getEntries(name.c_str());
     161        1148 :             if (subs.size())
     162          22 :                 return true;
     163             :         }
     164             :         {
     165        2252 :             std::set<std::string> subs = amrex::ParmParse::getEntries(full(name).c_str());
     166        1126 :             if (subs.size())
     167           0 :                 return true;
     168             :         }
     169        1126 :         return false;
     170             :     }
     171             : 
     172             :     template<typename T> 
     173         175 :     int query_required( std::string name, T & value,
     174             :                         std::string file = "", std::string func = "", int line = -1)
     175             :     {
     176         175 :         if (!contains(name.c_str()))
     177             :         {
     178           0 :             Util::ParmParseException(INFO,file,func,line,full(name),"required value for ",full(name)," missing");
     179             :         }
     180         175 :         return query(name.c_str(),value);
     181             :     }
     182             : 
     183             :     template<typename T>
     184         979 :     int query_default(  std::string name, T & value, T defaultvalue,
     185             :                         std::string = "", std::string = "", int = -1)
     186             :     {
     187         979 :         if (!contains(name.c_str()))
     188             :         {
     189         786 :             add(name.c_str(),defaultvalue);
     190             :         }
     191         979 :         return query(name.c_str(),value);
     192             :     } 
     193             : 
     194             :     int query_validate( std::string name, int & value, std::vector<int> possibleintvals,
     195             :                         std::string file = "", std::string func = "", int line = -1)
     196             :     {
     197             :         // First value is accepted by default...
     198             : 
     199             :         // set default value
     200             :         value = possibleintvals[0];
     201             : 
     202             :         // get the read value (if it exists)
     203             :         int retval = query(name.c_str(),value);
     204             : 
     205             :         // check to make sure the read value matches one of the inpus
     206             :         bool ok = false;
     207             :         for (unsigned int i = 0; i < possibleintvals.size(); i++)
     208             :         {
     209             :             if (value == possibleintvals[i]) ok = true;
     210             :         }
     211             : 
     212             :         if (ok) return retval;
     213             : 
     214             :         std::stringstream ss;
     215             :         ss << possibleintvals[0];
     216             :         for (unsigned int i = 1; i < possibleintvals.size(); i++)
     217             :             ss << "," << possibleintvals[i];
     218             : 
     219             :         Util::ParmParseException(INFO,file,func,line,full(name),"' expected [", ss.str(), "] but got ", value);
     220             : 
     221             :         return -1;
     222             :     }
     223             : 
     224             : 
     225          49 :     int query_validate( std::string name, std::string & value, std::vector<const char *> possiblecharvals, bool firstbydefault,
     226             :                         std::string file = "", std::string func = "", int line = -1)
     227             :     {        
     228             :         // if not using default values, then the input must be specified
     229          49 :         if (!firstbydefault)
     230             :         {
     231           0 :             if (!contains(name.c_str()))
     232             :             {
     233           0 :                 Util::ParmParseException(INFO,file,func,line,full(name),"required value for ",full(name)," missing");
     234             :             }
     235             :         }
     236             : 
     237             :         // set default value
     238          49 :         value = std::string(possiblecharvals[0]);
     239             : 
     240             :         // get the read value (if it exists)
     241          49 :         int retval = query(name.c_str(),value);
     242             : 
     243             :         // check to make sure the read value matches one of the inpus
     244          49 :         bool ok = false;
     245         210 :         for (unsigned int i = 0; i < possiblecharvals.size(); i++)
     246             :         {
     247         161 :             if (value == std::string(possiblecharvals[i])) ok = true;
     248             :         }
     249             :         
     250          49 :         if (ok) return retval;
     251             : 
     252           0 :         std::stringstream ss;
     253           0 :         ss << possiblecharvals[0];
     254           0 :         for (unsigned int i = 1; i < possiblecharvals.size(); i++)
     255           0 :             ss << "," << possiblecharvals[i];
     256             : 
     257           0 :         Util::ParmParseException(INFO,file,func,line,full(name),"' expected [", ss.str(), "] but got ", value);
     258             : 
     259           0 :         return -1;
     260             :     }
     261             : 
     262          49 :     int query_validate( std::string name, std::string & value, std::vector<const char *> possiblecharvals,
     263             :                         std::string file = "", std::string func = "", int line = -1)
     264             :     {
     265          49 :         return query_validate(name,value,possiblecharvals,true,file,func,line);
     266             :     }
     267             : 
     268             :     
     269             :     // special case for strings
     270          31 :     int query_default(  std::string name, std::string & value, const char *defaultvalue,
     271             :                         std::string file = "", std::string func = "", int line = -1)
     272             :     {
     273          31 :         return query_default(name, value, std::string(defaultvalue), file, func, line);
     274             :     }
     275             :     // special case for bools
     276           6 :     int query_default(  std::string name, int & value, bool defaultvalue,
     277             :                         std::string file = "", std::string func = "query_default", int line = -1)
     278             :     {
     279           6 :         int defaultint = 0;
     280           6 :         if (defaultvalue) defaultint = 1;
     281           6 :         return query_default(name, value, defaultint, file, func, line);
     282             :     }
     283             : 
     284             : 
     285             : 
     286             :     // validate filenames
     287           2 :     int query_file( std::string name, std::string & value, bool copyfile, bool checkfile,
     288             :                     std::string file = "", std::string func = "query_file", int line = -1)
     289             :     {
     290             :         try
     291             :         {
     292           2 :             if (!contains(name.c_str()))
     293             :             {
     294           0 :                 Util::ParmParseException(INFO,file,func,line,full(name),full(name)," must be specified");
     295             :             }
     296             : 
     297           2 :             int retval = query(name.c_str(),value);
     298             : 
     299           2 :             if (amrex::ParallelDescriptor::IOProcessor())
     300             :             {
     301           2 :                 if ( checkfile && ! std::filesystem::exists(value))
     302             :                 {
     303           0 :                     Util::ParmParseException(INFO,file,func,line,full(name),full(name)," does not exist");
     304             :                 }
     305           2 :                 if ( checkfile && !std::filesystem::is_regular_file(value))
     306             :                 {
     307           0 :                     Util::ParmParseException(INFO,file,func,line,full(name),full(name)," is not a regular file");
     308             :                 }
     309           2 :                 if ( copyfile )
     310             :                 {
     311           2 :                     Util::CopyFileToOutputDir(value, true, full(name));
     312             :                 }
     313             :             }
     314           2 :             return retval;
     315             :         }
     316           0 :         catch (...)
     317             :         {
     318           0 :             Util::ParmParseException(INFO,file,func,line,full(name));
     319             :         }
     320           0 :         return -1;
     321             :     }
     322             :     int query_file( std::string name, std::string & value, bool copyfile, 
     323             :                     std::string file = "", std::string func = "query_file", int line = -1)
     324             :     {
     325             :         return query_file(name,value,copyfile,true,file,func,line);
     326             :     }
     327           2 :     int query_file( std::string name, std::string & value, 
     328             :                     std::string file = "", std::string func = "query_file", int line = -1)
     329             :     {
     330           2 :         return query_file(name,value,true,true,file,func,line);
     331             :     }
     332             : 
     333             : 
     334             :     template<typename T>
     335         310 :     int queryarr(   std::string name, std::vector<T> & value,
     336             :                     std::string /*file*/, std::string /*func*/, int /*line*/)
     337             :     {
     338         310 :         return amrex::ParmParse::queryarr(name.c_str(),value);
     339             :     }
     340           9 :     int queryarr(   std::string name, Set::Vector & value,
     341             :                     std::string file = "", std::string func = "queryarr", int line = -1)
     342             :     {
     343           9 :         std::vector<Set::Scalar> vals;
     344           9 :         amrex::ParmParse::queryarr(name.c_str(), vals);
     345           9 :         if (vals.size() < AMREX_SPACEDIM) 
     346             :         {
     347           0 :             Util::ParmParseException(INFO,file,func,line,full(name),full(name)," requires at least ", AMREX_SPACEDIM, " arguments, got ",vals.size());
     348             :         }
     349          28 :         for (int i = 0; i < AMREX_SPACEDIM; i++) value(i) = vals[i];
     350          18 :         return 0;
     351             :     }
     352           6 :     int queryarr(   std::string name, Set::Matrix & value,
     353             :                     std::string file = "", std::string func = "queryarr", int line = -1)
     354             :     {
     355           6 :         std::vector<Set::Scalar> vals;
     356           6 :         amrex::ParmParse::queryarr(name.c_str(), vals);
     357           6 :         if (vals.size() == 9)
     358             :         {
     359             : #if AMREX_SPACEDIM==2
     360           4 :             Util::Warning(file,func,line,"Reading a 3D matrix (",full(name),")into a 2D code - some values will be ignored.");
     361           4 :             value(0,0) = vals[0];  value(0,1)= vals[1];
     362           4 :             value(1,0) = vals[3];  value(1,1)= vals[4];
     363             : #endif
     364             : #if AMREX_SPACEDIM==3
     365           2 :             value(0,0) = vals[0];  value(0,1)= vals[1];  value(0,2)= vals[2];
     366           2 :             value(1,0) = vals[3];  value(1,1)= vals[4];  value(1,2)= vals[5];
     367           2 :             value(2,0) = vals[6];  value(2,1)= vals[7];  value(2,2)= vals[8];
     368             : #endif
     369             :         }
     370           0 :         else if (vals.size() == 4)
     371             :         {
     372             : #if AMREX_SPACEDIM==2
     373           0 :             value(0,0) = vals[0];  value(0,1)= vals[1];
     374           0 :             value(1,0) = vals[2];  value(1,1)= vals[3];
     375             : #endif
     376             : #if AMREX_SPACEDIM==3
     377           0 :             Util::Warning(file,func,line,"Reading a 2D matrix (",full(name),")into a 3D code - remaining values will be set to zero.");
     378           0 :             value(0,0) = vals[0];  value(0,1)= vals[1];  value(0,2)= 0.0;
     379           0 :             value(1,0) = vals[2];  value(1,1)= vals[3];  value(1,2)= 0.0;
     380           0 :             value(2,0) = 0.0;      value(2,1)= 0.0;      value(2,2)= 0.0;
     381             : #endif
     382             :         }
     383             :         else
     384             :         {
     385           0 :             Util::ParmParseException(INFO,file,func,line,full(name),full(name)," needs either 4 or 9 components, but got ",vals.size());
     386             :         }    
     387          12 :         return 0;
     388             :     }
     389             :     template<typename T>
     390           9 :     int queryarr_required(   std::string name, std::vector<T> & value,
     391             :                     std::string file, std::string func, int line)
     392             :     {
     393           9 :         if (!contains(name.c_str()))
     394             :         {
     395           0 :             Util::ParmParseException(INFO,file,func,line,full(name),"required value for ",full(name)," missing");
     396             :         }        
     397           9 :         return queryarr(name,value,file,func,line);
     398             :     }
     399             : 
     400             :     int AnyUnusedInputs()
     401             :     {
     402             :         int cnt = 0;
     403             :         for (auto li = m_table->begin(), End = m_table->end(); li != End; ++li)
     404             :         {
     405             :             if (!li->second.m_count && li->first.rfind(getPrefix()+".",0) != std::string::npos)
     406             :             {
     407             :                 Util::Warning(INFO,li->first);
     408             :                 cnt++;
     409             :             }
     410             :         }
     411             :         return cnt;
     412             :     }
     413             : 
     414         117 :     std::vector<std::string> GetUnusedInputs()
     415             :     {
     416         117 :         std::vector<std::string> ret;
     417       14995 :         for (auto li = m_table->begin(), End = m_table->end(); li != End; ++li)
     418             :         {
     419       14878 :             if (!li->second.m_count && li->first.rfind(getPrefix()+".",0) != std::string::npos)
     420             :             {
     421           0 :                 ret.push_back(li->first);
     422             :             }
     423             :         }
     424         117 :         return ret;
     425             :     }
     426             : 
     427             :     static int AllUnusedInputs()
     428             :     {
     429             :         ParmParse pp;
     430             :         int cnt = 0;
     431             :         for (auto li = pp.m_table->begin(), End = pp.m_table->end(); li != End; ++li)
     432             :         {
     433             :             if (!li->second.m_count)
     434             :             {
     435             :                 Util::Warning(INFO,li->first);
     436             :                 cnt++;
     437             :             }
     438             :         }
     439             :         return cnt;
     440             :     }
     441           0 :     std::string prefix ()
     442             :     {
     443           0 :         return getPrefix();
     444             :     }
     445        2284 :     std::string full (std::string name)
     446             :     {
     447        4568 :         std::string prefix = getPrefix();
     448        3475 :         if (prefix != "") return getPrefix() + "." + name;
     449        1093 :         else return name;
     450             :     }
     451             : 
     452             : 
     453             :     using amrex::ParmParse::queryarr;
     454             :     template<class T>
     455             :     void queryclass(std::string name, T * value,
     456             :                     std::string file = "", std::string func = "", int line = -1)
     457             :     {
     458             :         auto old_prefix = m_prefix;
     459             :         try
     460             :         {
     461             :             if (old_prefix.empty()) m_prefix = name;
     462             :             else m_prefix.append(".").append(name);
     463             :             T::Parse(*value, *this);
     464             :             std::vector<std::string> unused_inputs = GetUnusedInputs();
     465             :             if (unused_inputs.size())
     466             :             {
     467             :                 std::stringstream ss;
     468             :                 for (unsigned int i=0; i < unused_inputs.size(); i++)
     469             :                     ss << "\n\t" << unused_inputs[i];
     470             :                 Util::ParmParseException(INFO,file,func,line,name,"The following inputs were specified but not used",ss.str());
     471             :             }
     472             :         }
     473             :         catch (...)
     474             :         {
     475             :             m_prefix = old_prefix;
     476             :             Util::ParmParseException(INFO,file,func,line,full(name));
     477             :         }
     478             :         m_prefix = old_prefix;
     479             :     }
     480             :     template<class T>
     481         117 :     void queryclass(std::string name, T & value,
     482             :                     std::string file = "", std::string func = "", int line = __LINE__)
     483             :     {
     484         234 :         auto old_prefix = m_prefix;
     485             :         try
     486             :         {
     487         117 :             if (old_prefix.empty()) m_prefix = name;
     488           0 :             else m_prefix.append(".").append(name);
     489         117 :             T::Parse(value, *this);
     490         234 :             std::vector<std::string> unused_inputs = GetUnusedInputs();
     491         117 :             if (unused_inputs.size())
     492             :             {
     493           0 :                 std::stringstream ss;
     494           0 :                 for (unsigned int i=0; i < unused_inputs.size(); i++)
     495           0 :                     ss << "\n\t" << unused_inputs[i];
     496           0 :                 Util::ParmParseException(INFO,file,func,line,name,"The following inputs were specified but not used",ss.str());
     497             :             }
     498             :         }
     499           0 :         catch (...)
     500             :         {
     501           0 :             m_prefix = old_prefix;
     502           0 :             Util::ParmParseException(INFO,file,func,line,full(name));
     503             :         }
     504         117 :         m_prefix = old_prefix;
     505         117 :     }
     506             :     template<class T>
     507             :     void queryclass(T * value,
     508             :                     std::string file = "", std::string func = "", int line = __LINE__)
     509             :     {
     510             :         try
     511             :         {
     512             :             T::Parse(*value, *this);
     513             :         }
     514             :         catch (...)
     515             :         {
     516             :             Util::ParmParseException(INFO,file,func,line,getPrefix());
     517             :         }
     518             :     }
     519             :     template<class T>
     520         450 :     void queryclass(T & value,
     521             :                     std::string file = "", std::string func = "", int line = __LINE__)
     522             :     {
     523             :         try
     524             :         {
     525         450 :             T::Parse(value, *this);
     526             :         }
     527           0 :         catch (...)
     528             :         {
     529           0 :             Util::ParmParseException(INFO,file,func,line,getPrefix());
     530             :         }
     531         450 :     }    
     532             : 
     533             :     template<typename... IC, typename... Args, typename PTRTYPE>
     534          45 :     void select (std::string name, PTRTYPE *& ic_eta, Args&&... args)
     535             :     {
     536          90 :         std::string type = "";
     537             : 
     538          45 :         this->query_required(name + ".type", type);
     539             :         
     540         114 :         bool matched = ((type == IC::name 
     541          69 :                         ? (ic_eta = new IC(std::forward<Args>(args)..., (*this), name + "." + std::string(IC::name))),
     542             :                         true
     543             :                         : false) || ...);
     544          45 :         if (!matched)
     545           0 :             Util::Exception(INFO,type," not a valid type for ",name);
     546          45 :     }
     547             : };
     548             : }
     549             : #endif

Generated by: LCOV version 1.14