Page MenuHomec4science

auto_argument.hh
No OneTemporary

File Metadata

Created
Mon, Jun 24, 15:20

auto_argument.hh

#ifndef __AUTO_ARGUMENT_HH__
#define __AUTO_ARGUMENT_HH__
/*****************************************************************/
#include <any>
#include <cxxabi.h>
#include <memory>
#include <sstream>
#include <typeinfo>
/*****************************************************************/
namespace AutoDispatch {
struct Argument {
Argument() = default;
virtual ~Argument() = default;
template <typename T> T &cast() { return dynamic_cast<T &>(*this); }
virtual void printself(std::ostream &os) const {
os << "(" << this << ")" << Argument::demangle(typeid(*this).name());
};
static std::string demangle(const char *name) {
int status = -4; // some arbitrary value to eliminate the compiler warning
std::unique_ptr<char, void (*)(void *)> res{
abi::__cxa_demangle(name, NULL, NULL, &status), std::free};
auto demangled_name = res.get();
return (status == 0) ? demangled_name : name;
}
};
/*****************************************************************/
inline std::ostream &operator<<(std::ostream &os, const Argument &a) {
a.printself(os);
return os;
}
/*****************************************************************/
struct bad_argument_cast : public std::exception {
const char *what() const throw() override { return str.c_str(); };
std::string str;
};
template <typename... Ts>
struct bad_argument_cast_tmpl : public bad_argument_cast {
bad_argument_cast_tmpl(Argument &obj) : real_type(typeid(obj)) {
std::stringstream sstr;
sstr << "cannot cast '" << Argument::demangle(real_type.name())
<< "' into any of: ("
<< (Argument::demangle(typeid(Ts).name()) + ", " + ...)
<< " ...)";
str = sstr.str();
}
const std::type_info &real_type;
};
/*****************************************************************/
class no_argument : public std::exception {
const char *what() const throw() override {
return "ArgumentAny has no value";
};
};
/*****************************************************************/
class ArgumentAny {
public:
ArgumentAny() : ptr(nullptr), s_ptr(nullptr) {}
ArgumentAny(const ArgumentAny &other)
: ptr(other.ptr), s_ptr(other.s_ptr), obj(other.obj){};
template <typename T>
constexpr static bool is_Argument =
std::is_base_of_v<Argument, std::decay_t<T>>;
template <typename T>
constexpr static bool is_ArgumentAny =
std::is_base_of_v<ArgumentAny, std::decay_t<T>>;
template <typename T, typename Ret>
using if_Argument = std::enable_if_t<is_Argument<T>, Ret>;
template <typename T, typename Ret>
using if_not_Argument =
std::enable_if_t<not(is_Argument<T> or is_ArgumentAny<T>), Ret>;
ArgumentAny &operator=(ArgumentAny &val) {
this->ptr = val.ptr;
this->s_ptr = val.s_ptr;
this->obj = val.obj;
return *this;
}
ArgumentAny &operator=(ArgumentAny &&val) {
obj = std::move(val.obj);
ptr = val.ptr;
s_ptr = val.s_ptr;
return *this;
}
template <typename T>
if_Argument<T, ArgumentAny &> operator=(std::shared_ptr<T> &val) {
s_ptr = val;
ptr = nullptr;
obj.reset();
return *this;
}
template <typename T> if_Argument<T, ArgumentAny &> operator=(T &val) {
s_ptr.reset();
ptr = &val;
obj.reset();
return *this;
}
template <typename T> if_Argument<T, ArgumentAny &> &operator=(T &&val) {
s_ptr = std::make_shared<T>(std::forward<T>(val));
ptr = nullptr;
obj.reset();
return *this;
}
template <typename T> if_not_Argument<T, ArgumentAny &> &operator=(T &&val) {
obj = std::forward<T>(val);
ptr = nullptr;
s_ptr.reset();
return *this;
}
template <typename T = Argument> if_Argument<T, T &> get() {
if (ptr)
return ptr->cast<T>();
else if (s_ptr)
return s_ptr.get()->cast<T>();
throw no_argument();
}
template <typename T = Argument> if_Argument<T, const T &> get() const {
if (ptr)
return ptr->cast<T>();
else if (s_ptr)
return s_ptr.get()->cast<T>();
throw no_argument();
}
template <typename T> if_not_Argument<T, T> get() {
return std::any_cast<T>(obj);
}
bool has_value() const {
return this->ptr != nullptr || s_ptr != nullptr || obj.has_value();
}
void reset() {
if (ptr)
ptr = nullptr;
if (s_ptr)
return s_ptr.reset();
obj.reset();
}
private:
Argument *ptr;
std::shared_ptr<Argument> s_ptr;
std::any obj;
};
/*****************************************************************/
template <typename... possible_types> struct argument {
argument() = default;
template <typename T> argument(T &&a) { arg = a; }
template <typename T> argument &operator=(T &&a) {
arg = std::forward<T>(a);
return *this;
}
template <typename F> void visit(F &&func) {
bool casted = false;
casted = (this->cast_and_call<possible_types>(func) | ...);
if (not casted)
throw bad_argument_cast_tmpl<possible_types...>(arg.get());
}
bool has_value() { return arg.has_value(); }
private:
template <typename T, typename F> bool cast_and_call(F &&func) {
try {
func(arg.get<T>());
return true;
} catch (std::bad_cast &e) {
return false;
}
return false;
}
ArgumentAny arg;
};
template <typename... possible_types>
struct argument<std::tuple<possible_types...>>
: public argument<possible_types...> {
using argument<possible_types...>::operator=;
};
/*****************************************************************/
} // namespace AutoDispatch
#endif //__AUTO_ARGUMENT_HH__

Event Timeline