File indexing completed on 2025-02-21 09:58:12
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 #pragma once
0028
0029 #include <cassert>
0030 #include <cstdint>
0031 #include <functional>
0032 #include <ostream>
0033 #include <stdexcept>
0034 #include <string>
0035 #include <type_traits>
0036 #include <unordered_map>
0037 #include <utility>
0038 #include <vector>
0039
0040 namespace dfe {
0041
0042
0043 class Variable final {
0044 public:
0045
0046 enum class Type { Empty, Boolean, Integer, Float, String };
0047
0048 Variable() : m_type(Type::Empty) {}
0049 Variable(Variable&& v) { *this = std::move(v); }
0050 Variable(const Variable& v) { *this = v; }
0051 explicit Variable(std::string&& s)
0052 : m_string(std::move(s)), m_type(Type::String) {}
0053 explicit Variable(const std::string& s) : Variable(std::string(s)) {}
0054 explicit Variable(const char* s) : Variable(std::string(s)) {}
0055
0056 template<typename I, typename = std::enable_if_t<std::is_integral<I>::value>>
0057 explicit Variable(I integer)
0058 : m_integer(static_cast<int64_t>(integer)), m_type(Type::Integer) {}
0059 explicit Variable(double d) : m_float(d), m_type(Type::Float) {}
0060 explicit Variable(float f) : Variable(static_cast<double>(f)) {}
0061 explicit Variable(bool b) : m_boolean(b), m_type(Type::Boolean) {}
0062 ~Variable() = default;
0063
0064 Variable& operator=(Variable&& v);
0065 Variable& operator=(const Variable& v);
0066
0067
0068 static Variable parse_as(const std::string& str, Type type);
0069
0070
0071
0072
0073 constexpr bool operator!() const { return m_type == Type::Empty; }
0074
0075 constexpr explicit operator bool() const { return !!(*this); }
0076
0077 constexpr Type type() const { return m_type; }
0078
0079
0080
0081 template<typename T>
0082 auto as() const;
0083
0084 private:
0085 template<typename T>
0086 struct Converter;
0087 template<typename I>
0088 struct IntegerConverter;
0089
0090 union {
0091 int64_t m_integer;
0092 double m_float;
0093 bool m_boolean;
0094 };
0095
0096
0097 std::string m_string;
0098 Type m_type;
0099
0100 friend std::ostream& operator<<(std::ostream& os, const Variable& v);
0101 };
0102
0103
0104
0105
0106 class Dispatcher {
0107 public:
0108
0109 using Interface = std::function<Variable(const std::vector<Variable>&)>;
0110
0111
0112
0113
0114
0115
0116
0117 void add(
0118 std::string name, Interface&& func, std::vector<Variable::Type>&& arg_types,
0119 std::string help = std::string());
0120
0121
0122
0123 template<typename R, typename... Args>
0124 void add(
0125 std::string name, std::function<R(Args...)>&& func,
0126 std::string help = std::string());
0127 template<typename R, typename... Args>
0128 void add(
0129 std::string name, R (*func)(Args...), std::string help = std::string());
0130 template<typename T, typename R, typename... Args>
0131 void add(
0132 std::string name, R (T::*member_func)(Args...), T* t,
0133 std::string help = std::string());
0134
0135
0136 template<typename... Args>
0137 Variable call(const std::string& name, Args&&... args);
0138
0139 Variable call_parsed(
0140 const std::string& name, const std::vector<std::string>& args);
0141
0142 Variable call_native(
0143 const std::string& name, const std::vector<Variable>& args);
0144
0145
0146 std::vector<std::string> commands() const;
0147
0148 const std::string& help(const std::string& name) const;
0149
0150 private:
0151 struct Command {
0152 Interface func;
0153 std::vector<Variable::Type> argument_types;
0154 std::string help;
0155 };
0156 std::unordered_map<std::string, Command> m_commands;
0157 };
0158
0159
0160
0161 inline Variable
0162 Variable::parse_as(const std::string& str, Type type) {
0163 if (type == Type::Boolean) {
0164 return Variable((str == "true"));
0165 } else if (type == Type::Integer) {
0166 return Variable(std::stoll(str));
0167 } else if (type == Type::Float) {
0168 return Variable(std::stod(str));
0169 } else if (type == Type::String) {
0170 return Variable(str);
0171 } else {
0172 return Variable();
0173 }
0174 }
0175
0176 inline std::ostream&
0177 operator<<(std::ostream& os, const Variable& v) {
0178 if (v.type() == Variable::Type::Boolean) {
0179 os << (v.m_boolean ? "true" : "false");
0180 } else if (v.m_type == Variable::Type::Integer) {
0181 os << v.m_integer;
0182 } else if (v.m_type == Variable::Type::Float) {
0183 os << v.m_float;
0184 } else if (v.m_type == Variable::Type::String) {
0185 os << v.m_string;
0186 }
0187 return os;
0188 }
0189
0190 inline Variable&
0191 Variable::operator=(Variable&& v) {
0192
0193 if (this == &v) {
0194 return *this;
0195 }
0196 if (v.m_type == Type::Boolean) {
0197 m_boolean = v.m_boolean;
0198 } else if (v.m_type == Type::Integer) {
0199 m_integer = v.m_integer;
0200 } else if (v.m_type == Type::Float) {
0201 m_float = v.m_float;
0202 } else if (v.m_type == Type::String) {
0203 m_string = std::move(v.m_string);
0204 }
0205 m_type = v.m_type;
0206 return *this;
0207 }
0208
0209 inline Variable&
0210 Variable::operator=(const Variable& v) {
0211 if (v.m_type == Type::Boolean) {
0212 m_boolean = v.m_boolean;
0213 } else if (v.m_type == Type::Integer) {
0214 m_integer = v.m_integer;
0215 } else if (v.m_type == Type::Float) {
0216 m_float = v.m_float;
0217 } else if (v.m_type == Type::String) {
0218 m_string = v.m_string;
0219 }
0220 m_type = v.m_type;
0221 return *this;
0222 }
0223
0224 template<>
0225 struct Variable::Converter<bool> {
0226 static constexpr Type type() { return Type::Boolean; }
0227 static constexpr bool as_t(const Variable& v) { return v.m_boolean; }
0228 };
0229 template<>
0230 struct Variable::Converter<float> {
0231 static constexpr Type type() { return Type::Float; }
0232 static constexpr float as_t(const Variable& v) {
0233 return static_cast<float>(v.m_float);
0234 }
0235 };
0236 template<>
0237 struct Variable::Converter<double> {
0238 static constexpr Type type() { return Type::Float; }
0239 static constexpr double as_t(const Variable& v) { return v.m_float; }
0240 };
0241 template<>
0242 struct Variable::Converter<std::string> {
0243 static constexpr Type type() { return Type::String; }
0244 static constexpr const std::string& as_t(const Variable& v) {
0245 return v.m_string;
0246 }
0247 };
0248 template<typename I>
0249 struct Variable::IntegerConverter {
0250 static constexpr Type type() { return Type::Integer; }
0251 static constexpr I as_t(const Variable& v) {
0252 return static_cast<I>(v.m_integer);
0253 }
0254 };
0255 template<>
0256 struct Variable::Converter<int8_t> : Variable::IntegerConverter<int8_t> {};
0257 template<>
0258 struct Variable::Converter<int16_t> : Variable::IntegerConverter<int16_t> {};
0259 template<>
0260 struct Variable::Converter<int32_t> : Variable::IntegerConverter<int32_t> {};
0261 template<>
0262 struct Variable::Converter<int64_t> : Variable::IntegerConverter<int64_t> {};
0263 template<>
0264 struct Variable::Converter<uint8_t> : Variable::IntegerConverter<uint8_t> {};
0265 template<>
0266 struct Variable::Converter<uint16_t> : Variable::IntegerConverter<uint16_t> {};
0267 template<>
0268 struct Variable::Converter<uint32_t> : Variable::IntegerConverter<uint32_t> {};
0269 template<>
0270 struct Variable::Converter<uint64_t> : Variable::IntegerConverter<uint64_t> {};
0271
0272 template<typename T>
0273 inline auto
0274 Variable::as() const {
0275 if (m_type != Variable::Converter<T>::type()) {
0276 throw std::invalid_argument(
0277 "Requested type is incompatible with stored type");
0278 }
0279 return Variable::Converter<T>::as_t(*this);
0280 }
0281
0282
0283
0284 namespace dispatcher_impl {
0285 namespace {
0286
0287
0288 template<typename R, typename... Args>
0289 struct InterfaceWrappper {
0290 std::function<R(Args...)> func;
0291
0292 Variable operator()(const std::vector<Variable>& args) {
0293 return call(args, std::index_sequence_for<Args...>());
0294 }
0295 template<std::size_t... I>
0296 Variable call(const std::vector<Variable>& args, std::index_sequence<I...>) {
0297 return Variable(func(args.at(I).as<typename std::decay_t<Args>>()...));
0298 }
0299 };
0300
0301
0302 template<typename... Args>
0303 struct InterfaceWrappper<void, Args...> {
0304 std::function<void(Args...)> func;
0305
0306 Variable operator()(const std::vector<Variable>& args) {
0307 return call(args, std::index_sequence_for<Args...>());
0308 }
0309 template<std::size_t... I>
0310 Variable call(const std::vector<Variable>& args, std::index_sequence<I...>) {
0311 func(args.at(I).as<typename std::decay_t<Args>>()...);
0312 return Variable();
0313 }
0314 };
0315
0316 template<typename R, typename... Args>
0317 inline Dispatcher::Interface
0318 make_wrapper(std::function<R(Args...)>&& function) {
0319 return InterfaceWrappper<R, Args...>{std::move(function)};
0320 }
0321
0322 template<typename R, typename... Args>
0323 std::vector<Variable::Type>
0324 make_types(const std::function<R(Args...)>&) {
0325 return {Variable(std::decay_t<Args>()).type()...};
0326 }
0327
0328 }
0329 }
0330
0331 inline void
0332 Dispatcher::add(
0333 std::string name, Dispatcher::Interface&& func,
0334 std::vector<Variable::Type>&& arg_types, std::string help) {
0335 if (name.empty()) {
0336 throw std::invalid_argument("Can not register command with empty name");
0337 }
0338 if (m_commands.count(name)) {
0339 throw std::invalid_argument(
0340 "Can not register command '" + name + "' more than once");
0341 }
0342 m_commands[std::move(name)] =
0343 Command{std::move(func), std::move(arg_types), std::move(help)};
0344 }
0345
0346 template<typename R, typename... Args>
0347 inline void
0348 Dispatcher::add(
0349 std::string name, std::function<R(Args...)>&& func, std::string help) {
0350 auto args = dispatcher_impl::make_types(func);
0351 add(
0352 std::move(name), dispatcher_impl::make_wrapper(std::move(func)),
0353 std::move(args), std::move(help));
0354 }
0355
0356 template<typename R, typename... Args>
0357 inline void
0358 Dispatcher::add(std::string name, R (*func)(Args...), std::string help) {
0359 assert(func && "Function pointer must be non-null");
0360 add(std::move(name), std::function<R(Args...)>(func), std::move(help));
0361 }
0362
0363 template<typename T, typename R, typename... Args>
0364 inline void
0365 Dispatcher::add(
0366 std::string name, R (T::*member_func)(Args...), T* t, std::string help) {
0367 assert(member_func && "Member function pointer must be non-null");
0368 assert(t && "Object pointer must be non-null");
0369 add(
0370 std::move(name), std::function<R(Args...)>([=](Args... args) {
0371 return (t->*member_func)(args...);
0372 }),
0373 std::move(help));
0374 }
0375
0376 inline Variable
0377 Dispatcher::call_native(
0378 const std::string& name, const std::vector<Variable>& args) {
0379 auto cmd = m_commands.find(name);
0380 if (cmd == m_commands.end()) {
0381 throw std::invalid_argument("Unknown command '" + name + "'");
0382 }
0383 if (args.size() != cmd->second.argument_types.size()) {
0384 throw std::invalid_argument("Invalid number of arguments");
0385 }
0386 return cmd->second.func(args);
0387 }
0388
0389 inline Variable
0390 Dispatcher::call_parsed(
0391 const std::string& name, const std::vector<std::string>& args) {
0392
0393 auto cmd = m_commands.find(name);
0394 if (cmd == m_commands.end()) {
0395 throw std::invalid_argument("Unknown command '" + name + "'");
0396 }
0397 if (args.size() != cmd->second.argument_types.size()) {
0398 throw std::invalid_argument("Invalid number of arguments");
0399 }
0400
0401 std::vector<Variable> vargs;
0402 for (std::size_t i = 0; i < args.size(); ++i) {
0403 vargs.push_back(Variable::parse_as(args[i], cmd->second.argument_types[i]));
0404 }
0405 return cmd->second.func(vargs);
0406 }
0407
0408 template<typename... Args>
0409 inline Variable
0410 Dispatcher::call(const std::string& name, Args&&... args) {
0411 return call_native(
0412 name, std::vector<Variable>{Variable(std::forward<Args>(args))...});
0413 }
0414
0415 inline std::vector<std::string>
0416 Dispatcher::commands() const {
0417 std::vector<std::string> cmds;
0418
0419 for (const auto& cmd : m_commands) {
0420 cmds.emplace_back(cmd.first);
0421 }
0422 return cmds;
0423 }
0424
0425 inline const std::string&
0426 Dispatcher::help(const std::string& name) const {
0427 return m_commands.at(name).help;
0428 }
0429
0430 }