hmbdc
simplify-high-performance-messaging-programming
Config.hpp
1 #include "hmbdc/Copyright.hpp"
2 #pragma once
3 
4 #include <string>
5 #include <memory>
6 #include <list>
7 #include <unordered_set>
8 #include <boost/property_tree/ptree.hpp>
9 #pragma GCC diagnostic ignored "-Wreturn-type"
10 #include <boost/property_tree/json_parser.hpp>
11 
12 namespace hmbdc { namespace app {
13 
14 using namespace std;
15 using namespace boost::property_tree;
16 /**
17  * @brief class to hold an hmbdc configuration
18  * @details it is based on a two level json format.
19  * top level for the fallback values and lower level for section specific values
20  * shown below:
21  *
22  * {
23  * "parameter_1": "top level, value used as a fallback",
24  * "parameter_2": "fallback is used when not configured in a section",
25  * "section_A": {
26  * "parameter_2": "lower level, a specific value effective in section_A",
27  * "parameter_1": "a specific value effective in section_A"
28  * },
29  * "another_section": {
30  * "parameter_2": "a specific value effective in another_section"
31  * }
32  * }
33  *
34  */
35 struct Config
36 : ptree {
37  using ptree::ptree;
38  /**
39  * @brief empty config
40  */
41  Config(){}
42 
43  /**
44  * @brief construct using stream, optionally specifying the section name
45  * @details if the section is nullptr, just use the fallback values. if
46  * the section name cannot be found, throw an exception
47  *
48  * @param is stream as input providing a json stream
49  * @param section pointing to the effective section in the json above
50  */
51  explicit
52  Config(istream&& is, char const* section = nullptr) {
53  if (section) {
54  read_json(is, fallback_);
55  (ptree&)*this = fallback_.get_child(section);
56  } else {
57  read_json(is, (ptree&)*this);
58  }
59  }
60  /**
61  * @brief construct using stream, optionally specifying the section name
62  * @details if the section is nullptr, just use the fallback values. if
63  * the section name cannot be found, throw an exception
64  *
65  * @param is stream as input providing a json stream
66  * @param section pointing to the effective section in the json above
67  */
68  explicit
69  Config(istream& is, char const* section = nullptr) {
70  if (section) {
71  read_json(is, fallback_);
72  (ptree&)*this = fallback_.get_child(section);
73  } else {
74  read_json(is, (ptree&)*this);
75  }
76  }
77 
78  /**
79  * @brief construct using a string, optionally specifying the section name
80  * @details if the section is nullptr, just use the fallback values. if
81  * the section name cannot be found, throw an exception
82  *
83  * @param json string as input providing a json text
84  * @param section pointing to the effective section in the json above
85  */
86  explicit
87  Config(char const* json, char const* section = nullptr)
88  : Config(istringstream(json), section)
89  {}
90 
91  /**
92  * @brief construct using another ptree as fallbacks, optionally specifying the section name
93  * @details if the section is nullptr, just use the fallback values. if
94  * the section name cannot be found, throw an exception
95  *
96  * @param t ptree as input providing fallbacks (and sections)
97  * @param section pointing to the effective section in the ptree above
98  */
99  Config(ptree const& t, char const* section = nullptr) {
100  if (section) {
101  fallback_ = t;
102  (ptree&)*this = fallback_.get_child(section);
103  } else {
104  (ptree&)*this = t;
105  }
106  }
107 
108  /**
109  * @brief construct using a fallback ptree, and specify the section ptree
110  * @details if the section is nullptr, just use the fallback values. if
111  * the section name cannot be found, throw an exception
112  *
113  * @param t ptree as input providing fallbacks
114  * @param section ptree providing section specific values
115  */
116  explicit
117  Config(ptree const& t, ptree const& section) {
118  fallback_ = t;
119  (ptree&)*this = section;
120  }
121 
122  /**
123  * @brief internal use
124  * @details this is to set the default user config values (not the fallback values)
125  *
126  * @param c a config holding configuration values
127  */
128  void setDefaultUserConfig(Config const& c) {
129  defaultUserConfig_.reset(new Config(c));
130  }
131 
132  /**
133  * @brief get a value from the config
134  * @details check the section for it, if not found, try use fallback provided
135  * if still missing, search using the default user config values set by
136  * setDefaultUserConfig. Throw exception ptree_bad_path if all fail
137  *
138  * @param param config parameter name
139  * @tparam T type of the value
140  * @return result
141  */
142  template <typename T>
143  T getExt(const path_type& param) const {
144  auto res = get_optional<T>(param);
145  if (!res) {
146  res = fallback_.get_optional<T>(param);
147  if (!res) {
148  if (defaultUserConfig_) {
149  return defaultUserConfig_->getExt<T>(param);
150  } else {
151  throw ptree_bad_path("invalid param and no default user Config set", param);
152  }
153  }
154  }
155  return *res;
156  }
157 
158  /**
159  * @brief get a number value in hex format
160  * @details check the section for it, if not found, try use fallback provided
161  * if still missing, search using the default user config values set by
162  * setDefaultUserConfig. Throw exception ptree_bad_path if all fail
163  *
164  * @param param config parameter name
165  * @tparam T numeric type of the value: int , uint64_t ...
166  * @return result
167  */
168  template <typename T>
169  T getHex(ptree::path_type const& param) {
170  istringstream iss(getExt<string>(param));
171  T res;
172  iss >> hex >> res;
173  return res;
174  }
175 
176  /**
177  * @brief fill in a variable with a configured value retrieved using getExt
178  * @details example cfg(abc, "abc")(def, "def");
179  *
180  * @param to destination
181  * @param param config parameter
182  *
183  * @return the Config object itself
184  */
185  template <typename T>
186  Config const& operator()(T& to, const path_type& param) const {
187  to = getExt<T>(param);
188  return *this;
189  }
190 
191  /**
192  * @brief get contents of all the effective configure in the form of list of string pairs
193  * @details only effective ones are shown
194  *
195  * @param skipThese skip those config params
196  * @return list of string pairs in the original order of ptree nodes
197  */
198  list<pair<string, string>> content(
199  unordered_set<string> const& skipThese = unordered_set<string>()) const {
200  list<pair<string, string>> res;
201  unordered_set<string> history(skipThese);
202  for (auto& p : *this) {
203  if (history.find(p.first) == history.end()) {
204  history.insert(p.first);
205  if (p.second.empty()) {
206  res.push_back(make_pair(p.first, p.second.get_value<string>()));
207  }
208  }
209  }
210  for (auto& p : fallback_) {
211  if (history.find(p.first) == history.end()) {
212  history.insert(p.first);
213  if (p.second.empty()) {
214  res.push_back(make_pair(p.first, p.second.get_value<string>()));
215  }
216  }
217  }
218  if (defaultUserConfig_) {
219  auto more = defaultUserConfig_->content(history);
220  res.insert(res.end(), more.begin(), more.end());
221  }
222  return res;
223  }
224 
225 private:
226  ptree fallback_;
227  std::shared_ptr<Config> defaultUserConfig_;
228 };
229 
230 }}
231 
class to hold an hmbdc configuration
Definition: Config.hpp:35
T getHex(ptree::path_type const &param)
get a number value in hex format
Definition: Config.hpp:169
void setDefaultUserConfig(Config const &c)
internal use
Definition: Config.hpp:128
Config()
empty config
Definition: Config.hpp:41
Definition: TypedString.hpp:74
list< pair< string, string > > content(unordered_set< string > const &skipThese=unordered_set< string >()) const
get contents of all the effective configure in the form of list of string pairs
Definition: Config.hpp:198
Config(istream &is, char const *section=nullptr)
construct using stream, optionally specifying the section name
Definition: Config.hpp:69
Config(ptree const &t, char const *section=nullptr)
construct using another ptree as fallbacks, optionally specifying the section name ...
Definition: Config.hpp:99
Config const & operator()(T &to, const path_type &param) const
fill in a variable with a configured value retrieved using getExt
Definition: Config.hpp:186
Config(istream &&is, char const *section=nullptr)
construct using stream, optionally specifying the section name
Definition: Config.hpp:52
Config(ptree const &t, ptree const &section)
construct using a fallback ptree, and specify the section ptree
Definition: Config.hpp:117
T getExt(const path_type &param) const
get a value from the config
Definition: Config.hpp:143
Config(char const *json, char const *section=nullptr)
construct using a string, optionally specifying the section name
Definition: Config.hpp:87
Definition: Client.hpp:11