First pass implementation of a naive argument parser. API is shaping up

This commit is contained in:
Pranav Srinivas Kumar 2019-03-30 10:50:51 -04:00
parent 2539bc33ce
commit a06308f673
2 changed files with 148 additions and 4 deletions

View File

@ -1,14 +1,134 @@
#include <string> #include <string>
#include <vector>
#include <functional>
#include <any>
namespace argparse { namespace argparse {
struct Argument {
std::vector<std::string> mNames;
std::string mHelp;
std::function<std::any()> mDefaultValue;
std::function<std::any(const std::string&)> mAction;
std::any mValue;
std::string mRawValue;
Argument() :
mNames({}),
mHelp(""),
mDefaultValue(nullptr),
mAction(nullptr),
mValue(nullptr),
mRawValue("") {}
Argument& help(const std::string& aHelp) {
mHelp = aHelp;
return *this;
}
Argument& default_value(std::function<std::any()> aDefaultValue) {
mDefaultValue = aDefaultValue;
return *this;
}
Argument& action(std::function<std::any(const std::string&)> aAction) {
mAction = aAction;
return *this;
}
template <typename T>
T get() {
if (!mValue.has_value()) {
if (mDefaultValue != nullptr) {
return std::any_cast<T>(mDefaultValue());
}
else
return T();
}
else {
if (mRawValue != "")
return std::any_cast<T>(mValue);
else {
if (mDefaultValue != nullptr)
return std::any_cast<T>(mDefaultValue());
else
return T();
}
}
}
};
class ArgumentParser { class ArgumentParser {
public: public:
ArgumentParser(const std::string& program_name) : ArgumentParser(const std::string& aProgramName) :
program_name_(program_name) {} mProgramName(aProgramName) {}
template<typename T, typename... Targs>
Argument& add_argument(T value, Targs... Fargs) {
std::shared_ptr<Argument> tArgument = std::make_shared<Argument>();
tArgument->mNames.push_back(value);
add_argument_internal(tArgument, Fargs...);
mArguments.push_back(tArgument);
return *tArgument;
}
void parse_args(int argc, char * argv[]) {
for (int i = 1; i < argc; i++) {
for (auto& tArgument : mArguments) {
auto tIndex = std::find(tArgument->mNames.begin(), tArgument->mNames.end(), argv[i]);
if (tIndex != tArgument->mNames.end()) {
i = i + 1;
if (i < argc) {
tArgument->mRawValue = argv[i];
if (tArgument->mAction != nullptr)
tArgument->mValue = tArgument->mAction(argv[i]);
else {
if (tArgument->mDefaultValue != nullptr)
tArgument->mValue = tArgument->mDefaultValue();
else
tArgument->mValue = std::string(argv[i]);
}
}
}
}
}
}
Argument& operator[](const char * key) {
for (auto& tArgument : mArguments) {
auto tIndex = std::find(tArgument->mNames.begin(), tArgument->mNames.end(), key);
if (tIndex != tArgument->mNames.end()) {
return *tArgument;
}
}
}
template <typename T = std::string>
T get(const char * aArgumentName) {
for (auto& tArgument : mArguments) {
auto tIndex = std::find(tArgument->mNames.begin(), tArgument->mNames.end(), aArgumentName);
if (tIndex != tArgument->mNames.end()) {
return tArgument->get<T>();
}
}
return T();
}
private: private:
std::string program_name_; Argument& add_argument_internal(std::shared_ptr<Argument> aArgument) {
return *aArgument;
}
template<typename T, typename... Targs>
Argument& add_argument_internal(std::shared_ptr<Argument> aArgument, T aArgumentName, Targs... Fargs) {
aArgument->mNames.push_back(aArgumentName);
add_argument_internal(aArgument, Fargs...);
return *aArgument;
}
std::string mProgramName;
std::vector<std::shared_ptr<Argument>> mArguments;
}; };
} }

View File

@ -1,5 +1,29 @@
#include <iostream>
#include <argparse.hpp> #include <argparse.hpp>
using namespace argparse;
int main() { int main(int argc, char * argv[]) {
ArgumentParser program("test");
program.add_argument("--config")
.help("Path to input file")
.default_value([]() { return std::string{"config.yml"}; });
program.add_argument("-n", "--num_iterations")
.help("Number of iterations")
.action([](const std::string& value) { return std::stoi(value); });
program.add_argument("-v", "--verbose", "VERBOSE")
.default_value([]() { return true; });
program.parse_args(argc, argv);
auto config_file = program.get<std::string>("--config");
auto num_iters = program.get<int>("-n");
auto verbose = program.get<bool>("-v");
std::cout << config_file << std::endl;
std::cout << num_iters << std::endl;
std::cout << verbose << std::endl;
return 0; return 0;
} }