Newer
Older
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef DUNE_PARAMETERTREE_HH
#define DUNE_PARAMETERTREE_HH
/** \file
* \brief A hierarchical structure of string parameters
*/
#include <cstddef>
#include <iostream>
#include <istream>
#include <iterator>
#include <locale>
#include <map>
#include <ostream>
#include <sstream>
#include <string>
#include <typeinfo>
#include <vector>
Dominic Kempf
committed
#include <bitset>
#include <dune/common/array.hh>
#include <dune/common/exceptions.hh>
#include <dune/common/fvector.hh>
#include <dune/common/classname.hh>
namespace Dune {
/** \brief Hierarchical structure of string parameters
* \ingroup Common
*/
class ParameterTree
{
// class providing a single static parse() function, used by the
// generic get() method
template<typename T>
struct Parser;
public:
typedef std::vector<std::string> KeyVector;
*/
ParameterTree();
/** \brief test for key
*
*
* \param key key name
* \return true if key exists in structure, otherwise false
*/
bool hasKey(const std::string& key) const;
/** \brief test for substructure
*
*
* \param sub substructure name
* \return true if substructure exists in structure, otherwise false
*/
bool hasSub(const std::string& sub) const;
/** \brief get value reference for key
*
* This creates the key, if not existent.
*
* \param key key name
*/
std::string& operator[] (const std::string& key);
/** \brief get value reference for key
*
* Returns reference to value for given key name.
* This creates the key, if not existent.
*
* \param key key name
* \return reference to corresponding value
* \throw Dune::RangeError if key is not found
*/
const std::string& operator[] (const std::string& key) const;
/** \brief print distinct substructure to stream
*
* Prints all entries with given prefix.
*
* \param stream Stream to print to
* \param prefix for key and substructure names
*/
void report(std::ostream& stream = std::cout,
const std::string& prefix = "") const;
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/** \brief get substructure by name
*
* \param sub substructure name
* \return reference to substructure
*/
ParameterTree& sub(const std::string& sub);
/** \brief get const substructure by name
*
* \param sub substructure name
* \return reference to substructure
*/
const ParameterTree& sub(const std::string& sub) const;
/** \brief get value as string
*
* Returns pure string value for given key.
*
* \param key key name
* \param defaultValue default if key does not exist
* \return value as string
*/
std::string get(const std::string& key, const std::string& defaultValue) const;
/** \brief get value as string
*
* Returns pure string value for given key.
*
* \todo This is a hack so get("my_key", "xyz") compiles
* (without this method "xyz" resolves to bool instead of std::string)
* \param key key name
* \param defaultValue default if key does not exist
* \return value as string
*/
std::string get(const std::string& key, const char* defaultValue) const;
/** \brief get value converted to a certain type
*
* Returns value as type T for given key.
*
* \tparam T type of returned value.
* \param key key name
* \param defaultValue default if key does not exist
* \return value converted to T
*/
template<typename T>
T get(const std::string& key, const T& defaultValue) const {
if(hasKey(key))
return get<T>(key);
else
return defaultValue;
}
/** \brief Get value
*
* \tparam T Type of the value
* \param key Key name
* \throws RangeError if key does not exist
* \throws NotImplemented Type is not supported
* \return value as T
*/
template <class T>
if(not hasKey(key))
DUNE_THROW(Dune::RangeError, "Key '" << key
<< "' not found in ParameterTree (prefix " + prefix_ + ")");
Christian Engwer
committed
try {
return Parser<T>::parse((*this)[key]);
}
catch(const RangeError& e) {
// rethrow the error and add more information
Christian Engwer
committed
DUNE_THROW(RangeError, "Cannot parse value \"" << (*this)[key]
<< "\" for key \"" << prefix_ << "." << key << "\""
<< e.what());
Christian Engwer
committed
}
}
/** \brief get value keys
*
* Returns a vector of all keys associated to (key,values) entries in
* order of appearance
*
* \return reference to entry vector
*/
const KeyVector& getValueKeys() const;
/** \brief get substructure keys
*
* Returns a vector of all keys associated to (key,substructure) entries
* in order of appearance
*
* \return reference to entry vector
*/
const KeyVector& getSubKeys() const;
protected:
std::string prefix_;
KeyVector valueKeys_;
KeyVector subKeys_;
std::map<std::string, std::string> values_;
std::map<std::string, ParameterTree> subs_;
static std::string ltrim(const std::string& s);
static std::string rtrim(const std::string& s);
static std::vector<std::string> split(const std::string & s);
// parse into a fixed-size range of iterators
template<class Iterator>
static void parseRange(const std::string &str,
Iterator it, const Iterator &end)
{
typedef typename std::iterator_traits<Iterator>::value_type Value;
std::istringstream s(str);
std::size_t n = 0;
for(; it != end; ++it, ++n) {
s >> *it;
if(!s)
DUNE_THROW(RangeError, "as a range of items of type "
<< className<Value>()
<< " (" << n << " items were extracted successfully)");
}
Value dummy;
s >> dummy;
// now extraction should have failed, and eof should be set
if(not s.fail() or not s.eof())
DUNE_THROW(RangeError, "as a range of "
<< n << " items of type "
<< className<Value>() << " (more items than the range can hold)");
};
template<typename T>
struct ParameterTree::Parser {
static T parse(const std::string& str) {
T val;
std::istringstream s(str);
// make sure we are in locale "C"
s.imbue(std::locale::classic());
s >> val;
if(!s)
DUNE_THROW(RangeError, " as a " << className<T>());
T dummy;
s >> dummy;
// now extraction should have failed, and eof should be set
if ((! s.fail()) || (! s.eof()))
DUNE_THROW(RangeError, " as a " << className<T>());
return val;
}
};
// "How do I convert a string into a wstring in C++?" "Why, that very simple
// son. You just need a these hundred lines of code."
// Instead im gonna restrict myself to string with charT=char here
template<typename traits, typename Allocator>
struct ParameterTree::Parser<std::basic_string<char, traits, Allocator> > {
static std::basic_string<char, traits, Allocator>
parse(const std::string& str) {
std::string trimmed = ltrim(rtrim(str));
return std::basic_string<char, traits, Allocator>(trimmed.begin(),
trimmed.end());
}
};
template<>
struct ParameterTree::Parser< bool > {
struct ToLower {
char operator()(char c)
return std::tolower(c, std::locale::classic());
}
};
static bool
parse(const std::string& str) {
std::string ret = str;
std::transform(ret.begin(), ret.end(), ret.begin(), ToLower());
if (ret == "yes" || ret == "true")
return true;
if (ret == "no" || ret == "false")
return false;
return (Parser<int>::parse(ret) != 0);
}
};
template<typename T, int n>
struct ParameterTree::Parser<FieldVector<T, n> > {
static FieldVector<T, n>
parse(const std::string& str) {
FieldVector<T, n> val;
parseRange(str, val.begin(), val.end());
return val;
}
};
template<typename T, std::size_t n>
struct ParameterTree::Parser<array<T, n> > {
static array<T, n>
parse(const std::string& str) {
array<T, n> val;
parseRange(str, val.begin(), val.end());
return val;
}
};
Dominic Kempf
committed
template<std::size_t n>
struct ParameterTree::Parser<std::bitset<n> > {
static std::bitset<n>
parse(const std::string& str) {
std::bitset<n> val;
std::vector<std::string> sub = split(str);
if (sub.size() != n)
DUNE_THROW(RangeError, "as a bitset<" << n << "> "
<< "because of unmatching size " << sub.size());
Dominic Kempf
committed
for (std::size_t i=0; i<n; ++i) {
val[i] = ParameterTree::Parser<bool>::parse(sub[i]);
}
return val;
}
};
template<typename T, typename A>
struct ParameterTree::Parser<std::vector<T, A> > {
static std::vector<T, A>
parse(const std::string& str) {
std::vector<std::string> sub = split(str);
std::vector<T, A> vec;
for (unsigned int i=0; i<sub.size(); ++i) {
T val = ParameterTree::Parser<T>::parse(sub[i]);