ComPPare 1.0.0
Loading...
Searching...
No Matches
plugin.hpp
Go to the documentation of this file.
1/*
2
3Copyright 2025 | Leong Fan FUNG | funglf | stanleyfunglf@gmail.com
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the “Software”), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21SOFTWARE.
22
23*/
24
33#pragma once
34#include <concepts>
35#include <utility>
36#include <iomanip>
37#include <stdexcept>
38#include <sstream>
39#include <string>
40#include <vector>
41
42namespace comppare::plugin
43{
58 template <class InTup, class OutTup>
59 class Plugin
60 {
61 public:
62 virtual ~Plugin() = default;
63 virtual void initialize(int & /*argc*/, char ** /*argv*/) {}
64 virtual void run() {}
65 };
66
80 template <template <class, class> class P, class InTup, class OutTup, class Func>
81 concept ValidPlugin =
82 requires { { P<InTup, OutTup>::instance() } -> std::same_as<std::shared_ptr<P<InTup, OutTup>>>; } &&
83 requires(const std::string &name, Func &&user_fn, const InTup &inputs, OutTup &outputs) { std::declval<P<InTup, OutTup> &>().register_impl(name, user_fn, inputs, outputs); } &&
84 std::derived_from<P<InTup, OutTup>, plugin::Plugin<InTup, OutTup>>;
85
107 {
108 public:
109 explicit PluginArgParser(std::string header, bool strict_missing_value = false)
110 : header_(std::move(header)), strict_(strict_missing_value) {}
111
116 ~PluginArgParser() = default;
117
118 [[nodiscard]] std::pair<int, char **> parse(int argc, char **argv)
119 {
120 args_.clear();
121 cargv_.clear();
122
123 if (argc <= 0 || argv == nullptr || argv[0] == nullptr)
124 {
125 args_.push_back(header_.empty() ? "program" : header_);
126 }
127 else
128 {
129 args_.emplace_back(argv[0]);
130 }
131
132 const std::string eq_prefix = header_ + "=";
133 std::vector<std::string> tokens;
134
135 for (int i = 1; i < argc; ++i)
136 {
137 if (!argv || argv[i] == nullptr)
138 break;
139 const std::string cur(argv[i]);
140
141 if (starts_with(cur, eq_prefix))
142 {
143 const std::string value = cur.substr(eq_prefix.size());
144 append_tokens(tokens, value);
145 }
146 else if (cur == header_)
147 {
148 if (i + 1 < argc && argv[i + 1] != nullptr)
149 {
150 const std::string value(argv[++i]); // consume value
151 append_tokens(tokens, value);
152 }
153 else if (strict_)
154 {
155 throw std::invalid_argument(header_ + " requires a value");
156 }
157 }
158 }
159
160 for (const auto &t : tokens)
161 args_.push_back(t);
162
163 cargv_.reserve(args_.size() + 1);
164 for (const auto &s : args_)
165 cargv_.push_back(const_cast<char *>(s.c_str()));
166 cargv_.push_back(nullptr);
167
168 return {static_cast<int>(args_.size()), cargv_.data()};
169 }
170
171 [[nodiscard]] int argc() const { return static_cast<int>(args_.size()); }
172 [[nodiscard]] char **argv() { return cargv_.data(); } // valid after parse()
173 [[nodiscard]] const std::vector<std::string> &args() const { return args_; }
174
175 private:
176 std::string header_;
178 std::vector<std::string> args_;
179 std::vector<char *> cargv_;
180
181 static bool starts_with(const std::string &s, const std::string &prefix)
182 {
183 return s.size() >= prefix.size() && s.compare(0, prefix.size(), prefix) == 0;
184 }
185
186 // shell-like split that respects quotes: R"(--x "a b" c)" -> {"--x","a b","c"}
187 static std::vector<std::string> split_shell_like(const std::string &s)
188 {
189 std::vector<std::string> out;
190 std::istringstream iss(s);
191 std::string tok;
192 while (iss >> std::quoted(tok))
193 out.push_back(tok);
194 return out;
195 }
196
197 static void append_tokens(std::vector<std::string> &dst, const std::string &value)
198 {
199 auto toks = split_shell_like(value);
200 dst.insert(dst.end(), toks.begin(), toks.end());
201 }
202 };
203
204} // namespace comppare::plugin
Argument parser for plugin command-line arguments.
Definition plugin.hpp:107
PluginArgParser(std::string header, bool strict_missing_value=false)
Definition plugin.hpp:109
const std::vector< std::string > & args() const
Definition plugin.hpp:173
std::vector< char * > cargv_
Definition plugin.hpp:179
std::string header_
Definition plugin.hpp:176
static std::vector< std::string > split_shell_like(const std::string &s)
Definition plugin.hpp:187
PluginArgParser & operator=(const PluginArgParser &)=delete
PluginArgParser(PluginArgParser &&)=default
bool strict_
Definition plugin.hpp:177
PluginArgParser & operator=(PluginArgParser &&)=default
int argc() const
Definition plugin.hpp:171
std::pair< int, char ** > parse(int argc, char **argv)
Definition plugin.hpp:118
static void append_tokens(std::vector< std::string > &dst, const std::string &value)
Definition plugin.hpp:197
std::vector< std::string > args_
Definition plugin.hpp:178
static bool starts_with(const std::string &s, const std::string &prefix)
Definition plugin.hpp:181
PluginArgParser(const PluginArgParser &)=delete
char ** argv()
Definition plugin.hpp:172
Base class for plugins in the ComPPare framework.
Definition plugin.hpp:60
virtual void run()
Definition plugin.hpp:64
virtual ~Plugin()=default
virtual void initialize(int &, char **)
Definition plugin.hpp:63
Concept for a valid plugin class.
Definition plugin.hpp:81
Definition google_benchmark.hpp:51