diff --git a/src/language/utils/BuiltinFunctionEmbedder.hpp b/src/language/utils/BuiltinFunctionEmbedder.hpp index c3f015c5b61fbdfda66ee78bbf928fe3a24f3de0..460ec3e866be479633e5bf9a9a416c1f84fc09e6 100644 --- a/src/language/utils/BuiltinFunctionEmbedder.hpp +++ b/src/language/utils/BuiltinFunctionEmbedder.hpp @@ -40,19 +40,25 @@ template <typename FX, typename... Args> class BuiltinFunctionEmbedderBase<FX(Args...)> : public IBuiltinFunctionEmbedder { protected: - template <size_t I> - PUGS_INLINE void constexpr _check_value() const + template <typename ValueT> + PUGS_INLINE void constexpr _check_value_type() const { - using ValueN_T = std::tuple_element_t<I, FX>; - if constexpr (std::is_lvalue_reference_v<ValueN_T>) { - static_assert(std::is_const_v<std::remove_reference_t<ValueN_T>>, + if constexpr (std::is_lvalue_reference_v<ValueT>) { + static_assert(std::is_const_v<std::remove_reference_t<ValueT>>, "builtin function return values are non mutable use 'const' when passing references"); } - if constexpr (is_std_ptr_v<ValueN_T>) { - static_assert(std::is_const_v<typename ValueN_T::element_type>, + if constexpr (is_std_ptr_v<ValueT>) { + static_assert(std::is_const_v<typename ValueT::element_type>, "builtin function return values are non mutable. For instance use std::shared_ptr<const T>"); } + } + + template <size_t I> + PUGS_INLINE void constexpr _check_value() const + { + using ValueN_T = std::tuple_element_t<I, FX>; + _check_value_type<ValueN_T>(); if (ast_node_data_type_from<std::remove_cv_t<std::remove_reference_t<ValueN_T>>> == ASTNodeDataType::undefined_t) { throw std::invalid_argument(std::string{"cannot bind C++ to language.\nnote: return value number "} + @@ -79,6 +85,7 @@ class BuiltinFunctionEmbedderBase<FX(Args...)> : public IBuiltinFunctionEmbedder std::string{"cannot bind C++ to language.\nnote: return value has no associated language type: "} + demangle<FX>()); } + _check_value_type<FX>(); } } @@ -99,8 +106,7 @@ class BuiltinFunctionEmbedderBase<FX(Args...)> : public IBuiltinFunctionEmbedder } template <size_t... I> - PUGS_INLINE std::vector<std::shared_ptr<const ASTNodeDataType>> - _getCompoundDataTypes(std::index_sequence<I...>) const + PUGS_INLINE std::vector<std::shared_ptr<const ASTNodeDataType>> _getCompoundDataTypes(std::index_sequence<I...>) const { std::vector<std::shared_ptr<const ASTNodeDataType>> compound_type_list; (compound_type_list.push_back(std::make_shared<ASTNodeDataType>(this->_getOneElementDataType<FX, I>())), ...); @@ -266,8 +272,7 @@ class BuiltinFunctionEmbedder<FX(Args...)> : public BuiltinFunctionEmbedderBase< } template <size_t... I> - PUGS_INLINE std::vector<ASTNodeDataType> - _getParameterDataTypes(std::index_sequence<I...>) const + PUGS_INLINE std::vector<ASTNodeDataType> _getParameterDataTypes(std::index_sequence<I...>) const { std::vector<ASTNodeDataType> parameter_type_list; (parameter_type_list.push_back(this->template _getOneElementDataType<ArgsTuple, I>()), ...); diff --git a/tests/test_BuiltinFunctionEmbedder.cpp b/tests/test_BuiltinFunctionEmbedder.cpp index 7fd481e163a77f73b32a0d08fba3f49224cdc130..2e56fe228bc4b5d0ae863ae177b3633efbfa6e90 100644 --- a/tests/test_BuiltinFunctionEmbedder.cpp +++ b/tests/test_BuiltinFunctionEmbedder.cpp @@ -10,12 +10,8 @@ inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> = ASTNodeDataType::build<ASTNodeDataType::type_id_t>("shared_const_double"); template <> -inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<double>> = - ASTNodeDataType::build<ASTNodeDataType::type_id_t>("shared_double"); - -template <> -inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<uint64_t>> = - ASTNodeDataType::build<ASTNodeDataType::type_id_t>("shared_uint64_t"); +inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const uint64_t>> = + ASTNodeDataType::build<ASTNodeDataType::type_id_t>("shared_const_uint64_t"); TEST_CASE("BuiltinFunctionEmbedder", "[language]") { @@ -177,7 +173,7 @@ TEST_CASE("BuiltinFunctionEmbedder", "[language]") REQUIRE(*data.data_ptr() == (2.3 + 4ul)); } - SECTION("double(std::shared_ptr<double>) BuiltinFunctionEmbedder") + SECTION("double(std::shared_ptr<const double>) BuiltinFunctionEmbedder") { std::function abs = [&](std::shared_ptr<const double> x) -> double { return std::abs(*x); }; @@ -237,7 +233,7 @@ TEST_CASE("BuiltinFunctionEmbedder", "[language]") SECTION("uint64_t(std::vector<EmbeddedData>) BuiltinFunctionEmbedder") { - std::function sum = [&](const std::vector<std::shared_ptr<uint64_t>>& x) -> uint64_t { + std::function sum = [&](const std::vector<std::shared_ptr<const uint64_t>>& x) -> uint64_t { uint64_t sum = 0; for (size_t i = 0; i < x.size(); ++i) { sum += *x[i]; @@ -246,7 +242,7 @@ TEST_CASE("BuiltinFunctionEmbedder", "[language]") }; std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c = - std::make_unique<BuiltinFunctionEmbedder<uint64_t(const std::vector<std::shared_ptr<uint64_t>>&)>>(sum); + std::make_unique<BuiltinFunctionEmbedder<uint64_t(const std::vector<std::shared_ptr<const uint64_t>>&)>>(sum); REQUIRE(i_embedded_c->numberOfParameters() == 1); REQUIRE(i_embedded_c->getParameterDataTypes().size() == 1); @@ -255,21 +251,21 @@ TEST_CASE("BuiltinFunctionEmbedder", "[language]") std::vector<EmbeddedData> embedded_data; REQUIRE(std::get<uint64_t>(i_embedded_c->apply({embedded_data})) == 0); - embedded_data.emplace_back(std::make_shared<DataHandler<uint64_t>>(std::make_shared<uint64_t>(1))); - embedded_data.emplace_back(std::make_shared<DataHandler<uint64_t>>(std::make_shared<uint64_t>(2))); - embedded_data.emplace_back(std::make_shared<DataHandler<uint64_t>>(std::make_shared<uint64_t>(3))); + embedded_data.emplace_back(std::make_shared<DataHandler<const uint64_t>>(std::make_shared<const uint64_t>(1))); + embedded_data.emplace_back(std::make_shared<DataHandler<const uint64_t>>(std::make_shared<const uint64_t>(2))); + embedded_data.emplace_back(std::make_shared<DataHandler<const uint64_t>>(std::make_shared<const uint64_t>(3))); REQUIRE(std::get<uint64_t>(i_embedded_c->apply({embedded_data})) == 6); - embedded_data.emplace_back(std::make_shared<DataHandler<double>>(std::make_shared<double>(4))); + embedded_data.emplace_back(std::make_shared<DataHandler<const double>>(std::make_shared<const double>(4))); REQUIRE_THROWS_WITH(i_embedded_c->apply({embedded_data}), "unexpected error: unexpected argument types while casting: invalid" " EmbeddedData type, expecting " + - demangle<DataHandler<uint64_t>>()); + demangle<DataHandler<const uint64_t>>()); REQUIRE_THROWS_WITH(i_embedded_c->apply({TinyVector<1>{13}}), "unexpected error: unexpected argument types while casting \"" + demangle<TinyVector<1>>() + - "\" to \"" + demangle<std::vector<std::shared_ptr<uint64_t>>>() + '"'); + "\" to \"" + demangle<std::vector<std::shared_ptr<const uint64_t>>>() + '"'); } SECTION("double(void) BuiltinFunctionEmbedder") @@ -286,9 +282,9 @@ TEST_CASE("BuiltinFunctionEmbedder", "[language]") REQUIRE(i_embedded_c->getReturnDataType() == ASTNodeDataType::double_t); } - SECTION("R*R -> R*R^2*shared_double BuiltinFunctionEmbedder") + SECTION("R*R -> R*R^2*shared_const_double BuiltinFunctionEmbedder") { - std::function c = [](double a, double b) -> std::tuple<double, TinyVector<2>, std::shared_ptr<double>> { + std::function c = [](double a, double b) -> std::tuple<double, TinyVector<2>, std::shared_ptr<const double>> { return std::make_tuple(a + b, TinyVector<2>{b, -a}, std::make_shared<double>(a - b)); }; @@ -311,15 +307,15 @@ TEST_CASE("BuiltinFunctionEmbedder", "[language]") REQUIRE(*data_type.contentTypeList()[0] == ASTNodeDataType::double_t); REQUIRE(*data_type.contentTypeList()[1] == ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)); - REQUIRE(*data_type.contentTypeList()[2] == ast_node_data_type_from<std::shared_ptr<double>>); + REQUIRE(*data_type.contentTypeList()[2] == ast_node_data_type_from<std::shared_ptr<const double>>); } - SECTION("void -> N*R*shared_double BuiltinFunctionEmbedder") + SECTION("void -> N*R*shared_const_double BuiltinFunctionEmbedder") { - std::function c = [](void) -> std::tuple<uint64_t, double, std::shared_ptr<double>> { + std::function c = [](void) -> std::tuple<uint64_t, double, std::shared_ptr<const double>> { uint64_t a = 1; double b = 3.5; - return std::make_tuple(a, b, std::make_shared<double>(a + b)); + return std::make_tuple(a, b, std::make_shared<const double>(a + b)); }; std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c = @@ -357,19 +353,19 @@ TEST_CASE("BuiltinFunctionEmbedder", "[language]") SECTION("EmbeddedData(void) BuiltinFunctionEmbedder") { - std::function c = [](void) -> std::shared_ptr<double> { return std::make_shared<double>(1.5); }; + std::function c = [](void) -> std::shared_ptr<const double> { return std::make_shared<const double>(1.5); }; std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c = - std::make_unique<BuiltinFunctionEmbedder<std::shared_ptr<double>(void)>>(c); + std::make_unique<BuiltinFunctionEmbedder<std::shared_ptr<const double>(void)>>(c); REQUIRE(i_embedded_c->numberOfParameters() == 0); REQUIRE(i_embedded_c->getParameterDataTypes().size() == 0); - REQUIRE(i_embedded_c->getReturnDataType() == ast_node_data_type_from<std::shared_ptr<double>>); + REQUIRE(i_embedded_c->getReturnDataType() == ast_node_data_type_from<std::shared_ptr<const double>>); - const auto embedded_data = std::get<EmbeddedData>(i_embedded_c->apply(std::vector<DataVariant>{})); - const IDataHandler& handled_data = embedded_data.get(); - const DataHandler<double>& data = dynamic_cast<const DataHandler<double>&>(handled_data); + const auto embedded_data = std::get<EmbeddedData>(i_embedded_c->apply(std::vector<DataVariant>{})); + const IDataHandler& handled_data = embedded_data.get(); + const DataHandler<const double>& data = dynamic_cast<const DataHandler<const double>&>(handled_data); REQUIRE(*data.data_ptr() == 1.5); }