Page MenuHomec4science

parser.hh
No OneTemporary

File Metadata

Created
Tue, Nov 12, 10:40

parser.hh

/**
*
* @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
*
* @section LICENSE
*
* Copyright (©) 2016 EPFL (Ecole Polytechnique Fédérale de
* Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des
* Solides)
*
* Tamaas is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* Tamaas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Tamaas. If not, see <http://www.gnu.org/licenses/>.
*
*/
/* -------------------------------------------------------------------------- */
#include <map>
#include <iomanip>
/* -------------------------------------------------------------------------- */
template <typename T>
class default_val{
public:
default_val(){
is_set = false;
};
default_val(const T & v){
is_set = true;
val = v;
};
bool is_set;
T val;
};
template <>
class default_val<bool>{
public:
default_val(){
is_set = true;
val = false;
};
default_val(const bool & v){
is_set = true;
val = v;
};
bool is_set;
bool val;
};
/* -------------------------------------------------------------------------- */
template <typename T> class TypedParameter;
/* -------------------------------------------------------------------------- */
class Parameter {
public:
Parameter(const std::string & name){
this->name = name;
}
virtual ~Parameter(){};
void setHelp(const std::string & help){
this->help = help;
}
std::string getHelp(){
return this->help;
}
virtual std::string getStringDefault() = 0;
virtual void parse(std::stringstream & sstr)=0;
template <typename T>
operator T(){
try {
return dynamic_cast<TypedParameter<T> &>(*this);
}
catch (...) {
SURFACE_FATAL("bad cast on parameter " << this->name);
}
};
virtual operator std::string() = 0;
std::string name;
std::string help;
};
/* -------------------------------------------------------------------------- */
template <typename T>
class TypedParameterInterface : public Parameter{
public:
TypedParameterInterface(const std::string & name, const default_val<T> & def):
Parameter(name){
is_set = false;
this->def = def;
};
virtual void parse(std::stringstream & sstr){
sstr >> this->val;
if (sstr.fail()) SURFACE_FATAL("could not parse " << this->name);
std::cerr << this->name << " = " << this->val << std::endl;
this->is_set = true;
};
operator std::string(){
std::stringstream sstr;
T tmp = *this;
sstr << tmp;
return sstr.str();
};
operator T(){
if (is_set) return val;
if (def.is_set) return def.val;
else SURFACE_FATAL("option '" << name << "' has no default: must be set");
};
virtual std::string getStringDefault(){
std::stringstream sstr;
if (def.is_set) sstr << def.val;
return sstr.str();
}
protected:
T val;
default_val<T> def;
bool is_set;
};
/* -------------------------------------------------------------------------- */
template <>
class TypedParameterInterface<std::string> : public Parameter{
public:
TypedParameterInterface(const std::string & name, const default_val<std::string> & def):
Parameter(name){
is_set = false;
this->def = def;
};
virtual void parse(std::stringstream & sstr){
sstr >> this->val;
std::cerr << this->name << " = " << this->val << std::endl;
this->is_set = true;
};
operator std::string(){
if (is_set) return val;
if (def.is_set) return def.val;
else SURFACE_FATAL("option '" << name << "' has no default: must be set");
};
virtual std::string getStringDefault(){
std::stringstream sstr;
if (def.is_set) sstr << def.val;
return sstr.str();
}
protected:
std::string val;
default_val<std::string> def;
bool is_set;
};
/* -------------------------------------------------------------------------- */
template <typename T>
class TypedParameter : public TypedParameterInterface<T>{
public:
TypedParameter(const std::string & name, const default_val<T> & def):
TypedParameterInterface<T>(name,def){};
};
/* -------------------------------------------------------------------------- */
template <>
class TypedParameter<bool> : public TypedParameterInterface<bool>{
public:
TypedParameter(const std::string & name, const default_val<bool> & def):
TypedParameterInterface<bool>(name,def){
};
virtual void parse(std::stringstream & sstr){
if (sstr.eof()) return;
std::string str_cpy = sstr.str().substr(sstr.tellg());
std::stringstream sstr_cpy(str_cpy);
std::string mot;
sstr_cpy >> mot;
if (mot == "False" || mot == "false")
val = false;
else if (mot == "True" || mot == "true")
val = true;
else {
if (! def.is_set) SURFACE_FATAL("default must be provided for unregistered option " << name);
val = def.val;
if (val == true) val = false;
else val = true;
}
std::cerr << this->name << " = " << val << std::endl;
is_set = true;
};
operator std::string(){
if (val) return "true";
else return "false";
};
virtual std::string getStringDefault(){
std::stringstream sstr;
if (def.is_set) {
if (def.val) sstr << "true";
else sstr << "false";
}
return sstr.str();
}
};
/* -------------------------------------------------------------------------- */
class Parser {
/* ------------------------------------------------------------------------ */
/* Constructors/Destructors */
/* ------------------------------------------------------------------------ */
public:
Parser(){
this->addParameter<bool>("help","Get Usage information",false);
};
virtual ~Parser(){
for (auto p: this->parameters) delete p.second;
};
/* ------------------------------------------------------------------------ */
/* Methods */
/* ------------------------------------------------------------------------ */
public:
template <typename T>
void addParameter(const std::string & name,
const std::string & help,
const default_val<T> def = default_val<T>());
template <typename T>
void addParameter(const std::string & name,
const std::string & help,const T & def);
std::string usage();
void parse(int argc,char ** argv);
void parse(const std::string & line);
std::string makeFilename(const std::string & prefix = "",
const std::string & extension = "txt");
Parameter & get(const std::string & name){
if (parameters.count(name) == 0)
SURFACE_FATAL("unregistered option " << name);
return *parameters[name];
};
/* ------------------------------------------------------------------------ */
/* Accessors */
/* ------------------------------------------------------------------------ */
public:
/* ------------------------------------------------------------------------ */
/* Class Members */
/* ------------------------------------------------------------------------ */
private:
std::map<std::string,Parameter*> parameters;
std::string prog_name;
};
/* -------------------------------------------------------------------------- */
template <typename T>
void Parser::addParameter(const std::string & name, const std::string & help,
const default_val<T> def){
TypedParameter<T> * p = new TypedParameter<T>(name,def);
p->setHelp(help);
this->parameters[name] = p;
}
/* -------------------------------------------------------------------------- */
template <typename T>
void Parser::addParameter(const std::string & name, const std::string & help,
const T & def){
TypedParameter<T> * p = new TypedParameter<T>(name,default_val<T>(def));
p->setHelp(help);
this->parameters[name] = p;
}
/* -------------------------------------------------------------------------- */
void Parser::parse(int argc, char ** argv){
std::string line;
this->prog_name = argv[0];
for (int i = 1; i < argc; ++i) {
line += argv[i];
if (i+1 != argc) line += " ";
}
this->parse(line);
}
/* -------------------------------------------------------------------------- */
void Parser::parse(const std::string & line){
std::stringstream sstr(line);
while (sstr.good()){
std::string word;
sstr >> word;
if (word.find("--") == 0){
std::string option = word.substr(2);
if (parameters.count(option) == 0){
SURFACE_FATAL("'" << option << "' is not a valid option" << std::endl
<< this->usage());
}
if (option == "help")
SURFACE_FATAL("\n\n\n" + this->usage());
parameters[option]->parse(sstr);
}
}
}
/* -------------------------------------------------------------------------- */
std::string Parser::makeFilename(const std::string & prefix,
const std::string & extension){
std::stringstream sstr;
if (prefix != "") sstr << prefix;
else sstr << "general";
std::map<std::string,Parameter*>::iterator it = parameters.begin();
std::map<std::string,Parameter*>::iterator end = parameters.end();
while (it != end){
std::string name = it->first;
std::string val = *(it->second);
if (name != "help")
sstr << "-" << name << "-" << val;
++it;
}
sstr << "." << extension;
return sstr.str();
}
/* -------------------------------------------------------------------------- */
std::string Parser::usage(){
std::map<std::string,Parameter*>::iterator it = parameters.begin();
std::map<std::string,Parameter*>::iterator end = parameters.end();
std::stringstream sstr;
sstr << "Usage: " << this->prog_name << " --option1 val1 ... --optionN valN ..."
<< std::endl << std::endl << "Options:" << std::endl;
while (it != end){
std::string name = it->first;
std::string help = it->second->getHelp();
sstr << "\t" << "--" << std::left << std::setw(30) << name;
std::string def = it->second->getStringDefault();
if (def != "") {
std::string def_str = "(default '" + def + "')";
sstr << std::setw(20) << def_str;
}
else sstr << std::setw(20) << "";
sstr << " " << help << std::endl;
++it;
}
return sstr.str();
}

Event Timeline