"src/scheme/Montee.hpp" did not exist on "5e55b997f679af8d8cb3ea49513512b29121beb9"
Select Git revision
ItemValue.hpp
BuiltinFunctionEmbedder.hpp 9.64 KiB
#ifndef BUILTIN_FUNCTION_EMBEDDER_HPP
#define BUILTIN_FUNCTION_EMBEDDER_HPP
#include <language/ast/ASTNodeDataType.hpp>
#include <language/utils/ASTNodeDataTypeTraits.hpp>
#include <language/utils/DataHandler.hpp>
#include <language/utils/DataVariant.hpp>
#include <language/utils/FunctionTable.hpp>
#include <utils/Demangle.hpp>
#include <utils/Exceptions.hpp>
#include <utils/PugsTraits.hpp>
#include <functional>
#include <memory>
#include <vector>
class IBuiltinFunctionEmbedder
{
public:
virtual size_t numberOfParameters() const = 0;
virtual ASTNodeDataType getReturnDataType() const = 0;
virtual std::vector<ASTNodeDataType> getParameterDataTypes() const = 0;
virtual DataVariant apply(const std::vector<DataVariant>&) const = 0;
IBuiltinFunctionEmbedder() = default;
IBuiltinFunctionEmbedder(const IBuiltinFunctionEmbedder&) = delete;
IBuiltinFunctionEmbedder(IBuiltinFunctionEmbedder&&) = delete;
virtual ~IBuiltinFunctionEmbedder() = default;
};
template <typename FX, typename... Args>
class BuiltinFunctionEmbedder
{
static_assert(std::is_class_v<BuiltinFunctionEmbedder<FX, Args...>>,
"wrong template parameters do not use <FX, Args...>, use <FX(Args...)>");
};
template <typename T>
inline constexpr bool is_const_ref_or_non_ref = (std::is_const_v<T> and std::is_lvalue_reference_v<T>) or
(not std::is_lvalue_reference_v<T>);
template <typename FX, typename... Args>
class BuiltinFunctionEmbedder<FX(Args...)> : public IBuiltinFunctionEmbedder
{
private:
std::function<FX(Args...)> m_f;
using ArgsTuple = std::tuple<std::decay_t<Args>...>;
template <size_t I>
PUGS_INLINE void
_copyValue(ArgsTuple& t, const std::vector<DataVariant>& v) const
{
std::visit(
[&](auto&& v_i) {
using Ti_Type = std::decay_t<decltype(std::get<I>(t))>;
using Vi_Type = std::decay_t<decltype(v_i)>;
if constexpr ((std::is_same_v<Vi_Type, Ti_Type>)) {
std::get<I>(t) = v_i;
} else if constexpr ((std::is_arithmetic_v<Vi_Type>)and(std::is_arithmetic_v<Ti_Type> or
std::is_same_v<Ti_Type, std::string>)) {
std::get<I>(t) = v_i;
} else if constexpr (is_shared_ptr_v<Ti_Type>) {
if constexpr (std::is_same_v<Vi_Type, EmbeddedData>) {
using Ti_handeled_type = typename Ti_Type::element_type;
try {
auto& data_handler = dynamic_cast<const DataHandler<Ti_handeled_type>&>(v_i.get());
std::get<I>(t) = data_handler.data_ptr();
}
catch (std::bad_cast&) {
throw UnexpectedError("unexpected argument types while casting: invalid EmbeddedData type, expecting " +
demangle<DataHandler<Ti_handeled_type>>());
}
} else {
throw UnexpectedError("unexpected argument types while casting: expecting EmbeddedData");
}
} else if constexpr (std::is_same_v<Vi_Type, std::vector<EmbeddedData>>) {
if constexpr (is_vector_v<Ti_Type>) {
using Ti_value_type = typename Ti_Type::value_type;
if constexpr (is_shared_ptr_v<Ti_value_type>) {
static_assert(is_shared_ptr_v<Ti_value_type>, "expecting shared_ptr");
using Ti_handeled_type = typename Ti_value_type::element_type;
std::get<I>(t).resize(v_i.size());
for (size_t j = 0; j < v_i.size(); ++j) {
try {
auto& data_handler = dynamic_cast<const DataHandler<Ti_handeled_type>&>(v_i[j].get());
std::get<I>(t)[j] = data_handler.data_ptr();
}
catch (std::bad_cast&) {
throw UnexpectedError(
"unexpected argument types while casting: invalid EmbeddedData type, expecting " +
demangle<DataHandler<Ti_handeled_type>>());
}
}
} else {
throw UnexpectedError("unexpected argument types while casting \"" + demangle<Vi_Type>() + "\" to \"" +
demangle<Ti_Type>() + '"');
}
} else {
throw UnexpectedError("unexpected argument types while casting \"" + demangle<Vi_Type>() + "\" to \"" +
demangle<Ti_Type>() + '"');
}
} else {
throw UnexpectedError("unexpected argument types while casting \"" + demangle<Vi_Type>() + "\" to \"" +
demangle<Ti_Type>() + '"');
}
},
v[I]);
}
template <size_t... I>
PUGS_INLINE void
_copyFromVector(ArgsTuple& t, const std::vector<DataVariant>& v, std::index_sequence<I...>) const
{
Assert(sizeof...(Args) == v.size());
(_copyValue<I>(t, v), ...);
}
template <size_t I>
PUGS_INLINE ASTNodeDataType
_getOneParameterDataType(ArgsTuple& t) const
{
using ArgN_T = std::decay_t<decltype(std::get<I>(t))>;
if constexpr (is_data_variant_v<ArgN_T>) {
return ast_node_data_type_from<ArgN_T>;
} else if constexpr (std::is_same_v<void, ArgN_T>) {
return ASTNodeDataType::void_t;
} else {
return ASTNodeDataType::type_id_t;
}
}
template <size_t... I>
PUGS_INLINE std::vector<ASTNodeDataType>
_getParameterDataTypes(ArgsTuple t, std::index_sequence<I...>) const
{
std::vector<ASTNodeDataType> parameter_type_list;
(parameter_type_list.push_back(this->_getOneParameterDataType<I>(t)), ...);
return parameter_type_list;
}
template <typename T>
PUGS_INLINE std::shared_ptr<IDataHandler>
_createHandler(std::shared_ptr<T> data) const
{
return std::make_shared<DataHandler<T>>(data);
}
template <size_t I>
PUGS_INLINE void constexpr _check_arg() const
{
using ArgN_T = std::tuple_element_t<I, std::tuple<Args...>>;
if constexpr (std::is_lvalue_reference_v<ArgN_T>) {
static_assert(std::is_const_v<std::remove_reference_t<ArgN_T>>,
"builtin function arguments are non mutable use 'const' when passing references");
}
if constexpr (is_std_ptr_v<ArgN_T>) {
static_assert(std::is_const_v<typename ArgN_T::element_type>,
"builtin function arguments are non mutable. For instance use std::shared_ptr<const T>");
}
}
template <size_t... I>
PUGS_INLINE void constexpr _check_arg_list(std::index_sequence<I...>) const
{
(_check_arg<I>(), ...);
}
public:
PUGS_INLINE ASTNodeDataType
getReturnDataType() const final
{
if constexpr (is_data_variant_v<FX>) {
return ast_node_data_type_from<FX>;
} else if constexpr (std::is_same_v<void, FX>) {
return ASTNodeDataType::void_t;
} else {
return ASTNodeDataType::type_id_t;
}
}
PUGS_INLINE std::vector<ASTNodeDataType>
getParameterDataTypes() const final
{
constexpr size_t N = std::tuple_size_v<ArgsTuple>;
ArgsTuple t;
using IndexSequence = std::make_index_sequence<N>;
return this->_getParameterDataTypes(t, IndexSequence{});
}
PUGS_INLINE size_t
numberOfParameters() const final
{
return sizeof...(Args);
}
public:
PUGS_INLINE
DataVariant
apply(const std::vector<DataVariant>& x) const final
{
constexpr size_t N = std::tuple_size_v<ArgsTuple>;
ArgsTuple t;
using IndexSequence = std::make_index_sequence<N>;
this->_copyFromVector(t, x, IndexSequence{});
if constexpr (is_data_variant_v<FX>) {
return {std::apply(m_f, t)};
} else if constexpr (std::is_same_v<FX, void>) {
std::apply(m_f, t);
return {};
} else {
return EmbeddedData(_createHandler(std::apply(m_f, t)));
}
}
BuiltinFunctionEmbedder(std::function<FX(Args...)> f) : m_f{f}
{
using IndexSequence = std::make_index_sequence<std::tuple_size_v<ArgsTuple>>;
this->_check_arg_list(IndexSequence{});
static_assert((std::is_same_v<Args, Args> and ...));
}
BuiltinFunctionEmbedder(const BuiltinFunctionEmbedder&) = delete;
BuiltinFunctionEmbedder(BuiltinFunctionEmbedder&&) = delete;
~BuiltinFunctionEmbedder() = default;
};
template <typename FX>
class BuiltinFunctionEmbedder<FX, void>
{
static_assert(std::is_class_v<BuiltinFunctionEmbedder<FX, void>>,
"wrong template parameters do not use <FX, void>, use <FX(void)>");
};
template <typename FX>
class BuiltinFunctionEmbedder<FX(void)> : public IBuiltinFunctionEmbedder
{
private:
std::function<FX(void)> m_f;
template <typename T>
PUGS_INLINE std::shared_ptr<IDataHandler>
_createHandler(std::shared_ptr<T> data) const
{
return std::make_shared<DataHandler<T>>(data);
}
public:
PUGS_INLINE ASTNodeDataType
getReturnDataType() const final
{
if constexpr (is_data_variant_v<FX>) {
return ast_node_data_type_from<FX>;
} else if constexpr (std::is_same_v<void, FX>) {
return ASTNodeDataType::void_t;
} else {
return ASTNodeDataType::type_id_t;
}
}
PUGS_INLINE std::vector<ASTNodeDataType>
getParameterDataTypes() const final
{
return {};
}
PUGS_INLINE size_t
numberOfParameters() const final
{
return 0;
}
PUGS_INLINE
DataVariant
apply(const std::vector<DataVariant>&) const final
{
if constexpr (is_data_variant_v<FX>) {
return {m_f()};
} else if constexpr (std::is_same_v<FX, void>) {
m_f();
return {};
} else {
return EmbeddedData(_createHandler(m_f()));
}
}
BuiltinFunctionEmbedder(std::function<FX(void)> f) : m_f{f} {}
BuiltinFunctionEmbedder(const BuiltinFunctionEmbedder&) = delete;
BuiltinFunctionEmbedder(BuiltinFunctionEmbedder&&) = delete;
~BuiltinFunctionEmbedder() = default;
};
#endif // BUILTIN_FUNCTION_EMBEDDER_HPP