00001 #ifndef OPTIONS_H_
00002 #define OPTIONS_H_
00003
00004 #include <initializer_list>
00005 #include <sstream>
00006 #include <stdexcept>
00007 #include <string>
00008
00009 #include <boost/program_options.hpp>
00010 #include <yaml-cpp/yaml.h>
00011
00012 #include <Logger.h>
00013 #include <HZZException.h>
00014
00015
00032 class Options {
00033 public:
00037 class Error : public HZZException {
00038 public:
00039 Error(std::string const &message) : HZZException{message} {};
00040 };
00041
00042 using Group = boost::program_options::options_description;
00043
00061 Options(int argc, char **argv,
00062 std::initializer_list<Group> const &optionGroups);
00063
00067 bool Exists(std::string const &label) const;
00068
00077 template<typename T>
00078 T GetAs(std::string const &label) const;
00079
00093 template<typename T, typename Checker>
00094 T GetAsChecked(std::string const &label, Checker const &checker) const;
00095
00104 YAML::Node const &GetConfig() const;
00105
00113 template<typename T>
00114 static T NodeAs(YAML::Node const &node,
00115 std::initializer_list<std::string> const keys = {});
00116
00131 template<typename T, typename Checker>
00132 static T NodeAsChecked(YAML::Node const &node, Checker const &checker,
00133 std::initializer_list<std::string> const keys = {});
00134
00135 private:
00139 void PrintUsage() const;
00140
00142 std::string programName_;
00143
00145 boost::program_options::options_description allOptions_;
00146
00148 boost::program_options::variables_map optionMap_;
00149
00156 YAML::Node config_;
00157 };
00158
00159
00160 template<typename T>
00161 T Options::GetAs(std::string const &label) const {
00162 if (not Exists(label)) {
00163 std::ostringstream message;
00164 message << "Unknown option \"" << label << "\"";
00165 LOG_DEBUG << message.str();
00166 throw Error(message.str());
00167 }
00168
00169 return optionMap_[label].as<T>();
00170 }
00171
00172
00173 template<typename T, typename Checker>
00174 T Options::GetAsChecked(std::string const &label,
00175 Checker const &checker) const {
00176 T const value = GetAs<T>(label);
00177
00178 if (not checker(value)) {
00179 std::ostringstream message;
00180 message << "Invalid value read for option \"" << label << "\": " << value;
00181 LOG_DEBUG << message.str();
00182 throw Error(message.str());
00183 }
00184
00185 return value;
00186 }
00187
00188
00189 template<typename T>
00190 T Options::NodeAs(YAML::Node const &node,
00191 std::initializer_list<std::string> const keys) {
00192 if (not node)
00193 throw Error("The node does not exist.");
00194
00195
00196
00197
00198
00199
00200 YAML::Node copyNode = YAML::Clone(node);
00201 unsigned short int counter = 0;
00202 for (auto &key : keys) {
00203 counter++;
00204 copyNode = copyNode[key];
00205 if (not copyNode) break;
00206 }
00207
00208 if (not copyNode) {
00209 std::ostringstream message;
00210 message << "The node ";
00211
00212 for (auto key = keys.begin(); key != keys.begin() + counter; ++key)
00213 message << "[" << *key << "]";
00214 message << " does not exist.";
00215 throw Error(message.str());
00216 }
00217
00218 return copyNode.as<T>();
00219 }
00220
00221
00222 template<typename T, typename Checker>
00223 T Options::NodeAsChecked(YAML::Node const &node, Checker const &checker,
00224 std::initializer_list<std::string> const keys) {
00225 T const value = NodeAs<T>(node, keys);
00226
00227 if (not checker(value)) {
00228 std::ostringstream message;
00229 message << "Invalid value found for node: " << value;
00230 throw Error(message.str());
00231 }
00232
00233 return value;
00234 }
00235
00236 #endif // OPTIONS_H_