Page MenuHomec4science

auto_argument.hh
No OneTemporary

File Metadata

Created
Fri, Jul 5, 20:54

auto_argument.hh

#ifndef __AUTO_ARGUMENT_HH__
#define __AUTO_ARGUMENT_HH__
/*****************************************************************/
#include <any>
#include <cxxabi.h>
#include <memory>
#include <sstream>
#include <typeinfo>
// #include <iostream>
/*****************************************************************/
namespace AutoDispatch {
inline 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;
}
template <typename T> std::string obj_info(T &obj) {
std::stringstream sstr;
sstr << "(" << std::hex << "0x" << &obj << ")"
<< demangle(typeid(obj).name());
return sstr.str();
}
/*****************************************************************/
struct Argument {
Argument(){
// std::cerr << "allocate " << obj_info(*this) << std::endl;
};
virtual ~Argument(){
// std::cerr << "delete " << obj_info(*this) << std::endl;
};
template <typename T> T &cast() { return dynamic_cast<T &>(*this); }
virtual void printself(std::ostream &os) const { os << obj_info(*this); };
template <typename T> bool is_type() {
try {
this->cast<T>();
return true;
} catch (std::bad_cast &e) {
}
return false;
}
};
/*****************************************************************/
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(const std::type_info &type) : real_type(type) {
std::stringstream sstr;
sstr << "cannot cast '" << demangle(real_type.name()) << "' into any of: ("
<< (demangle(typeid(Ts).name()) + ", " + ...)
<< " ...)";
str = sstr.str();
}
const std::type_info &real_type;
};
template <> struct bad_argument_cast_tmpl<> : public bad_argument_cast {
bad_argument_cast_tmpl(const std::type_info &type) : real_type(type) {
std::stringstream sstr;
sstr << "cannot cast '" << demangle(real_type.name())
<< "' because there are no possible types";
str = sstr.str();
}
const std::type_info &real_type;
};
/*****************************************************************/
struct no_argument : public std::exception {
no_argument() {}
const char *what() const throw() override { return str.c_str(); };
std::string str;
};
/*****************************************************************/
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> bool is_type() { return this->get().is_type<T>(); }
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;
val.ptr = nullptr;
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) {
// std::cerr << "saving ptr " << obj_info(val) << std::endl;
s_ptr.reset();
ptr = &val;
obj.reset();
return *this;
}
template <typename T> if_Argument<T, ArgumentAny &> &operator=(T &&val) {
// std::cerr << "saving s_ptr " << obj_info(val) << std::endl;
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) {
// std::cerr << "saving any " << obj_info(val) << std::endl;
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_argument() const { return this->ptr != nullptr || s_ptr != nullptr; }
bool has_value() const {
return this->ptr != nullptr || s_ptr != nullptr || obj.has_value();
}
const std::type_info &type() const {
if (obj.has_value())
return obj.type();
const Argument &arg = this->get();
return typeid(arg);
}
void reset() {
if (ptr)
ptr = nullptr;
if (s_ptr)
return s_ptr.reset();
obj.reset();
}
private:
Argument *ptr{nullptr};
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.type());
}
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=;
};
template <> 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 &&) {
throw bad_argument_cast_tmpl<>(arg.type());
}
bool has_value() { return arg.has_value(); }
private:
ArgumentAny arg;
};
/*****************************************************************/
} // namespace AutoDispatch
#endif //__AUTO_ARGUMENT_HH__

Event Timeline