-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcli.hpp
156 lines (123 loc) · 4.22 KB
/
cli.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#pragma once
#include <utility>
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include <memory>
#include <string>
class Switch {
public:
friend bool operator ==(const Switch& lhs, const Switch& rhs) {
auto lhsIds = lhs.identifiers();
auto rhsIds = rhs.identifiers();
if (lhsIds.size() != rhsIds.size())
return false;
for (auto i = 0; i < lhsIds.size(); i++) {
if (lhsIds[i] != rhsIds[i])
return false;
}
return true;
}
friend bool operator !=(const Switch& lhs, const Switch& rhs) {
return !(lhs == rhs);
}
friend bool operator <(const Switch& lhs, const Switch& rhs) {
auto lhsIds = lhs.identifiers();
auto rhsIds = rhs.identifiers();
if (lhsIds.size() != rhsIds.size())
return lhsIds.size() < rhsIds.size();
for (auto i = 0; i < lhsIds.size(); i++) {
if (lhsIds[i] < rhsIds[i])
return true;
}
return false;
}
friend bool operator >(const Switch& lhs, const Switch& rhs) {
return rhs < lhs;
}
friend bool operator <=(const Switch& lhs, const Switch& rhs) {
return !(lhs > rhs);
}
friend bool operator >=(const Switch& lhs, const Switch& rhs) {
return !(lhs < rhs);
}
virtual auto identifiers() const -> std::vector<std::string> = 0;
virtual auto hasValue() const -> bool = 0;
};
class Flag : public Switch {
public:
auto identifiers() const -> std::vector<std::string> override { return ids; }
auto hasValue() const -> bool override { return false; }
template<typename ...T>
explicit Flag(const T ...identifier) : ids { identifier... } {
static_assert(sizeof...(T) >= 1, "At least one identifier must be provided");
}
private:
const std::vector<std::string> ids;
};
class Option : public Switch {
public:
const char* defaultValue;
auto identifiers() const -> std::vector<std::string> override { return ids; }
auto hasValue() const -> bool override { return true; }
template<typename ...T>
explicit Option(const char* defaultValue, const T ...identifier)
: defaultValue(defaultValue), ids { identifier... } {
static_assert(sizeof...(T) >= 1, "At least one identifier must be provided");
}
private:
const std::vector<std::string> ids;
};
namespace std {
template<> struct hash<Switch> {
std::size_t operator ()(const Switch& s) const noexcept {
std::size_t hash = 1337;
for (const std::string& id : s.identifiers()) {
auto h = std::hash<std::string>{}(id);
hash = (((h * 97) << 2u) * hash) % 117649312;
}
return hash;
}
};
template<> struct hash<Flag> {
std::size_t operator ()(const Flag& f) const noexcept {
return std::hash<Switch>{}(f);
}
};
template<> struct hash<Option> {
std::size_t operator ()(const Option& f) const noexcept {
return std::hash<Switch>{}(f);
}
};
}
class CommandLineParseResult {
public:
const std::unordered_set<Flag> flags;
const std::unordered_map<Option, std::string> options;
auto hasFlag(const Flag& flag) -> bool {
auto search = flags.find(flag);
return search != flags.end();
}
auto hasOption(const Option& option) -> bool {
auto search = options.find(option);
return search != options.end();
}
auto getValue(const Option& option) -> std::string {
auto search = options.find(option);
if (search == options.end())
return option.defaultValue;
return search->second;
}
explicit CommandLineParseResult(std::unordered_set<Flag> flags, std::unordered_map<Option, std::string> options)
: flags(std::move(flags)), options(std::move(options)) { }
};
class CommandLineParser {
public:
const std::unordered_map<std::string, Switch*>& switches;
auto parse() -> CommandLineParseResult;
explicit CommandLineParser(const std::unordered_map<std::string, Switch*>& switches, int count, char** args)
: switches(switches), count(count), args(args) { }
private:
const int count;
char** args;
};