LCOV - code coverage report
Current view: top level - conffwk/src - ConfigurationImpl.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 37.7 % 297 112
Test Date: 2026-07-12 15:23:06 Functions: 38.6 % 57 22

            Line data    Source code
       1              : //
       2              : // DUNE DAQ modification notice:
       3              : // This file has been modified from the original ATLAS config source for the DUNE DAQ project.
       4              : // Fork baseline commit: 67a24e731 (2022-10-27).
       5              : // Renamed since fork: no.
       6              : //
       7              : 
       8              : #include <stdlib.h>
       9              : 
      10              : #include "conffwk/Configuration.hpp"
      11              : #include "conffwk/ConfigurationImpl.hpp"
      12              : #include "conffwk/Schema.hpp"
      13              : 
      14              : namespace dunedaq {
      15              :   namespace conffwk {
      16              : 
      17            0 :     const char * bool2str(bool value) { return (value ? "yes" : "no"); }
      18              : 
      19        17327 :     attribute_t::attribute_t(
      20              :       const std::string& name, type_t type, const std::string& range,
      21              :       int_format_t int_format, bool is_not_null, bool is_multi_value,
      22              :       const std::string& default_value, const std::string& description
      23        17327 :     ) :
      24        17327 :       p_name             (name),
      25        17327 :       p_type             (type),
      26        17327 :       p_range            (range),
      27        17327 :       p_int_format       (int_format),
      28        17327 :       p_is_not_null      (is_not_null),
      29        17327 :       p_is_multi_value   (is_multi_value),
      30        17327 :       p_default_value    (default_value),
      31        17327 :       p_description      (description)
      32        17327 :     { ; }
      33              : 
      34            0 :     const char * attribute_t::type2str(type_t type)
      35              :     {
      36            0 :       switch(type) {
      37              :         case bool_type:   return "boolean";
      38            0 :         case s8_type:     return "8-bits signed integer";
      39            0 :         case u8_type:     return "8-bits unsigned integer";
      40            0 :         case s16_type:    return "16-bits signed integer";
      41            0 :         case u16_type:    return "16-bits unsigned integer";
      42            0 :         case s32_type:    return "32-bits signed integer";
      43            0 :         case u32_type:    return "32-bits unsigned integer";
      44            0 :         case s64_type:    return "64-bits signed integer";
      45            0 :         case u64_type:    return "64-bits unsigned integer";
      46            0 :         case float_type:  return "float";
      47            0 :         case double_type: return "double";
      48            0 :         case date_type:   return "date";
      49            0 :         case time_type:   return "time";
      50            0 :         case string_type: return "string";
      51            0 :         case enum_type:   return "enumeration";
      52            0 :         case class_type:  return "class reference";
      53            0 :         default:          return "unknown";
      54              :       }
      55              :     }
      56              : 
      57            0 :     const char * attribute_t::type(type_t type)
      58              :     {
      59            0 :       switch(type) {
      60              :         case bool_type:   return "bool";
      61            0 :         case s8_type:     return "s8";
      62            0 :         case u8_type:     return "u8";
      63            0 :         case s16_type:    return "s16";
      64            0 :         case u16_type:    return "u16";
      65            0 :         case s32_type:    return "s32";
      66            0 :         case u32_type:    return "u32";
      67            0 :         case s64_type:    return "s64";
      68            0 :         case u64_type:    return "u64";
      69            0 :         case float_type:  return "float";
      70            0 :         case double_type: return "double";
      71            0 :         case date_type:   return "date";
      72            0 :         case time_type:   return "time";
      73            0 :         case string_type: return "string";
      74            0 :         case enum_type:   return "enum";
      75            0 :         case class_type:  return "class";
      76            0 :         default:          return "unknown";
      77              :       }
      78              :     }
      79              : 
      80            0 :     const char * attribute_t::format2str(int_format_t type)
      81              :     {
      82            0 :       switch(type) {
      83              :         case oct_int_format:   return "octal";
      84            0 :         case dec_int_format:   return "decimal";
      85            0 :         case hex_int_format:   return "hexadecimal";
      86            0 :         default:               return "not applicable";
      87              :       }
      88              :     }
      89              : 
      90            0 :     void attribute_t::print(std::ostream& out, const std::string& prefix) const
      91              :     {
      92            0 :       out
      93            0 :         << prefix << "attribute \'" << p_name << "\'\n"
      94            0 :         << prefix << "  type: \'" << type2str(p_type) << "\'\n"
      95            0 :         << prefix << "  range: \'" << p_range << "\'\n";
      96              : 
      97            0 :       if(p_int_format != na_int_format) {
      98            0 :         out << prefix << "  integer format: \'" << format2str(p_int_format) << "\'\n";
      99              :       }
     100              : 
     101            0 :       out
     102            0 :         << prefix << "  is not null: " << bool2str(p_is_not_null) << '\n'
     103            0 :         << prefix << "  is multi-value: " << bool2str(p_is_multi_value) << '\n'
     104            0 :         << prefix << "  default value: \'" << p_default_value << "\'\n"
     105            0 :         << prefix << "  description: \'" << p_description << '\'';
     106            0 :     }
     107              :     
     108            0 :     std::ostream& operator<<(std::ostream& out, const attribute_t& a)
     109              :     {
     110            0 :       a.print(out);
     111            0 :       return out;
     112              :     }
     113              : 
     114              : 
     115        12071 :     relationship_t::relationship_t(
     116              :       const std::string& name, const std::string& type, bool can_be_null,
     117              :       bool is_multi_value, bool is_aggregation, const std::string& description
     118        12071 :     ) :
     119        12071 :       p_name             (name),
     120        12071 :       p_type             (type),
     121        12071 :       p_cardinality      (
     122        12071 :                             (can_be_null  && !is_multi_value) ? zero_or_one  :
     123        10906 :                             (can_be_null  && is_multi_value ) ? zero_or_many :
     124         4359 :                             (!can_be_null && is_multi_value ) ? one_or_many  :
     125              :                             only_one
     126              :                          ),
     127        12071 :       p_is_aggregation   (is_aggregation),
     128        12071 :       p_description      (description)
     129        12071 :     { ; }
     130              :     
     131            0 :     const char * relationship_t::card2str(cardinality_t cardinality)
     132              :     {
     133            0 :       switch(cardinality) {
     134              :         case zero_or_one:    return "zero or one";
     135            0 :         case zero_or_many:   return "zero or many";
     136            0 :         case only_one:       return "one";
     137            0 :         case one_or_many:    return "one or many";
     138            0 :         default:             return "unknown";
     139              :       }
     140              :     }
     141              : 
     142            0 :     void relationship_t::print(std::ostream& out, const std::string& prefix) const
     143              :     {
     144            0 :       out
     145            0 :         << prefix << "relationship \'" << p_name << "\'\n"
     146            0 :         << prefix << "  class type: \'" << p_type << "\'\n"
     147            0 :         << prefix << "  cardinality: \'" << card2str(p_cardinality) << "\'\n"
     148            0 :         << prefix << "  is aggregation: \'" << bool2str(p_is_aggregation) << "\'\n"
     149            0 :         << prefix << "  description: \'" << p_description << '\'';
     150            0 :     }
     151              : 
     152            0 :     std::ostream& operator<<(std::ostream& out, const relationship_t& r)
     153              :     {
     154            0 :       r.print(out);
     155            0 :       return out;
     156              :     }
     157              : 
     158         6519 :     class_t::class_t(
     159              :       const std::string& name,
     160              :       const std::string& description,
     161              :       const std::string& schema_path,
     162              :       bool is_abstract
     163         6519 :     ) :
     164         6519 :     p_name             (name),
     165         6519 :     p_description      (description),
     166         6519 :     p_schema_path      (schema_path),
     167         6519 :     p_abstract         (is_abstract)
     168         6519 :     { ; }
     169              : 
     170            0 :     void class_t::print(std::ostream& out, const std::string& prefix) const
     171              :     {
     172            0 :       out
     173            0 :         << prefix << "class \'" << p_name << "\'\n"
     174            0 :         << prefix << "  is abstract: \'" << bool2str(p_abstract) << "\'\n"
     175            0 :         << prefix << "  description: \'" << p_description << "\'\n"
     176            0 :         << prefix << "  path: \'" << p_schema_path << "\'\n";
     177              : 
     178            0 :       if(p_superclasses.empty()) {
     179            0 :         out << prefix << "  there are no superclasses\n";
     180              :       }
     181              :       else {
     182            0 :         out << prefix << "  " << p_superclasses.size() << " superclass(es):\n";
     183            0 :         for(std::vector<std::string>::const_iterator i = p_superclasses.begin(); i != p_superclasses.end(); ++i) {
     184            0 :           out << prefix << "    \'" << *i << "\'\n";
     185              :         }
     186              :       }
     187              : 
     188            0 :       if(p_subclasses.empty()) {
     189            0 :         out << prefix << "  there are no subclasses\n";
     190              :       }
     191              :       else {
     192            0 :         out << prefix << "  " << p_subclasses.size() << " subclass(es):\n";
     193            0 :         for(std::vector<std::string>::const_iterator i = p_subclasses.begin(); i != p_subclasses.end(); ++i) {
     194            0 :           out << prefix << "    \'" << *i << "\'\n";
     195              :         }
     196              :       }
     197              : 
     198            0 :       std::string new_prefix(prefix);
     199            0 :       new_prefix += "    ";
     200              : 
     201            0 :       if(p_attributes.empty()) {
     202            0 :         out << prefix << "  there are no attributes\n";
     203              :       }
     204              :       else {
     205            0 :         out << prefix << "  " << p_attributes.size() << " attribute(s):\n";
     206            0 :         for(std::vector<attribute_t>::const_iterator i = p_attributes.begin(); i != p_attributes.end(); ++i) {
     207            0 :           (*i).print(out, new_prefix.c_str());
     208            0 :           out << std::endl;
     209              :         }
     210              :       }
     211              : 
     212            0 :       if(p_relationships.empty()) {
     213            0 :         out << prefix << "  there are no relationships\n";
     214              :       }
     215              :       else {
     216            0 :         out << prefix << "  " << p_relationships.size() << " relationship(s):\n";
     217            0 :         for(std::vector<relationship_t>::const_iterator i = p_relationships.begin(); i != p_relationships.end(); ++i) {
     218            0 :           (*i).print(out, new_prefix.c_str());
     219            0 :           out << std::endl;
     220              :         }
     221              :       }
     222            0 :     }
     223              : 
     224            0 :     std::ostream& operator<<(std::ostream& out, const class_t& c)
     225              :     {
     226            0 :       c.print(out);
     227            0 :       return out;
     228              :     }
     229              : 
     230              : 
     231           87 : ConfigurationImpl::ConfigurationImpl() noexcept :
     232           87 :   p_number_of_cache_hits  (0),
     233           87 :   p_number_of_object_read (0),
     234           87 :   m_conf                  (0)
     235              : {
     236           87 : }
     237              : 
     238           87 : ConfigurationImpl::~ConfigurationImpl()
     239              : {
     240           87 :   clean();
     241           87 : }
     242              : 
     243              : void
     244            0 : ConfigurationImpl::print_cache_info() noexcept
     245              : {
     246            0 :   std::cout <<
     247              :     "Configuration implementation profiler report:\n"
     248            0 :     "  number of read objects: " << p_number_of_object_read << "\n"
     249            0 :     "  number of cache hits: " << p_number_of_cache_hits << std::endl;
     250            0 : }
     251              : 
     252              : ConfigObjectImpl *
     253         1408 : ConfigurationImpl::get_impl_object(const std::string& name, const std::string& id) const noexcept
     254              : {
     255              : 
     256         1408 :   conffwk::pmap<conffwk::map<ConfigObjectImpl *> *>::const_iterator i = m_impl_objects.find(&name);
     257              : 
     258         1408 :   const std::string * class_name = nullptr;
     259              : 
     260         1408 :   if(i != m_impl_objects.end()) {
     261          656 :     conffwk::map<ConfigObjectImpl *>::const_iterator j = i->second->find(id);
     262              : 
     263          656 :     if(j != i->second->end()) {
     264          179 :       p_number_of_cache_hits++;
     265          179 :       TLOG_DEBUG(4) << "\n  * found the object with id = \'" << id << "\' in class \'" << name << '\'' ;
     266          179 :       return j->second;
     267              :     }
     268              : 
     269          477 :     class_name = i->first;
     270              : 
     271              : 
     272              :       // prepare and print out debug message
     273              : 
     274          477 :     if(ers::debug_level() >= 4) {
     275           10 :       TLOG_DEBUG(40) << " * there is no object with id = \'" << id << "\' found in the class \'" << name
     276           10 :                      << "\' that has " << i->second->size() << " objects in cache: ";
     277           32 :       for(j=i->second->begin(); j != i->second->end();++j) {
     278           22 :         TLOG_DEBUG(40) << '\'' << j->first << '\'';
     279              :       }
     280              :     }
     281              : 
     282              :   }
     283              :   else {
     284          752 :     class_name = &DalFactory::instance().get_known_class_name_ref(name);
     285          752 :     TLOG_DEBUG(40) << "  * there is no object with id = \'" << id << "\' found in the class \'" << name
     286          752 :                    << "\' that has no objects in cache";
     287              :   }
     288              : 
     289              :     // check implementation objects of subclasses
     290              : 
     291         1229 :   if(m_conf) {
     292         1229 :     conffwk::fmap<conffwk::fset>::const_iterator subclasses = m_conf->subclasses().find(class_name);
     293              : 
     294         1229 :     if(subclasses != m_conf->subclasses().end()) {
     295          480 :       for(conffwk::fset::const_iterator k = subclasses->second.begin(); k != subclasses->second.end(); ++k) {
     296          324 :         i = m_impl_objects.find(*k);
     297          324 :         if(i != m_impl_objects.end()) {
     298            6 :           conffwk::map<ConfigObjectImpl *>::const_iterator j = i->second->find(id);
     299              : 
     300            6 :           if(j != i->second->end()) {
     301            0 :             p_number_of_cache_hits++;
     302            0 :             TLOG_DEBUG(40) << "  * found the object with id = \'" << id << "\' in class \'" << *k << '\'';
     303              : 
     304            0 :             return j->second;
     305              :           }
     306              : 
     307              : 
     308              :             // prepare and print out debug message
     309              : 
     310            6 :           else if(ers::debug_level() >= 4) {
     311            0 :             TLOG_DEBUG(40) << "  * there is no object with id = \'" << id << "\' found in the class \'" << *k
     312            0 :                            << "\' that has " << i->second->size() << " objects in cache: ";
     313            0 :             for(j=i->second->begin(); j != i->second->end();++j) {
     314            0 :               TLOG_DEBUG(40) << '\'' << j->first << '\'';
     315              :             }
     316              :           }
     317              : 
     318              : 
     319              :         }
     320              :         else {
     321          318 :           TLOG_DEBUG(40) << "  * there is no object with id = \'" << id << "\' found in the class \'" << *k
     322          318 :                          << "\' that has no objects in cache\n";
     323              :         }
     324              : 
     325              :       }
     326              :     }
     327              : 
     328         1229 :     TLOG_DEBUG(40) << "  * there is no object \'" << id << "\' in class \'" << name
     329         1229 :                    << "\' and it's subclasses, returning NULL ...";
     330              :   }
     331              :   else {
     332            0 :     TLOG_DEBUG(40) << "  * there is no object \'" << id << "\' in class \'" << name << "\', returning NULL ...";
     333              :   }
     334              : 
     335              :   return nullptr;
     336              : }
     337              : 
     338              : 
     339              : void
     340         1229 : ConfigurationImpl::put_impl_object(const std::string& name, const std::string& id, ConfigObjectImpl * obj) noexcept
     341              : {
     342         1229 :   p_number_of_object_read++;
     343              : 
     344         1229 :   conffwk::pmap<conffwk::map<ConfigObjectImpl *> * >::iterator i = m_impl_objects.find(&name);
     345              : 
     346         1229 :   if(i != m_impl_objects.end()) {
     347          477 :     (*i->second)[id] = obj;
     348          477 :     obj->m_class_name = i->first;
     349              :   }
     350              :   else {
     351          752 :     conffwk::map<ConfigObjectImpl *> * m = new conffwk::map<ConfigObjectImpl *>();
     352          752 :     obj->m_class_name = &DalFactory::instance().get_known_class_name_ref(name);
     353          752 :     m_impl_objects[obj->m_class_name] = m;
     354          752 :     (*m)[id] = obj;
     355              :   }
     356         1229 : }
     357              : 
     358              : void
     359            0 : ConfigurationImpl::rename_impl_object(const std::string * class_name, const std::string& old_id, const std::string& new_id) noexcept
     360              : {
     361            0 :   conffwk::pmap<conffwk::map<ConfigObjectImpl *> *>::iterator i = m_impl_objects.find(class_name);
     362              : 
     363            0 :   if (i != m_impl_objects.end())
     364              :     {
     365            0 :       conffwk::map<ConfigObjectImpl *>::iterator j = i->second->find(old_id);
     366              : 
     367            0 :       if (j != i->second->end())
     368              :         {
     369            0 :           ConfigObjectImpl*& obj = (*i->second)[new_id];
     370              : 
     371            0 :           if (obj != nullptr)
     372              :             {
     373            0 :               obj->m_state = dunedaq::conffwk::Unknown;
     374            0 :               m_tangled_objects.push_back(obj);
     375              :             }
     376              : 
     377            0 :           obj = j->second;
     378              : 
     379            0 :           TLOG_DEBUG(2) << "rename implementation " << (void *)j->second << " of object \'" << old_id << '@' << *class_name << "\' to \'" << new_id << '\'';
     380            0 :           i->second->erase(j);
     381              :         }
     382              :     }
     383            0 : }
     384              : 
     385              : void
     386          261 : ConfigurationImpl::clean() noexcept
     387              : {
     388         1013 :   for (auto& i : m_impl_objects)
     389              :     {
     390         1981 :       for (auto& j : *i.second)
     391         1229 :         delete j.second;
     392              : 
     393          752 :       delete i.second;
     394              :     }
     395              : 
     396          261 :   m_impl_objects.clear();
     397              : 
     398          261 :   for (auto& x : m_tangled_objects)
     399            0 :     delete x;
     400              : 
     401          261 :   m_tangled_objects.clear();
     402          261 : }
     403              : 
     404              : std::mutex&
     405            0 : ConfigurationImpl::get_conf_impl_mutex() const
     406              : {
     407            0 :   return m_conf->m_impl_mutex;
     408              : }
     409              : 
     410              : void
     411           75 : ConfigObjectImpl::convert(bool& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     412              : {
     413           75 :   m_impl->m_conf->convert(value, obj, attr_name);
     414           75 : }
     415              : 
     416              : void
     417            8 : ConfigObjectImpl::convert(uint8_t& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     418              : {
     419            8 :   m_impl->m_conf->convert(value, obj, attr_name);
     420            8 : }
     421              : 
     422              : void
     423            0 : ConfigObjectImpl::convert(int8_t& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     424              : {
     425            0 :   m_impl->m_conf->convert(value, obj, attr_name);
     426            0 : }
     427              : 
     428              : void
     429           37 : ConfigObjectImpl::convert(uint16_t& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     430              : {
     431           37 :   m_impl->m_conf->convert(value, obj, attr_name);
     432           37 : }
     433              : 
     434              : void
     435            0 : ConfigObjectImpl::convert(int16_t& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     436              : {
     437            0 :   m_impl->m_conf->convert(value, obj, attr_name);
     438            0 : }
     439              : 
     440              : void
     441         1235 : ConfigObjectImpl::convert(uint32_t& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     442              : {
     443         1235 :   m_impl->m_conf->convert(value, obj, attr_name);
     444         1235 : }
     445              : 
     446              : void
     447           85 : ConfigObjectImpl::convert(int32_t& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     448              : {
     449           85 :   m_impl->m_conf->convert(value, obj, attr_name);
     450           85 : }
     451              : 
     452              : void
     453            8 : ConfigObjectImpl::convert(uint64_t& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     454              : {
     455            8 :   m_impl->m_conf->convert(value, obj, attr_name);
     456            8 : }
     457              : 
     458              : void
     459            0 : ConfigObjectImpl::convert(int64_t& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     460              : {
     461            0 :   m_impl->m_conf->convert(value, obj, attr_name);
     462            0 : }
     463              : 
     464              : void
     465            0 : ConfigObjectImpl::convert(float& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     466              : {
     467            0 :   m_impl->m_conf->convert(value, obj, attr_name);
     468            0 : }
     469              : 
     470              : void
     471            0 : ConfigObjectImpl::convert(double& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     472              : {
     473            0 :   m_impl->m_conf->convert(value, obj, attr_name);
     474            0 : }
     475              : 
     476              : void
     477         1090 : ConfigObjectImpl::convert(std::string& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     478              : {
     479         1090 :   m_impl->m_conf->convert(value, obj, attr_name);
     480         1090 : }
     481              : 
     482              : 
     483              : void
     484            0 : ConfigObjectImpl::convert(std::vector<bool>& /*value*/, const ConfigObject& /*obj*/, const std::string& /*attr_name*/) noexcept
     485              : {
     486              :   //m_impl->m_conf->convert2(value, obj, attr_name);
     487            0 : }
     488              : 
     489              : void
     490            0 : ConfigObjectImpl::convert(std::vector<uint8_t>& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     491              : {
     492            0 :   m_impl->m_conf->convert2(value, obj, attr_name);
     493            0 : }
     494              : 
     495              : void
     496            0 : ConfigObjectImpl::convert(std::vector<int8_t>& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     497              : {
     498            0 :   m_impl->m_conf->convert2(value, obj, attr_name);
     499            0 : }
     500              : 
     501              : void
     502            0 : ConfigObjectImpl::convert(std::vector<uint16_t>& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     503              : {
     504            0 :   m_impl->m_conf->convert2(value, obj, attr_name);
     505            0 : }
     506              : 
     507              : void
     508            0 : ConfigObjectImpl::convert(std::vector<int16_t>& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     509              : {
     510            0 :   m_impl->m_conf->convert2(value, obj, attr_name);
     511            0 : }
     512              : 
     513              : void
     514            0 : ConfigObjectImpl::convert(std::vector<uint32_t>& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     515              : {
     516            0 :   m_impl->m_conf->convert2(value, obj, attr_name);
     517            0 : }
     518              : 
     519              : void
     520            0 : ConfigObjectImpl::convert(std::vector<int32_t>& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     521              : {
     522            0 :   m_impl->m_conf->convert2(value, obj, attr_name);
     523            0 : }
     524              : 
     525              : void
     526            0 : ConfigObjectImpl::convert(std::vector<uint64_t>& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     527              : {
     528            0 :   m_impl->m_conf->convert2(value, obj, attr_name);
     529            0 : }
     530              : 
     531              : void
     532            0 : ConfigObjectImpl::convert(std::vector<int64_t>& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     533              : {
     534            0 :   m_impl->m_conf->convert2(value, obj, attr_name);
     535            0 : }
     536              : 
     537              : void
     538            0 : ConfigObjectImpl::convert(std::vector<float>& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     539              : {
     540            0 :   m_impl->m_conf->convert2(value, obj, attr_name);
     541            0 : }
     542              : 
     543              : void
     544            0 : ConfigObjectImpl::convert(std::vector<double>& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     545              : {
     546            0 :   m_impl->m_conf->convert2(value, obj, attr_name);
     547            0 : }
     548              : 
     549              : void
     550           61 : ConfigObjectImpl::convert(std::vector<std::string>& value, const ConfigObject& obj, const std::string& attr_name) noexcept
     551              : {
     552           61 :   m_impl->m_conf->convert2(value, obj, attr_name);
     553           61 : }
     554              : 
     555              : } // namespace conffwk
     556              : } // namespace dunedaq
        

Generated by: LCOV version 2.0-1