Select Git revision
CFunctionEmbedder.hpp
CFunctionEmbedder.hpp 3.32 KiB
#ifndef CFUNCTION_EMBEDDER_HPP
#define CFUNCTION_EMBEDDER_HPP
#include <PugsAssert.hpp>
#include <PugsMacros.hpp>
#include <ASTNodeDataType.hpp>
#include <ASTNodeDataVariant.hpp>
#include <cmath>
#include <functional>
#include <iostream>
#include <tuple>
#include <vector>
#include <type_traits>
class ICFunctionEmbedder
{
public:
virtual size_t numberOfArguments() const = 0;
virtual ASTNodeDataType getReturnDataType() const = 0;
virtual std::vector<ASTNodeDataType> getArgumentDataTypes() const = 0;
virtual void apply(const std::vector<ASTNodeDataVariant>& x, ASTNodeDataVariant& f_x) const = 0;
virtual ~ICFunctionEmbedder() = default;
};
template <typename FX, typename... Args>
class CFunctionEmbedder : public ICFunctionEmbedder
{
private:
std::function<FX(Args...)> m_f;
using ArgsTuple = std::tuple<Args...>;
template <size_t I>
PUGS_INLINE void
_copy_value(ArgsTuple& t, const std::vector<ASTNodeDataVariant>& v) const
{
std::visit(
[&](auto v_i) {
if constexpr (std::is_arithmetic_v<decltype(v_i)>) {
std::get<I>(t) = v_i;
} else {
throw std::runtime_error("unexpected argument type!");
}
},
v[I]);
}
template <size_t... I>
PUGS_INLINE void
_copy_from_vector(ArgsTuple& t, const std::vector<ASTNodeDataVariant>& v, std::index_sequence<I...>) const
{
Assert(sizeof...(Args) == v.size());
(_copy_value<I>(t, v), ...);
}
template <size_t I>
PUGS_INLINE ASTNodeDataType
_getOneArgumentDataType(ArgsTuple& t) const
{
return ast_node_data_type_from_pod<std::decay_t<decltype(std::get<I>(t))>>;
}
template <size_t... I>
PUGS_INLINE std::vector<ASTNodeDataType>
_getArgumentDataTypes(ArgsTuple t, std::index_sequence<I...>) const
{
std::vector<ASTNodeDataType> argument_type_list;
(argument_type_list.push_back(this->_getOneArgumentDataType<I>(t)), ...);
return argument_type_list;
}
public:
PUGS_INLINE ASTNodeDataType
getReturnDataType() const final
{
return ast_node_data_type_from_pod<FX>;
}
PUGS_INLINE std::vector<ASTNodeDataType>
getArgumentDataTypes() const final
{
constexpr size_t N = std::tuple_size_v<ArgsTuple>;
ArgsTuple t;
using IndexSequence = std::make_index_sequence<N>;
return this->_getArgumentDataTypes(t, IndexSequence{});
}
PUGS_INLINE size_t
numberOfArguments() const final
{
return sizeof...(Args);
}
PUGS_INLINE
void
apply(const std::vector<ASTNodeDataVariant>& x, ASTNodeDataVariant& f_x) const final
{
constexpr size_t N = std::tuple_size_v<ArgsTuple>;
ArgsTuple t;
using IndexSequence = std::make_index_sequence<N>;
this->_copy_from_vector(t, x, IndexSequence{});
f_x = std::apply(m_f, t);
}
// @note This is written in a template fashion to ensure that function type
// is correct. If one uses simply CFunctionEmbedder(std::function<FX(Args...)>&&),
// types seem unchecked
template <typename FX2, typename... Args2>
CFunctionEmbedder(std::function<FX2(Args2...)> f) : m_f(f)
{
static_assert(std::is_same_v<FX, FX2>, "incorrect return type");
static_assert(sizeof...(Args) == sizeof...(Args2), "invalid number of arguments");
using Args2Tuple = std::tuple<Args2...>;
static_assert(std::is_same_v<ArgsTuple, Args2Tuple>, "invalid arguments type");
}
};
#endif // CFUNCTION_EMBEDDER_HPP