Skip to content
Snippets Groups Projects
Select Git revision
  • 8d0741889a3f484d04e4bc8cc8126f0022aa8395
  • develop default protected
  • feature/variational-hydro
  • origin/stage/bouguettaia
  • feature/gmsh-reader
  • feature/reconstruction
  • save_clemence
  • feature/kinetic-schemes
  • feature/local-dt-fsi
  • feature/composite-scheme-sources
  • feature/composite-scheme-other-fluxes
  • feature/serraille
  • feature/composite-scheme
  • hyperplastic
  • feature/polynomials
  • feature/gks
  • feature/implicit-solver-o2
  • feature/coupling_module
  • feature/implicit-solver
  • feature/merge-local-dt-fsi
  • master protected
  • v0.5.0 protected
  • v0.4.1 protected
  • v0.4.0 protected
  • v0.3.0 protected
  • v0.2.0 protected
  • v0.1.0 protected
  • Kidder
  • v0.0.4 protected
  • v0.0.3 protected
  • v0.0.2 protected
  • v0 protected
  • v0.0.1 protected
33 results

PugsUtils.cpp

Blame
  • 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