MarlinMT  0.1.0
Configuration.cc
Go to the documentation of this file.
1 // -- marlinmt headers
3 #include <marlinmt/Parameter.h>
5 
6 // -- std headers
7 #include <algorithm>
8 #include <filesystem>
9 
10 namespace marlinmt {
11 
12  ConfigSection::ConfigSection( const std::string &name ) :
13  _name(name) {
14  /* nop */
15  }
16 
17  //--------------------------------------------------------------------------
18 
19  const std::string &ConfigSection::name() const {
20  return _name ;
21  }
22 
23  //--------------------------------------------------------------------------
24 
25  bool ConfigSection::empty() const {
26  return (_subsections.empty() && _parameters.empty() ) ;
27  }
28 
29  //--------------------------------------------------------------------------
30 
31  ConfigSection &ConfigSection::section( const std::string &n ) {
32  auto iter = _subsections.find( n ) ;
33  if( _subsections.end() == iter ) {
34  MARLINMT_THROW( "No sub-section '" + n + "' in section '" + name() + "'" ) ;
35  }
36  return iter->second ;
37  }
38 
39  //--------------------------------------------------------------------------
40 
41  const ConfigSection &ConfigSection::section( const std::string &n ) const {
42  auto iter = _subsections.find( n ) ;
43  if( _subsections.end() == iter ) {
44  MARLINMT_THROW( "No sub-section '" + n + "' in section '" + name() + "'" ) ;
45  }
46  return iter->second ;
47  }
48 
49  //--------------------------------------------------------------------------
50 
51  ConfigSection &ConfigSection::addSection( const std::string &n ) {
52  auto iter = _subsections.find( n ) ;
53  if( _subsections.end() != iter ) {
54  MARLINMT_THROW( "Sub-section '" + n + "' already present in section '" + name() + "'" ) ;
55  }
56  return _subsections.emplace( n, ConfigSection{n} ).first->second ;
57  }
58 
59  //--------------------------------------------------------------------------
60 
61  bool ConfigSection::hasSection( const std::string &n ) const {
62  return (_subsections.end() != _subsections.find( n )) ;
63  }
64 
65  //--------------------------------------------------------------------------
66 
67  std::vector<std::string> ConfigSection::subsectionNames() const {
68  std::vector<std::string> names( _subsections.size() ) ;
69  std::transform( _subsections.begin(), _subsections.end(), names.begin(), [] (const auto &iter) { return iter.first ; } ) ;
70  return names ;
71  }
72 
73  //--------------------------------------------------------------------------
74 
75  bool ConfigSection::hasParameter( const std::string &n ) const {
76  return (_parameters.end() != _parameters.find( n )) ;
77  }
78 
79  //--------------------------------------------------------------------------
80 
81  std::vector<std::string> ConfigSection::parameterNames() const {
82  std::vector<std::string> names( _parameters.size() ) ;
83  std::transform( _parameters.begin(), _parameters.end(), names.begin(), [] (const auto &iter) { return iter.first ; } ) ;
84  return names ;
85  }
86 
87  //--------------------------------------------------------------------------
88 
90  return _parameters ;
91  }
92 
93  //--------------------------------------------------------------------------
94 
96  return _metadata ;
97  }
98 
99  //--------------------------------------------------------------------------
100 
102  return _metadata ;
103  }
104 
105  //--------------------------------------------------------------------------
106  //--------------------------------------------------------------------------
107 
108  bool Configuration::hasConstant( const std::string &cn ) const {
109  return ( _constants.end() != _constants.find( cn ) ) ;
110  }
111 
112  //--------------------------------------------------------------------------
113 
115  return _constants ;
116  }
117 
118  //--------------------------------------------------------------------------
119 
120  ConfigSection &Configuration::createSection( const std::string &sn ) {
121  auto iter = _sections.find( sn ) ;
122  if( _sections.end() != iter ) {
123  MARLINMT_THROW( "Section '" + sn + "' already exists" ) ;
124  }
125  return _sections.emplace( sn, ConfigSection{sn} ).first->second ;
126  }
127 
128  //--------------------------------------------------------------------------
129 
130  ConfigSection &Configuration::section( const std::string &sn ) {
131  auto iter = _sections.find( sn ) ;
132  if( _sections.end() == iter ) {
133  MARLINMT_THROW( "Section '" + sn + "' doesn't exists" ) ;
134  }
135  return iter->second ;
136  }
137 
138  //--------------------------------------------------------------------------
139 
140  const ConfigSection &Configuration::section( const std::string &sn ) const {
141  auto iter = _sections.find( sn ) ;
142  if( _sections.end() == iter ) {
143  MARLINMT_THROW( "Section '" + sn + "' doesn't exists" ) ;
144  }
145  return iter->second ;
146  }
147 
148  //--------------------------------------------------------------------------
149 
150  std::vector<std::string> Configuration::sections() const {
151  return details::keys( _sections ) ;
152  }
153 
154  //--------------------------------------------------------------------------
155 
156  bool Configuration::hasSection( const std::string &n ) const {
157  return ( _sections.find( n ) != _sections.end()) ;
158  }
159 
160  //--------------------------------------------------------------------------
161 
162  void Configuration::replaceConstants( std::string& str ) const {
163  size_t pos = str.find("${") ;
164  while( pos != std::string::npos ) {
165  size_t pos2 = str.find_first_of( "}", pos+2 ) ;
166  if( pos2 == std::string::npos ) {
167  MARLINMT_THROW_T( ParseException, "Couldn't parse constant value in string '" + str + "'. It seems you have an open bracket '${' but it is not closed" ) ;
168  }
169  const std::string key( str.substr( pos+2 , pos2-pos-2 )) ;
170  auto iter = _constants.find( key ) ;
171  const std::string replacementValue( iter != _constants.end() ? iter->second : "" ) ;
172  if( replacementValue.empty() ) {
173  MARLINMT_THROW_T( ParseException, "Constant '" + key + "' doesn't exists !" ) ;
174  }
175  str.replace( pos , (pos2+1-pos) , replacementValue ) ;
176  pos2 = pos + replacementValue.size() ; // new end position after replace
177  pos = str.find("${", pos2) ; // find next possible key to replace
178  }
179  }
180 
181  //--------------------------------------------------------------------------
182 
183  void printSection( const ConfigSection &section, std::ostream &stream, const std::string &prefix ) {
184  std::string localprefix = prefix + " |";
185  stream << prefix << " + Section: " << section.name() << std::endl ;
186  auto pnames = section.parameterNames() ;
187  for( auto &pn : pnames ) {
188  stream << localprefix << " - " << pn << " = " << section.parameter<std::string>( pn ) << std::endl ;
189  }
190  auto sections = section.subsectionNames() ;
191  for( auto &sec : sections ) {
192  printSection( section.section( sec ), stream, localprefix ) ;
193  }
194  }
195 
196  std::ostream &operator<<( std::ostream &stream, const Configuration &cfg ) {
197  auto constants = cfg.constants() ;
198  if( not constants.empty() ) {
199  stream << "==== Constants =====" << std::endl ;
200  for( auto &kv : constants ) {
201  stream << " * " << kv.first << " : " << kv.second << std::endl ;
202  }
203  }
204  auto sections = cfg.sections() ;
205  for( auto &sec : sections ) {
206  printSection( cfg.section( sec ), stream, "" ) ;
207  }
208  return stream ;
209  }
210 
211  //--------------------------------------------------------------------------
212  //--------------------------------------------------------------------------
213 
214  std::pair<std::string, std::string> ConfigHelper::splitPluginInput( const std::string &str ) {
215  auto splitVals = details::split_string<std::string>( str, ":", 2 ) ;
216  return (2 == splitVals.size()) ? std::pair{ splitVals[0], splitVals[1] } : std::pair{ "", splitVals[0] } ;
217  }
218 
219  //--------------------------------------------------------------------------
220 
221  void ConfigHelper::readConfig( const std::string &str, Configuration &cfg ) {
222  auto pluginInput = ConfigHelper::splitPluginInput( str ) ;
223  // if no plugin guess it from the input string
224  if( pluginInput.first.empty() ) {
225  std::filesystem::path filepath = pluginInput.second ;
226  if( filepath.extension().string() == ".xml" ) {
227  pluginInput.first = "XMLConfigReader" ;
228  }
229  }
230  if( pluginInput.first.empty() ) {
231  MARLINMT_THROW( "No config reader plugin found in config string. Please specify your config as 'plugin_name:input'" ) ;
232  }
233  auto reader = PluginManager::instance().create<ConfigReader>( pluginInput.first ) ;
234  if( nullptr == reader ) {
235  MARLINMT_THROW( "No ConfigReader plugin found for type '" + pluginInput.first + "'" ) ;
236  }
237  reader->init( pluginInput.second ) ;
238  reader->read( cfg ) ;
239  }
240 
241  //--------------------------------------------------------------------------
242 
243  void ConfigHelper::writeConfig( const std::string &str, Configuration &cfg ) {
244  auto pluginInput = ConfigHelper::splitPluginInput( str ) ;
245  // if no plugin guess it from the input string
246  if( pluginInput.first.empty() ) {
247  std::filesystem::path filepath = pluginInput.second ;
248  if( filepath.extension().string() == ".xml" ) {
249  pluginInput.first = "XMLConfigWriter" ;
250  }
251  }
252  if( pluginInput.first.empty() ) {
253  MARLINMT_THROW( "No config writer plugin found in config string. Please specify your config as 'plugin_name:input'" ) ;
254  }
255  auto writer = PluginManager::instance().create<ConfigWriter>( pluginInput.first ) ;
256  if( nullptr == writer ) {
257  MARLINMT_THROW( "No ConfigWriter plugin found for type '" + pluginInput.first + "'" ) ;
258  }
259  writer->init( pluginInput.second ) ;
260  writer->write( cfg ) ;
261  }
262 
263 }
const Metadata & metadata() const
Get the section metadata.
ConfigSection(const ConfigSection &)=default
ConfigSection & section(const std::string &n)
Get a subsection by name.
T parameter(const std::string &n) const
Get a parameter value as type T.
#define MARLINMT_THROW_T(ExceptionType, message)
Definition: Exceptions.h:9
const std::string & name() const
Get the section name.
std::vector< std::string > parameterNames() const
Get the list of parameter names.
std::ostream & operator<<(std::ostream &stream, const Configuration &cfg)
Stream operator.
ConfigSection & createSection(const std::string &sn)
Create a new section by name.
std::map< std::string, std::string > ParameterMap
Definition: Configuration.h:23
bool hasSection(const std::string &n) const
Whether the subsection exists.
static void writeConfig(const std::string &str, Configuration &cfg)
Write the configuration using a ConfigWriter plugin.
std::vector< std::string > sections() const
Get the list of subsections.
std::map< std::string, std::string > ConstantsMap
Metadata _metadata
The section metdata map.
std::map< std::string, std::string > Metadata
Definition: Configuration.h:24
ConfigReader base class Interface for reading configuration.
void printSection(const ConfigSection &section, std::ostream &stream, const std::string &prefix)
static std::pair< std::string, std::string > splitPluginInput(const std::string &str)
Split the string to a pair "plugin, input".
const std::string _name
The section name.
bool empty() const
Whether the section is empty (no parameter, no subsection)
bool hasConstant(const std::string &cn) const
Whetehr the constant is registered in the configuration.
bool hasParameter(const std::string &n) const
Whether the parameter exists.
#define MARLINMT_THROW(message)
Definition: Exceptions.h:8
static void readConfig(const std::string &str, Configuration &cfg)
Read the configuration using a ConfigReader plugin.
ConfigSection & addSection(const std::string &n)
Create a new subsection.
ConfigSection & section(const std::string &sn)
Get a section by name.
Configuration class.
ParameterMap _parameters
The parameter map.
ConfigWriter base class Interface for writing configuration.
std::vector< std::string > subsectionNames() const
Get the list of subsection names.
ConfigSectionMap _subsections
The subsection map.
std::unique_ptr< T > create(const std::string &name) const
Create a new plugin instance.
const ConstantsMap & constants() const
Get the constants map.
const ParameterMap & parameters() const
Get the raw parameter storage.
void replaceConstants(std::string &str) const
Replace all occurences of ${constant_name} in the input string where "constant_name" must match a reg...
ConfigSection class Holds a set of parameters and subsection.
Definition: Configuration.h:20
bool hasSection(const std::string &n) const
Whether the section exists.
static PluginManager & instance()
Get the plugin manager instance.
std::vector< K > keys(const std::map< K, V > &m)
Definition: Utils.h:539