Newer
Older
Martin Christoph Hierholzer
committed
#ifndef CHIMERATK_APPLICATION_CORE_CONFIG_READER_H
#define CHIMERATK_APPLICATION_CORE_CONFIG_READER_H
#include <map>
#include <mtca4u/SupportedUserTypes.h>
#include "ApplicationCore.h"
namespace ChimeraTK {
struct FunctorFill;
struct ArrayFunctorFill;
Martin Christoph Hierholzer
committed
struct FunctorSetValues;
struct FunctorSetValuesArray;
Martin Christoph Hierholzer
committed
/**
* Generic module to read an XML config file and provide the defined values as constant variables. The config file
* should look like this:
* \code{.xml}
<configuration>
<variable name="variableName" type="int32" value="42"/>
<variable name="anotherVariable" type="string" value="Hello world!"/>
</configuration>
\endcode
*
* Outputs are created for each variable, so they can be connected to other modules. All values will be provided to
* the receivers already in the preparation phase, so no read() must be called. Updates will never be sent, so any
* blocking read operation on the receivers will block forever.
*
* Configuration values can already be accessed during the Application::defineConnection() function by using the
* ConfigReader::get() function.
*/
Martin Christoph Hierholzer
committed
struct ConfigReader : ApplicationModule {
Martin Christoph Hierholzer
committed
ConfigReader(EntityOwner *owner, const std::string &name, const std::string &fileName,
const std::unordered_set<std::string> &tags={});
Martin Christoph Hierholzer
committed
void mainLoop() override {}
void prepare() override;
Martin Christoph Hierholzer
committed
/** Get value for given configuration variable. This is already accessible right after construction of this
* object. Throws std::out_of_range if variable doesn't exist.
* To obtain the value of an array, use an std::vector<T> as template argument. */
Martin Christoph Hierholzer
committed
template<typename T>
Martin Christoph Hierholzer
committed
const T& get(const std::string &variableName) const;
Martin Christoph Hierholzer
committed
protected:
Martin Christoph Hierholzer
committed
/** File name */
std::string _fileName;
/** throw a parsing error with more information */
void parsingError(const std::string &message);
Martin Christoph Hierholzer
committed
/** Class holding the value and the accessor for one configuration variable */
template<typename T>
struct Var {
Var(Module *owner, const std::string &name, const T &value)
: _accessor(owner, name, "unknown", "Configuration variable"),
_value(value)
{}
ScalarOutput<T> _accessor;
T _value;
};
/** Class holding the values and the accessor for one configuration array */
template<typename T>
struct Array {
Array(Module *owner, const std::string &name, const std::vector<T> &value)
: _accessor(owner, name, "unknown", value.size(), "Configuration array"),
_value(value)
{}
ArrayOutput<T> _accessor;
std::vector<T> _value;
};
Martin Christoph Hierholzer
committed
/** Create an instance of Var<T> and place it on the variableMap */
template<typename T>
void createVar(const std::string &name, const std::string &value);
/** Create an instance of Array<T> and place it on the arrayMap */
template<typename T>
void createArray(const std::string &name, const std::map<size_t, std::string> &values);
Martin Christoph Hierholzer
committed
/** Define type for map of std::string to Var, so we can put it into the TemplateUserTypeMap */
Martin Christoph Hierholzer
committed
template<typename T>
Martin Christoph Hierholzer
committed
using MapOfVar = std::map<std::string, Var<T>>;
Martin Christoph Hierholzer
committed
/** Type-depending map of vectors of variables */
Martin Christoph Hierholzer
committed
mtca4u::TemplateUserTypeMap<MapOfVar> variableMap;
/** Define type for map of std::string to Array, so we can put it into the TemplateUserTypeMap */
template<typename T>
using MapOfArray = std::map<std::string, Array<T>>;
/** Type-depending map of vectors of arrays */
mtca4u::TemplateUserTypeMap<MapOfArray> arrayMap;
Martin Christoph Hierholzer
committed
/** Map assigning string type identifyers to C++ types */
mtca4u::SingleTypeUserTypeMap<const char*> typeMap{"int8","uint8","int16","uint16","int32","uint32",
"int64","uint64","float","double","string"};
/** Implementation of get() which can be overloaded for scalars and vectors. The second argument is a dummy
* only to distinguish the two overloaded functions. */
template<typename T>
const T& get_impl(const std::string &variableName, T*) const;
template<typename T>
const std::vector<T>& get_impl(const std::string &variableName, std::vector<T>*) const;
Martin Christoph Hierholzer
committed
friend struct FunctorFill;
friend struct ArrayFunctorFill;
Martin Christoph Hierholzer
committed
friend struct FunctorSetValues;
friend struct FunctorSetValuesArray;
Martin Christoph Hierholzer
committed
};
Martin Christoph Hierholzer
committed
/*********************************************************************************************************************/
/*********************************************************************************************************************/
template<typename T>
const T& ConfigReader::get(const std::string &variableName) const {
return get_impl(variableName, static_cast<T*>(nullptr));
}
/*********************************************************************************************************************/
/*********************************************************************************************************************/
template<typename T>
const T& ConfigReader::get_impl(const std::string &variableName, T*) const {
Martin Christoph Hierholzer
committed
try {
return boost::fusion::at_key<T>(variableMap.table).at(variableName)._value;
}
catch(std::out_of_range &e) {
throw(std::out_of_range("ConfigReader: Cannot find a scalar configuration variable of the name '"+
variableName+"' in the config file '"+_fileName+"'."));
}
}
/*********************************************************************************************************************/
/*********************************************************************************************************************/
template<typename T>
const std::vector<T>& ConfigReader::get_impl(const std::string &variableName, std::vector<T>*) const {
try {
return boost::fusion::at_key<T>(arrayMap.table).at(variableName)._value;
}
catch(std::out_of_range &e) {
throw(std::out_of_range("ConfigReader: Cannot find an array configuration variable of the name '"+
Martin Christoph Hierholzer
committed
variableName+"' in the config file '"+_fileName+"'."));
}
}
Martin Christoph Hierholzer
committed
} // namespace ChimeraTK
#endif /* CHIMERATK_APPLICATION_CORE_CONFIG_READER_H */