Forked from
jlab / hallc / analyzer_software / hcana
144 commits behind the upstream repository.
-
Chao Peng authored16736e1a
ConfigParser.h 8.36 KiB
#ifndef CONFIG_PARSER_H
#define CONFIG_PARSER_H
#include <string>
#include <vector>
#include <deque>
#include <fstream>
#include "ConfigValue.h"
// a macro to auto generate enum2str and str2enum
// name mapping begins at bias and continuously increase, split by '|'
// an example:
// enum ABC {a = 3, b, c};
// ENUM_MAP(ABC, 3, "a|b|c")
// ABC2str(3) = "a"
// str2ABC("b") = 4
#define ENUM_MAP(type, bias, strings) \
static std::string type ## 2str(int T) \
{ \
return ConfigParser::get_split_part(T - (bias), strings, '|'); \
}; \
static type str2 ## type(const char *str) \
{ \
return static_cast<type>(bias + ConfigParser::get_part_count(str, strings, '|')); \
}
// config parser class
class ConfigParser
{
typedef std::pair<std::string, std::string> string_pair;
public:
struct Format
{
std::string split; // element splitters (chars)
std::string white; // white spaces (chars)
std::string delim; // line delimiter (string)
std::string glue; // line glue (string)
std::string cmtmark; // comment marks (string), until the line breaker '\n'
std::string cmtopen; // comment-block opening mark (string)
std::string cmtclose; // comment-block closing mark (string)
static Format Basic() {return {" \t,", " \t", "\n", "", "", "", ""};}
static Format BashLike() {return {" \t,", " \t", "\n", "\\", "#", "\'", "\'"};}
static Format CLike() {return {" \t,\n", " \t\n", ";", "", "//", "/*", "*/"};}
};
struct CharBuffer
{
std::vector<char> data;
size_t begin, end;
CharBuffer(size_t cap = 256) : begin(0), end(0)
{
data.resize(cap);
}
void Reset() {begin = 0; end = 0; data.clear();}
void Add(char ch)
{
if(data.size() <= end)
data.resize(2*data.size());
data[end++] = ch;
}
std::string String()
const
{
std::string str;
if(end > begin)
str.assign(&data[begin], end - begin);
return str;
}
inline const char &operator [] (size_t idx) const {return data[idx];}
inline char &operator [] (size_t idx) {return data[idx];}
};
public:
ConfigParser(Format f = Format::BashLike());
ConfigParser(ConfigParser &&that);
ConfigParser(const ConfigParser &that);
virtual ~ConfigParser();
ConfigParser &operator = (ConfigParser &&rhs);
ConfigParser &operator = (const ConfigParser &rhs);
// format related
inline void SetFormat(Format &&f) {form = f;}
inline void SetFormat(const Format &f) {form = f;}
inline void SetSplitters(std::string s) {form.split = s;}
inline void SetWhiteSpaces(std::string w) {form.white = w;}
inline void SetCommentMark(std::string c) {form.cmtmark = c;}
inline void SetCommentPair(std::string o, std::string c) {form.cmtopen = o; form.cmtclose = c;}
inline void SetLineGlues(std::string g) {form.glue = g;}
inline void SetLineBreaks(std::string b) {form.delim = b;}
const Format &GetFormat() const {return form;}
// dealing with file/buffer
bool OpenFile(const std::string &path, size_t cap = 64*1024);
bool ReadFile(const std::string &path);
void ReadBuffer(const char*);
void CloseFile();
void Clear();
// parse line, return false if no more line to parse
bool ParseLine();
// parse the whole file or buffer, return false if no elements found
bool ParseAll();
// parse a string, trim and split it into elements
int ParseString(const std::string &line);
// get current parsing status
bool CheckElements(int num, int optional = 0);
int NbofElements() const {return elements.size();}
int LineNumber() const {return line_number;}
std::string CurrentLine() const {return cur_line.String();}
// take the elements
ConfigValue TakeFirst();
template<typename T>
T TakeFirst()
{
return TakeFirst().Convert<T>();
}
template<typename T>
ConfigParser &operator >>(T &t)
{
t = (*this).TakeFirst().Convert<T>();
return *this;
}
template<class BidirIt>
int Take(BidirIt first, BidirIt last)
{
int count = 0;
for(auto it = first; it != last; ++it, ++count)
{
if(elements.empty())
break;
*it = elements.front();
elements.pop_front();
}
return count;
}
template<template<class, class> class Container>
Container<ConfigValue, std::allocator<ConfigValue>> TakeAll()
{
Container<ConfigValue, std::allocator<ConfigValue>> res;
while(elements.size())
{
res.emplace_back(std::move(elements.front()));
elements.pop_front();
}
return res;
}
template<template<class, class> class Container, class T>
Container<T, std::allocator<T>> TakeAll()
{
Container<T, std::allocator<T>> res;
while(elements.size())
{
ConfigValue tmp(std::move(elements.front()));
elements.pop_front();
res.emplace_back(tmp.Convert<T>());
}
return res;
}
private:
// private functions
bool getBuffer();
bool getLine(CharBuffer &line_buf, bool recursive = false);
int parseBuffer(const CharBuffer &line);
private:
// private members
Format form;
std::ifstream infile;
CharBuffer buf, cur_line;
int line_number;
std::deque<std::string> elements;
public:
// static functions
static void comment_line(std::string &str, const std::string &cmt, const std::string &brk);
static void comment_between(std::string &str, const std::string &open, const std::string &close);
static std::string trim(const std::string &str, const std::string &w);
static std::deque<std::string> split(const std::string &str, const std::string &s);
static std::deque<std::string> split(const char* str, const size_t &len, const std::string &s);
static std::string get_split_part(int num, const char *str, const char &s);
static int get_part_count(const char *cmp, const char *str, const char &s);
static std::vector<int> stois(const std::string &str, const std::string &s, const std::string &w);
static std::vector<float> stofs(const std::string &str, const std::string &s, const std::string &w);
static std::vector<double> stods(const std::string &str, const std::string &s, const std::string &w);
static std::string str_remove(const std::string &str, const std::string &ignore);
static std::string str_replace(const std::string &str, const std::string &ignore, const char &rc = ' ');
static std::string str_lower(const std::string &str);
static std::string str_upper(const std::string &str);
static std::pair<size_t, size_t> find_pair(const std::string &str,
const std::string &open,
const std::string &close,
size_t pos = 0);
static bool case_ins_equal(const std::string &str1, const std::string &str2);
static int find_integer(const std::string &str, const size_t &pos = 0);
static std::vector<int> find_integers(const std::string &str);
static void find_integer_helper(const std::string &str, std::vector<int> &result);
struct PathInfo { std::string dir, name, ext; };
static PathInfo decompose_path(const std::string &path);
static std::string compose_path(const PathInfo &path);
static std::string form_path(const std::string &dir, const std::string &file);
static std::string file_to_string(const std::string &path);
// break text file into several blocks in the format
// <label> <open_mark> <content> <close_mark>, this structure can be separated by sep characters
// return extracted <residual> {<label> <content>} with white characters trimmed
struct TextBlock {std::string label, content;};
struct TextBlocks {std::string residual; std::vector<TextBlock> blocks;};
static TextBlocks break_into_blocks(const std::string &buf,
const std::string &open = "{",
const std::string &close = "}",
const std::string &seps = " \t\n");
};
#endif