lammps/lib/colvars/colvarparse.h

318 lines
12 KiB
C++

// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef COLVARPARSE_H
#define COLVARPARSE_H
#include <cstring>
#include <string>
#include "colvarmodule.h"
#include "colvarvalue.h"
/// \file colvarparse.h Parsing functions for collective variables
/// \brief Base class containing parsing functions; all objects which
/// need to parse input inherit from this
class colvarparse {
protected:
/// \brief List of legal keywords for this object: this is updated
/// by each call to colvarparse::get_keyval() or
/// colvarparse::key_lookup()
std::list<std::string> allowed_keywords;
/// \brief List of delimiters for the values of each keyword in the
/// configuration string; all keywords will be stripped of their
/// values before the keyword check is performed
std::list<size_t> data_begin_pos;
/// \brief List of delimiters for the values of each keyword in the
/// configuration string; all keywords will be stripped of their
/// values before the keyword check is performed
std::list<size_t> data_end_pos;
/// \brief Whether or not to accumulate data_begin_pos and
/// data_end_pos in key_lookup(); it may be useful to disable
/// this after the constructor is called, because other files may be
/// read (e.g. restart) that would mess up the registry; in any
/// case, nothing serious happens until check_keywords() is invoked
/// (which should happen only right after construction)
bool save_delimiters;
/// \brief Add a new valid keyword to the list
void add_keyword(char const *key);
/// \brief Remove all the values from the config string
void strip_values(std::string &conf);
/// \brief Configuration string of the object
std::string config_string;
public:
inline colvarparse()
: save_delimiters(true)
{
init();
}
/// Constructor that stores the object's config string
inline colvarparse(const std::string& conf)
: save_delimiters(true)
{
init(conf);
}
/// Set the object ready to parse a new configuration string
inline void init()
{
config_string.clear();
clear_keyword_registry();
}
/// Set a new config string for this object
inline void init(const std::string& conf)
{
if (! config_string.size()) {
init();
config_string = conf;
}
}
inline const std::string& get_config()
{
return config_string;
}
/// How a keyword is parsed in a string
enum Parse_Mode {
/// \brief(default) Read the first instance of a keyword (if
/// any), report its value, and print a warning when there is more
/// than one
parse_normal,
/// \brief Like parse_normal, but don't send any message to the log
/// (useful e.g. in restart files when such messages are very
/// numerous and redundant)
parse_silent
};
/// \brief Check that all the keywords within "conf" are in the list
/// of allowed keywords; this will invoke strip_values() first and
/// then loop over all words
int check_keywords(std::string &conf, char const *key);
/// \brief Use this after parsing a config string (note that check_keywords() calls it already)
void clear_keyword_registry();
public:
/// \fn get_keyval bool const get_keyval (std::string const &conf,
/// char const *key, _type_ &value, _type_ const &def_value,
/// Parse_Mode const parse_mode) \brief Helper function to parse
/// keywords in the configuration and get their values
///
/// In normal circumstances, you should use either version the
/// get_keyval function. Both of them look for the C string "key"
/// in the C++ string "conf", and assign the corresponding value (if
/// available) to the variable "value" (first version), or assign as
/// many values as found to the vector "values" (second version).
///
/// If "key" is found but no value is associated to it, the default
/// value is provided (either one copy or as many copies as the
/// current length of the vector "values" specifies). A message
/// will print, unless parse_mode is equal to parse_silent. The
/// return value of both forms of get_keyval is true if "key" is
/// found (with or without value), and false when "key" is absent in
/// the string "conf". If there is more than one instance of the
/// keyword, a warning will be raised; instead, to loop over
/// multiple instances key_lookup() should be invoked directly.
///
/// If you introduce a new data type, add two new instances of this
/// functions, or insert this type in the \link colvarvalue \endlink
/// wrapper class (colvarvalue.h).
bool get_keyval(std::string const &conf,
char const *key,
int &value,
int const &def_value = (int)0,
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
size_t &value,
size_t const &def_value = (size_t)0,
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
long &value,
long const &def_value = 0,
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::string &value,
std::string const &def_value = std::string(""),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
cvm::real &value,
cvm::real const &def_value = (cvm::real)0.0,
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
cvm::rvector &value,
cvm::rvector const &def_value = cvm::rvector(),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
cvm::quaternion &value,
cvm::quaternion const &def_value = cvm::quaternion(),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
colvarvalue &value,
colvarvalue const &def_value = colvarvalue(colvarvalue::type_notset),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
bool &value,
bool const &def_value = false,
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::vector<int> &values,
std::vector<int> const &def_values = std::vector<int>(0, (int)0),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::vector<size_t> &values,
std::vector<size_t> const &def_values = std::vector<size_t>(0, (size_t)0),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::vector<long> &values,
std::vector<long> const &def_values = std::vector<long>(0, (long)0),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::vector<std::string> &values,
std::vector<std::string> const &def_values = std::vector<std::string>(0, std::string("")),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::vector<cvm::real> &values,
std::vector<cvm::real> const &def_values = std::vector<cvm::real>(0, (cvm::real)0.0),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::vector<cvm::rvector> &values,
std::vector<cvm::rvector> const &def_values = std::vector<cvm::rvector>(0, cvm::rvector()),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::vector<cvm::quaternion> &values,
std::vector<cvm::quaternion> const &def_values = std::vector<cvm::quaternion>(0, cvm::quaternion()),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::vector<colvarvalue> &values,
std::vector<colvarvalue> const &def_values = std::vector<colvarvalue>(0, colvarvalue(colvarvalue::type_notset)),
Parse_Mode const parse_mode = parse_normal);
protected:
// Templates
template<typename TYPE> bool _get_keyval_scalar_(std::string const &conf,
char const *key,
TYPE &value,
TYPE const &def_value,
Parse_Mode const parse_mode);
bool _get_keyval_scalar_string_(std::string const &conf,
char const *key,
std::string &value,
std::string const &def_value,
Parse_Mode const parse_mode);
template<typename TYPE> bool _get_keyval_vector_(std::string const &conf,
char const *key,
std::vector<TYPE> &values,
std::vector<TYPE> const &def_values,
Parse_Mode const parse_mode);
public:
/// \brief Return a lowercased copy of the string
static inline std::string to_lower_cppstr(std::string const &in)
{
std::string out = "";
for (size_t i = 0; i < in.size(); i++) {
out.append(1, (char) ::tolower(in[i]) );
}
return out;
}
/// \brief Helper class to read a block of the type "key { ... }"
/// from a stream and store it in a string
///
/// Useful on restarts, where the file is too big to be loaded in a
/// string by key_lookup; it can only check that the keyword is
/// correct and the block is properly delimited by braces, not
/// skipping other blocks
class read_block {
std::string const key;
std::string * const data;
public:
inline read_block(std::string const &key_in, std::string &data_in)
: key(key_in), data(&data_in)
{}
inline ~read_block() {}
friend std::istream & operator >> (std::istream &is, read_block const &rb);
};
/// Accepted white space delimiters, used in key_lookup()
static std::string const white_space;
/// \brief Low-level function for parsing configuration strings;
/// automatically adds the requested keyword to the list of valid
/// ones. \param conf the content of the configuration file or one
/// of its blocks \param key the keyword to search within "conf" \param
/// data (optional) holds the string provided after "key", if any
/// \param save_pos (optional) stores the position of the keyword
/// within "conf", useful when doing multiple calls
bool key_lookup(std::string const &conf,
char const *key,
std::string &data = dummy_string,
size_t &save_pos = dummy_pos);
/// Used as a default argument by key_lookup
static std::string dummy_string;
/// Used as a default argument by key_lookup
static size_t dummy_pos;
/// \brief Works as std::getline() but also removes everything
/// between a comment character and the following newline
static std::istream & getline_nocomments(std::istream &is,
std::string &s,
char const delim = '\n');
/// Check if the content of the file has matching braces
bool brace_check(std::string const &conf,
size_t const start_pos = 0);
};
#endif