flags-cpp/flags.h

107 lines
3.4 KiB
C
Raw Normal View History

2023-11-30 20:36:11 +00:00
#ifndef FLAGS_H
#define FLAGS_H
#include <functional>
#include <map>
#include <string>
#include <typeindex>
namespace Flags {
// utility functions
2023-12-01 14:22:58 +00:00
std::vector<std::string> split(const std::string& input, const char separator);
bool starts_with(const std::string& input, const std::string& start);
2023-11-30 20:36:11 +00:00
// flag base class
// should be abstract, don't use
class Flag {
std::string description;
bool found;
bool parsed;
2023-12-01 14:22:58 +00:00
protected:
2023-11-30 20:36:11 +00:00
void set_found(const bool found) { this->found = found; }
void set_parsed(const bool parsed) { this->parsed = parsed; }
2023-12-01 14:22:58 +00:00
public:
virtual const void* get_value_ptr() const = 0;
2023-11-30 20:36:11 +00:00
2023-12-01 14:22:58 +00:00
Flag(const std::string& description, const bool required) : description(description), found(!required), parsed(false) {}
2023-11-30 20:36:11 +00:00
2023-12-01 02:32:03 +00:00
virtual ~Flag(){};
2023-11-30 20:36:11 +00:00
2023-12-01 14:22:58 +00:00
const std::string& get_description() const { return description; }
2023-12-01 02:32:03 +00:00
bool get_parsed() const { return parsed; }
2023-12-01 14:22:58 +00:00
bool get_found() const { return found; }
2023-11-30 20:36:11 +00:00
2023-12-01 14:22:58 +00:00
virtual void parse(const std::string& arg) = 0;
2023-11-30 20:36:11 +00:00
};
// type of flag based parser classes' factory functions
2023-12-01 14:22:58 +00:00
typedef std::function<Flag*(const void*, const std::string&, const bool)> flag_constructor_t;
2023-11-30 20:36:11 +00:00
2023-12-01 02:32:03 +00:00
// use this class to create your own parser
2023-12-01 14:22:58 +00:00
template <typename T>
class FlagTemplate : public Flag {
protected:
2023-12-01 02:32:03 +00:00
T value;
2023-11-30 20:36:11 +00:00
2023-12-01 14:22:58 +00:00
public:
explicit FlagTemplate<T>(const void* default_value, const std::string& description, const bool required)
: Flag(description, required), value(*(T*)default_value) {}
2023-11-30 20:36:11 +00:00
2023-12-01 14:22:58 +00:00
const void* get_value_ptr() const override { return &value; };
2023-11-30 20:36:11 +00:00
};
2023-12-01 14:22:58 +00:00
#define PARSER(name, type, func) \
class name : public FlagTemplate<type> { \
using FlagTemplate<type>::FlagTemplate; \
\
public: \
static Flag* make(const void* default_value, const std::string& description, const bool required) { \
return new name(default_value, description, required); \
} \
void parse(const std::string& arg) override func \
2023-12-01 02:32:03 +00:00
}; // namespace Flags
2023-11-30 20:36:11 +00:00
// flag holder, parsing orchestrator
class Parser {
2023-12-01 14:22:58 +00:00
private:
2023-11-30 20:36:11 +00:00
const std::string prefix;
const std::string help_text;
2023-12-01 14:22:58 +00:00
std::map<std::string, Flag*> flags;
2023-11-30 20:36:11 +00:00
std::map<std::type_index, flag_constructor_t> constructors;
2023-12-01 14:22:58 +00:00
public:
Parser(const std::string& prefix, const std::string& help_text);
2023-11-30 20:36:11 +00:00
Parser() : Parser("--", "Help:") {}
~Parser() {
for (auto f : flags) {
delete f.second;
}
}
2023-12-01 02:32:03 +00:00
template <typename T>
void set_parser(flag_constructor_t constructor_function) {
2023-11-30 20:36:11 +00:00
constructors[typeid(T)] = constructor_function;
}
template <typename T>
2023-12-01 14:22:58 +00:00
T* add(const std::string& name, const std::string& description, const bool required, T default_value) {
flags[name] = constructors[typeid(T)]((void*)&default_value, description, required);
return (T*)flags[name]->get_value_ptr();
2023-11-30 20:36:11 +00:00
}
2023-12-01 02:32:03 +00:00
unsigned get_found() const;
2023-11-30 20:36:11 +00:00
2023-12-01 02:32:03 +00:00
unsigned get_parsed() const;
2023-11-30 20:36:11 +00:00
2023-12-01 14:22:58 +00:00
bool parse(int argc, char** argv);
2023-11-30 20:36:11 +00:00
void help() const;
};
} // namespace Flags
#endif