LCOV - code coverage report
Current view: top level - include/parser - ParameterRegistration.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: a4781e Lines: 88 88 100.0 %
Date: 2025-09-23 09:14:59 Functions: 139 225 61.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #pragma once
      11             : 
      12             : #include <vector>
      13             : #include <map>
      14             : #include <string>
      15             : 
      16             : #include "hit/hit.h"
      17             : 
      18             : #include "MooseUtils.h"
      19             : 
      20             : #define combineParamNames1(X, Y) X##Y
      21             : #define combineParamNames(X, Y) combineParamNames1(X, Y)
      22             : 
      23             : /// Macro for registering a scalar parameter using the setScalarValue helper
      24             : #define registerScalarParameter(type)                                                              \
      25             :   static char combineParamNames(dummyvar_reg_param, __COUNTER__) =                                 \
      26             :       Moose::ParameterRegistry::get().add<type>(                                                   \
      27             :           [](type & value, const hit::Field & field)                                               \
      28             :           { Moose::ParameterRegistration::setScalarValue<type>(value, field); })
      29             : /// Macro for registering a vector parameter using the setVectorValue helper
      30             : #define registerVectorParameter(type)                                                              \
      31             :   static char combineParamNames(dummyvar_reg_param, __COUNTER__) =                                 \
      32             :       Moose::ParameterRegistry::get().add<std::vector<type>>(                                      \
      33             :           [](std::vector<type> & value, const hit::Field & field)                                  \
      34             :           { Moose::ParameterRegistration::setVectorValue<type>(value, field); })
      35             : /// Macro for registering a double vector parameter using the setDoubleVectorValue helper
      36             : #define registerDoubleVectorParameter(type)                                                        \
      37             :   static char combineParamNames(dummyvar_reg_param, __COUNTER__) =                                 \
      38             :       Moose::ParameterRegistry::get().add<std::vector<std::vector<type>>>(                         \
      39             :           [](std::vector<std::vector<type>> & value, const hit::Field & field)                     \
      40             :           { Moose::ParameterRegistration::setDoubleVectorValue<type>(value, field); })
      41             : /// Macro for registering a double vector parameter using the setTripleVectorValue helper
      42             : #define registerTripleVectorParameter(type)                                                        \
      43             :   static char combineParamNames(dummyvar_reg_param, __COUNTER__) =                                 \
      44             :       Moose::ParameterRegistry::get().add<std::vector<std::vector<std::vector<type>>>>(            \
      45             :           [](std::vector<std::vector<std::vector<type>>> & value, const hit::Field & field)        \
      46             :           { Moose::ParameterRegistration::setTripleVectorValue<type>(value, field); })
      47             : /// Macro for registering a scalar, vector, double vector, and triple vector parameter
      48             : #define registerParameter(type)                                                                    \
      49             :   registerScalarParameter(type);                                                                   \
      50             :   registerVectorParameter(type);                                                                   \
      51             :   registerDoubleVectorParameter(type);                                                             \
      52             :   registerTripleVectorParameter(type)
      53             : /// Macro for registering a map parameter of the given type using the setMapValue helper
      54             : #define registerMapParameter(key_type, value_type)                                                 \
      55             :   static char combineParamNames(dummyvar_reg_param, __COUNTER__) =                                 \
      56             :       Moose::ParameterRegistry::get().add<std::map<key_type, value_type>>(                         \
      57             :           [](std::map<key_type, value_type> & value, const hit::Field & field)                     \
      58             :           { Moose::ParameterRegistration::setMapValue<key_type, value_type>(value, field); })
      59             : 
      60             : namespace Moose::ParameterRegistration
      61             : {
      62             : 
      63             : /**
      64             :  * Converts the given field node into a scalar of the given type.
      65             :  */
      66             : template <class T>
      67             : void setScalarValue(T & value, const hit::Field & field);
      68             : 
      69             : /**
      70             :  * Converts the given field node into a vector of the given type.
      71             :  */
      72             : template <class T>
      73             : void setVectorValue(std::vector<T> & value, const hit::Field & field);
      74             : 
      75             : /**
      76             :  * Converts the given field node into a vector-of-vectors of the given type.
      77             :  */
      78             : template <class T>
      79             : void setDoubleVectorValue(std::vector<std::vector<T>> & value, const hit::Field & field);
      80             : 
      81             : /**
      82             :  * Converts the given field node into a triple-indexed vector of the given type.
      83             :  */
      84             : template <class T>
      85             : void setTripleVectorValue(std::vector<std::vector<std::vector<T>>> & value,
      86             :                           const hit::Field & field);
      87             : 
      88             : /**
      89             :  * Converts the given field node into a map with the given types.
      90             :  */
      91             : template <class Key, class Value>
      92             : void setMapValue(std::map<Key, Value> & value, const hit::Field & field);
      93             : 
      94             : /// setScalarValue specialiation for bool
      95             : template <>
      96             : void setScalarValue(bool & value, const hit::Field & field);
      97             : 
      98             : template <class T>
      99             : void
     100     1541307 : setScalarValue(T & value, const hit::Field & field)
     101             : {
     102     3082614 :   const auto strval = field.param<std::string>();
     103             :   if constexpr (std::is_base_of_v<std::string, T>)
     104             :   {
     105     1112733 :     value = strval;
     106             :   }
     107             :   else
     108             :   {
     109      428574 :     if (!MooseUtils::convert<T>(strval, value, false))
     110           5 :       throw std::invalid_argument("invalid syntax for " + MooseUtils::prettyCppType<T>() +
     111             :                                   " parameter: " + field.fullpath() + "='" + strval + "'");
     112             :   }
     113     1541307 : }
     114             : 
     115             : template <class T>
     116             : void
     117      440408 : setVectorValue(std::vector<T> & value, const hit::Field & field)
     118             : {
     119      440408 :   value.clear();
     120      880816 :   const auto base_values = field.param<std::vector<std::string>>();
     121             :   if constexpr (std::is_base_of_v<std::string, T>)
     122             :   {
     123      371317 :     std::copy(base_values.begin(), base_values.end(), std::back_inserter(value));
     124             :   }
     125             :   else
     126             :   {
     127       69091 :     value.resize(base_values.size());
     128      215617 :     for (const auto i : index_range(base_values))
     129             :     {
     130             :       if constexpr (std::is_same_v<bool, T>)
     131             :       {
     132        2287 :         if (base_values[i] == "1")
     133             :         {
     134          20 :           value[i] = true;
     135          20 :           continue;
     136             :         }
     137        2267 :         else if (base_values[i] == "0")
     138             :         {
     139          20 :           value[i] = false;
     140          20 :           continue;
     141             :         }
     142        2247 :         else if (bool bool_val; hit::toBool(base_values[i], &bool_val))
     143             :         {
     144        2147 :           value[i] = bool_val;
     145        2147 :           continue;
     146             :         }
     147             :       }
     148             :       else
     149             :       {
     150      144340 :         if (MooseUtils::convert<T>(base_values[i], value[i], false))
     151      144339 :           continue;
     152             :       }
     153             : 
     154         202 :       throw std::invalid_argument("invalid syntax for " + MooseUtils::prettyCppType<T>() +
     155             :                                   " vector parameter: " + field.fullpath() + "[" +
     156         101 :                                   std::to_string(i) + "]='" + base_values[i] + "'");
     157             :     }
     158             :   }
     159      440408 : }
     160             : 
     161             : template <class T>
     162             : void
     163        5693 : setDoubleVectorValue(std::vector<std::vector<T>> & value, const hit::Field & field)
     164             : {
     165        5693 :   value.clear();
     166       17079 :   const auto strval = MooseUtils::trim(field.param<std::string>());
     167        5693 :   if (strval.empty())
     168          29 :     return;
     169             : 
     170             :   // split vector on ";" (the substrings are _not_ of type T yet)
     171             :   // The zero length here is intentional, as we want something like:
     172             :   // "abc; 123;" -> ["abc", "123", ""]
     173       11328 :   const auto tokens = MooseUtils::split(strval, ";");
     174             : 
     175        5664 :   value.resize(tokens.size());
     176       15746 :   for (const auto i : index_range(tokens))
     177             :   {
     178       20164 :     const auto token = MooseUtils::trim(tokens[i]);
     179       20164 :     if (!MooseUtils::tokenizeAndConvert<T>(token, value[i]))
     180           1 :       throw std::invalid_argument("invalid syntax for " + MooseUtils::prettyCppType<T>() +
     181             :                                   " double vector parameter: " + field.fullpath() + "[" +
     182             :                                   std::to_string(i) + "]='" + token + "'");
     183             :   }
     184        5694 : }
     185             : 
     186             : template <class T>
     187             : void
     188         637 : setTripleVectorValue(std::vector<std::vector<std::vector<T>>> & value, const hit::Field & field)
     189             : {
     190         637 :   value.clear();
     191        1274 :   const auto value_string = field.param<std::string>();
     192         637 :   if (value_string.find_first_not_of(' ', 0) == std::string::npos)
     193           1 :     return;
     194             : 
     195             :   // Add a space between neighboring delim's, before the first delim if nothing is ahead of it, and
     196             :   // after the last delim if nothing is behind it.
     197         636 :   std::string buffer;
     198         636 :   buffer.push_back(value_string[0]);
     199         636 :   if (buffer[0] == '|' || buffer[0] == ';')
     200          39 :     buffer = ' ' + buffer;
     201       78623 :   for (std::string::size_type i = 1; i < value_string.size(); i++)
     202             :   {
     203       77987 :     const auto val = value_string[i];
     204       77987 :     const auto last_val = value_string[i - 1];
     205       77987 :     if ((last_val == '|' || last_val == ';') && (val == '|' || val == ';'))
     206          91 :       buffer.push_back(' ');
     207       77987 :     buffer.push_back(val);
     208             :   }
     209         636 :   if (buffer.back() == '|' || buffer.back() == ';')
     210          17 :     buffer.push_back(' ');
     211             : 
     212             :   // split vector at delim | to get a series of 2D subvectors
     213         636 :   std::vector<std::string> outer_tokens;
     214         636 :   MooseUtils::tokenize(buffer, outer_tokens, 1, "|");
     215         636 :   value.resize(outer_tokens.size());
     216        3501 :   for (const auto i : index_range(outer_tokens))
     217             :   {
     218        1474 :     const auto & inner_token = outer_tokens[i];
     219        1474 :     auto & inner_value = value[i];
     220             : 
     221             :     // Identify empty subvector first
     222        1474 :     if (inner_token.find_first_not_of(' ', 0) == std::string::npos)
     223             :     {
     224             :       mooseAssert(inner_value.empty(), "Should be empty");
     225          82 :       continue;
     226             :     }
     227             : 
     228             :     // split each 2D subvector at delim ; to get 1D sub-subvectors
     229             :     // NOTE: the 1D sub-subvectors are _not_ of type T yet
     230        1392 :     std::vector<std::string> inner_tokenized;
     231        1392 :     MooseUtils::tokenize(inner_token, inner_tokenized, 1, ";");
     232        1392 :     inner_value.resize(inner_tokenized.size());
     233        4824 :     for (const auto j : index_range(inner_tokenized))
     234             :     {
     235        6864 :       const auto token = MooseUtils::trim(inner_tokenized[j]);
     236        6864 :       if (!MooseUtils::tokenizeAndConvert<T>(token, inner_value[j]))
     237           1 :         throw std::invalid_argument("invalid syntax for " + MooseUtils::prettyCppType<T>() +
     238             :                                     " triple vector parameter: " + field.fullpath() + "[" +
     239             :                                     std::to_string(i) + "][" + std::to_string(j) + "]='" + token +
     240             :                                     "'");
     241             :     }
     242             :   }
     243         639 : }
     244             : 
     245             : template <class Key, class Value>
     246             : void
     247         455 : setMapValue(std::map<Key, Value> & value, const hit::Field & field)
     248             : {
     249         455 :   value.clear();
     250             : 
     251         910 :   const auto string_vec = field.param<std::vector<std::string>>();
     252         455 :   auto it = string_vec.begin();
     253        2378 :   while (it != string_vec.end())
     254             :   {
     255        1006 :     const auto & string_key = *(it++);
     256        1006 :     if (it == string_vec.end())
     257           1 :       throw std::invalid_argument(
     258             :           "odd number of entries for map parameter '" + field.fullpath() +
     259             :           "'; there must be an even number or else you will end up with a key without a value");
     260        1005 :     const auto & string_value = *(it++);
     261             : 
     262        1005 :     std::pair<Key, Value> pr;
     263             : 
     264             :     // convert key
     265        1005 :     if (!MooseUtils::convert<Key>(string_key, pr.first, false))
     266           1 :       throw std::invalid_argument("invalid " + MooseUtils::prettyCppType<Key>() +
     267             :                                   " syntax for map parameter '" + field.fullpath() + "' key: '" +
     268             :                                   string_key + "'");
     269             : 
     270             :     // convert value
     271        1004 :     if (!MooseUtils::convert<Value>(string_value, pr.second, false))
     272           1 :       throw std::invalid_argument("invalid " + MooseUtils::prettyCppType<Value>() +
     273             :                                   " syntax for map parameter '" + field.fullpath() + "' value: '" +
     274             :                                   string_value + "'");
     275             :     // attempt insert
     276        1003 :     if (!value.insert(std::move(pr)).second)
     277           1 :       throw std::invalid_argument("duplicate entry for map parameter: '" + field.fullpath() +
     278             :                                   "'; key '" + string_key + "' appears multiple times");
     279             :   }
     280         455 : }
     281             : 
     282             : } // end of namespace Moose::ParameterRegistration

Generated by: LCOV version 1.14