xgboost
config.h
Go to the documentation of this file.
1 
7 #ifndef XGBOOST_COMMON_CONFIG_H_
8 #define XGBOOST_COMMON_CONFIG_H_
9 
10 #include <string>
11 #include <fstream>
12 #include <istream>
13 #include <sstream>
14 #include <vector>
15 #include <regex>
16 #include <iterator>
17 #include <utility>
18 
19 #include "xgboost/logging.h"
20 
21 namespace xgboost {
22 namespace common {
26 class ConfigParser {
27  public:
32  explicit ConfigParser(const std::string path)
33  : path_(std::move(path)),
34  line_comment_regex_("^#"),
35  key_regex_(R"rx(^([^#"'=\r\n\t ]+)[\t ]*=)rx"),
36  key_regex_escaped_(R"rx(^(["'])([^"'=\r\n]+)\1[\t ]*=)rx"),
37  value_regex_(R"rx(^([^#"'\r\n\t ]+)[\t ]*(?:#.*){0,1}$)rx"),
38  value_regex_escaped_(R"rx(^(["'])([^"'\r\n]+)\1[\t ]*(?:#.*){0,1}$)rx")
39  {}
40 
41  std::string LoadConfigFile(const std::string& path) {
42  std::ifstream fin(path, std::ios_base::in | std::ios_base::binary);
43  CHECK(fin) << "Failed to open config file: \"" << path << "\"";
44  try {
45  std::string content{std::istreambuf_iterator<char>(fin),
46  std::istreambuf_iterator<char>()};
47  return content;
48  } catch (std::ios_base::failure const &e) {
49  LOG(FATAL) << "Failed to read config file: \"" << path << "\"\n"
50  << e.what();
51  }
52  return "";
53  }
54 
64  std::string NormalizeConfigEOL(std::string const& config_str) {
65  std::string result;
66  std::stringstream ss(config_str);
67  for (auto c : config_str) {
68  if (c == '\r') {
69  result.push_back('\n');
70  continue;
71  }
72  result.push_back(c);
73  }
74  return result;
75  }
76 
82  std::vector<std::pair<std::string, std::string>> Parse() {
83  std::string content { LoadConfigFile(path_) };
84  content = NormalizeConfigEOL(content);
85  std::stringstream ss { content };
86  std::vector<std::pair<std::string, std::string>> results;
87  std::string line;
88  std::string key, value;
89  // Loop over every line of the configuration file
90  while (std::getline(ss, line)) {
91  if (ParseKeyValuePair(line, &key, &value)) {
92  results.emplace_back(key, value);
93  }
94  }
95  return results;
96  }
97 
98  private:
99  std::string path_;
100  const std::regex line_comment_regex_, key_regex_, key_regex_escaped_,
101  value_regex_, value_regex_escaped_;
102 
103  public:
109  static std::string TrimWhitespace(const std::string& str) {
110  const auto first_char = str.find_first_not_of(" \t\n\r");
111  const auto last_char = str.find_last_not_of(" \t\n\r");
112  if (first_char == std::string::npos) {
113  // Every character in str is a whitespace
114  return std::string();
115  }
116  CHECK_NE(last_char, std::string::npos);
117  const auto substr_len = last_char + 1 - first_char;
118  return str.substr(first_char, substr_len);
119  }
120 
128  bool ParseKeyValuePair(const std::string& str, std::string* key,
129  std::string* value) {
130  std::string buf = TrimWhitespace(str);
131  if (buf.empty()) {
132  return false;
133  }
134 
135  /* Match key */
136  std::smatch m;
137  if (std::regex_search(buf, m, line_comment_regex_)) {
138  // This line is a comment
139  return false;
140  } else if (std::regex_search(buf, m, key_regex_)) {
141  // Key doesn't have whitespace or #
142  CHECK_EQ(m.size(), 2);
143  *key = m[1].str();
144  } else if (std::regex_search(buf, m, key_regex_escaped_)) {
145  // Key has a whitespace and/or #; it has to be wrapped around a pair of
146  // single or double quotes. Example: "foo bar" 'foo#bar'
147  CHECK_EQ(m.size(), 3);
148  *key = m[2].str();
149  } else {
150  LOG(FATAL) << "This line is not a valid key-value pair: " << str;
151  }
152 
153  /* Match value */
154  buf = m.suffix().str();
155  buf = TrimWhitespace(buf);
156  if (std::regex_search(buf, m, value_regex_)) {
157  // Value doesn't have whitespace or #
158  CHECK_EQ(m.size(), 2);
159  *value = m[1].str();
160  } else if (std::regex_search(buf, m, value_regex_escaped_)) {
161  // Value has a whitespace and/or #; it has to be wrapped around a pair of
162  // single or double quotes. Example: "foo bar" 'foo#bar'
163  CHECK_EQ(m.size(), 3);
164  *value = m[2].str();
165  } else {
166  LOG(FATAL) << "This line is not a valid key-value pair: " << str;
167  }
168  return true;
169  }
170 };
171 
172 } // namespace common
173 } // namespace xgboost
174 #endif // XGBOOST_COMMON_CONFIG_H_
Implementation of config reader.
Definition: config.h:26
namespace of xgboost
Definition: base.h:102