Toolbox snapshot
The Reactive C++ Toolbox
Loading...
Searching...
No Matches
Options.hpp
Go to the documentation of this file.
1// The Reactive C++ Toolbox.
2// Copyright (C) 2013-2019 Swirly Cloud Limited
3// Copyright (C) 2022 Reactive Markets Limited
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17#ifndef TOOLBOX_UTIL_OPTIONS_HPP
18#define TOOLBOX_UTIL_OPTIONS_HPP
19
27
30
31#include <map>
32#include <variant>
33
34namespace toolbox {
35inline namespace util {
36
37class NoOp {};
38class Help {};
39
40template <typename DerivedT>
41class Presence {
42 public:
44
46 {
47 presence_ = Required;
48 return *static_cast<DerivedT*>(this);
49 }
50
51 Type presence() const noexcept { return presence_; }
52
53 private:
54 Type presence_{Optional};
55};
56
57class Value : public Presence<Value> {
58
59 public:
60 template <typename VarT>
61 explicit Value(VarT& var)
62 : func_{[&var](std::string_view arg) { var = from_string<VarT>(arg); }}
63 {
64 }
65
66 template <typename VarT, typename AllocT>
67 explicit Value(std::vector<VarT, AllocT>& var)
68 : func_{[&var](std::string_view arg) { var.push_back(from_string<VarT>(arg)); }}
69 {
70 }
71
72 template <typename ValueT>
73 Value& default_value(const ValueT& value)
74 {
75 if constexpr (is_string<ValueT>::value) {
76 func_(value);
77 } else {
78 func_(std::to_string(value));
79 }
80 return *this;
81 }
83 {
84 multitoken_ = true;
85 return *this;
86 }
87
88 private:
89 friend class Options;
90
91 void run(std::string_view arg)
92 {
93 func_(arg);
94 set_ = true;
95 }
96
97 bool set() const noexcept { return set_; }
98
99 std::function<void(std::string_view)> func_;
100 bool set_{false};
101 bool multitoken_{false};
102};
103
104class Switch : public Presence<Switch> {
105 public:
106 Switch(bool& flag) // NOLINT(hicpp-explicit-conversions)
107 : flag_{flag}
108 {
109 }
110
111 private:
112 friend class Options;
113
114 void run() { flag_ = true; }
115
116 bool& flag_;
117};
118
120
121 struct OptionCompare {
122 using is_transparent = void;
123 bool operator()(const std::string& lhs, const std::string& rhs) const noexcept
124 {
125 return lhs < rhs;
126 }
127 bool operator()(const std::string& lhs, std::string_view rhs) const noexcept
128 {
129 return lhs < rhs;
130 }
131 bool operator()(std::string_view lhs, const std::string& rhs) const noexcept
132 {
133 return lhs < rhs;
134 }
135 };
136
137 using Data = std::variant<Value, Help, NoOp, Switch>;
138
139 struct OptionData : RefCount<OptionData, ThreadUnsafePolicy> {
140 template <typename DataT>
141 OptionData(char short_opt, const std::string& long_opt, DataT data, std::string description)
142 : long_opt{long_opt}
143 , data{std::move(data)}
144 , description{std::move(description)}
145 {
146 if (short_opt) {
147 this->short_opt.push_back(short_opt);
148 }
149 }
150 const std::string& opt() const noexcept { return long_opt.empty() ? short_opt : long_opt; }
151
152 std::string short_opt, long_opt;
153 Data data;
154 std::string description;
155 };
156
157 using OptionDataPtr = boost::intrusive_ptr<OptionData>;
158
159 public:
160 explicit Options(std::string description = "");
161
162 template <typename DataT>
163 Options& operator()(const std::string& long_opt, DataT&& option_data,
164 std::string description = "")
165 {
166 this->operator()(0, long_opt, std::forward<DataT>(option_data), std::move(description));
167 return *this;
168 }
169
170 template <typename DataT>
171 Options& operator()(char short_opt, const std::string& long_opt, DataT&& data,
172 std::string description = "")
173 {
174 auto opt_data = make_intrusive<OptionData>(short_opt, long_opt, std::forward<DataT>(data),
175 std::move(description));
176 help_.push_back(opt_data);
177 if (short_opt) {
178 const bool inserted = opts_.emplace(opt_data->short_opt, opt_data).second;
179 if (!inserted) {
180 throw std::runtime_error{"attempting to register duplicate option "
181 + opt_data->short_opt};
182 }
183 }
184 if (!long_opt.empty()) {
185 const bool inserted = opts_.emplace(long_opt, opt_data).second;
186 if (!inserted) {
187 throw std::runtime_error{"attempting to register duplicate option " + long_opt};
188 }
189 }
190 return *this;
191 }
192
193 template <typename DataT>
194 Options& operator()(DataT data, std::string /*description*/ = "")
195 {
196 positional_.push_back(std::move(data));
197 return *this;
198 }
199
200 template <typename DataT>
201 Options& operator()(char short_opt, DataT&& option_data, std::string description = "")
202 {
203 this->operator()(short_opt, "", std::forward<DataT>(option_data), std::move(description));
204 return *this;
205 }
206
207 bool operator[](const std::string& long_opt) const noexcept;
208 bool operator[](char short_opt) const noexcept;
209 void parse(int argc, const char* const argv[]);
210
211 private:
212 friend std::ostream& operator<<(std::ostream& out, const Options& options);
213
214 std::string description_;
215 using HelpVec = std::vector<OptionDataPtr>;
216 HelpVec help_;
217 using OptsMap = std::map<std::string, OptionDataPtr, OptionCompare>;
218 OptsMap opts_;
219 using DataVec = std::vector<Data>;
220 DataVec positional_;
221};
222
223TOOLBOX_API std::ostream& operator<<(std::ostream& out, const Options& options);
224
225} // namespace util
226} // namespace toolbox
227
228#endif // TOOLBOX_UTIL_OPTIONS_HPP
#define TOOLBOX_API
Definition Config.h:39
ostream & operator<<(ostream &os, const sockaddr_in &sa)
Definition Endpoint.cpp:180
Options & operator()(const std::string &long_opt, DataT &&option_data, std::string description="")
Definition Options.hpp:163
Options & operator()(DataT data, std::string="")
Definition Options.hpp:194
Options & operator()(char short_opt, const std::string &long_opt, DataT &&data, std::string description="")
Definition Options.hpp:171
Options & operator()(char short_opt, DataT &&option_data, std::string description="")
Definition Options.hpp:201
DerivedT & required()
Definition Options.hpp:45
Type presence() const noexcept
Definition Options.hpp:51
Base class for atomic referenced counted objects.
Definition RefCount.hpp:61
Value & multitoken()
Definition Options.hpp:82
Value(std::vector< VarT, AllocT > &var)
Definition Options.hpp:67
Value & default_value(const ValueT &value)
Definition Options.hpp:73
STL namespace.
const DataT & data(const MsgEvent &ev) noexcept
Definition Event.hpp:54
double var(const VarAccum &v) noexcept
Definition Math.hpp:106
constexpr auto bind() noexcept
Definition Slot.hpp:92