diff --git a/dev/function.h b/dev/function.h index 868b31dfc..67a593214 100644 --- a/dev/function.h +++ b/dev/function.h @@ -23,49 +23,44 @@ namespace sqlite_orm { namespace internal { struct udf_proxy_base { - using func_call = - std::function; - using final_call = std::function; + using func_call_fn_t = void (*)(void* udfHandle, + sqlite3_context* context, + int argsCount, + sqlite3_value** values); + using final_call_fn_t = void (*)(void* udfHandle, sqlite3_context* context); std::string name; int argumentsCount = 0; std::function create; xdestroy_fn_t destroy = nullptr; - - udf_proxy_base(decltype(name) name_, - decltype(argumentsCount) argumentsCount_, - decltype(create) create_, - decltype(destroy) destroy_) : - name(std::move(name_)), - argumentsCount(argumentsCount_), create(std::move(create_)), destroy(destroy_) {} - - virtual ~udf_proxy_base() = default; + func_call_fn_t func = nullptr; + final_call_fn_t finalAggregateCall = nullptr; + + udf_proxy_base(std::string name, + int argumentsCount, + std::function create, + xdestroy_fn_t destroy, + func_call_fn_t run) : + name(std::move(name)), + argumentsCount(argumentsCount), create(std::move(create)), destroy(destroy), func(run) {} + + udf_proxy_base(std::string name, + int argumentsCount, + std::function create, + xdestroy_fn_t destroy, + func_call_fn_t step, + final_call_fn_t finalCall) : + name(std::move(name)), + argumentsCount(argumentsCount), create(std::move(create)), destroy(destroy), func(step), + finalAggregateCall(finalCall) {} }; struct scalar_udf_proxy : udf_proxy_base { - func_call run; - - scalar_udf_proxy(decltype(name) name_, - int argumentsCount_, - decltype(create) create_, - decltype(run) run_, - decltype(destroy) destroy_) : - udf_proxy_base{std::move(name_), argumentsCount_, std::move(create_), destroy_}, - run(std::move(run_)) {} + using udf_proxy_base::udf_proxy_base; }; struct aggregate_udf_proxy : udf_proxy_base { - func_call step; - final_call finalCall; - - aggregate_udf_proxy(decltype(name) name_, - int argumentsCount_, - decltype(create) create_, - decltype(step) step_, - decltype(finalCall) finalCall_, - decltype(destroy) destroy_) : - udf_proxy_base{std::move(name_), argumentsCount_, std::move(create_), destroy_}, - step(std::move(step_)), finalCall(std::move(finalCall_)) {} + using udf_proxy_base::udf_proxy_base; }; template diff --git a/dev/storage_base.h b/dev/storage_base.h index 9c45bc53e..9f935cefc 100644 --- a/dev/storage_base.h +++ b/dev/storage_base.h @@ -24,6 +24,7 @@ #include "values_to_tuple.h" #include "arg_values.h" #include "util.h" +#include "xdestroy_handling.h" #include "serializing_util.h" namespace sqlite_orm { @@ -268,15 +269,16 @@ namespace sqlite_orm { []() -> void* { return new F(); }, + /* destroy = */ + obtain_xdestroy_for(std::default_delete{}), /* call = */ - [](sqlite3_context* context, void* udfHandle, int argsCount, sqlite3_value** values) { + [](void* udfHandle, sqlite3_context* context, int argsCount, sqlite3_value** values) { F& udf = *static_cast(udfHandle); args_tuple argsTuple; values_to_tuple{}(values, argsTuple, argsCount); auto result = call(udf, std::move(argsTuple)); statement_binder().result(context, result); - }, - delete_function_callback)); + })); if(this->connection->retain_count() > 0) { sqlite3* db = this->connection->get(); @@ -335,20 +337,21 @@ namespace sqlite_orm { []() -> void* { return new F(); }, + /* destroy = */ + obtain_xdestroy_for(std::default_delete{}), /* step = */ - [](sqlite3_context*, void* udfHandle, int argsCount, sqlite3_value** values) { + [](void* udfHandle, sqlite3_context*, int argsCount, sqlite3_value** values) { F& udf = *static_cast(udfHandle); args_tuple argsTuple; values_to_tuple{}(values, argsTuple, argsCount); call(udf, &F::step, std::move(argsTuple)); }, /* finalCall = */ - [](sqlite3_context* context, void* udfHandle) { + [](void* udfHandle, sqlite3_context* context) { F& udf = *static_cast(udfHandle); auto result = udf.fin(); statement_binder().result(context, result); - }, - delete_function_callback)); + })); if(this->connection->retain_count() > 0) { sqlite3* db = this->connection->get(); @@ -730,7 +733,7 @@ namespace sqlite_orm { } udfHandle = udfProxy->create(); } - udfProxy->step(context, udfHandle, argsCount, values); + udfProxy->func(udfHandle, context, argsCount, values); } static void aggregate_function_final_callback(sqlite3_context* context) { @@ -742,23 +745,17 @@ namespace sqlite_orm { if(udfHandle == nullptr) { udfHandle = udfProxy->create(); } - udfProxy->finalCall(context, udfHandle); + udfProxy->finalAggregateCall(udfHandle, context); udfProxy->destroy(udfHandle); } static void scalar_function_callback(sqlite3_context* context, int argsCount, sqlite3_value** values) { - auto udfProxy = static_cast(sqlite3_user_data(context)); + auto* udfProxy = static_cast(sqlite3_user_data(context)); if(udfProxy->argumentsCount != -1 && udfProxy->argumentsCount != argsCount) { throw std::system_error{orm_error_code::arguments_count_does_not_match}; } - const std::unique_ptr udfHandle(udfProxy->create(), udfProxy->destroy); - udfProxy->run(context, udfHandle.get(), argsCount, values); - } - - template - static void delete_function_callback(void* udfHandle) { - F* udf = static_cast(udfHandle); - delete udf; + const std::unique_ptr udfHandle{udfProxy->create(), udfProxy->destroy}; + udfProxy->func(udfHandle.get(), context, argsCount, values); } std::string current_time(sqlite3* db) { diff --git a/dev/xdestroy_handling.h b/dev/xdestroy_handling.h index b545e0c81..0b4b40afd 100644 --- a/dev/xdestroy_handling.h +++ b/dev/xdestroy_handling.h @@ -181,8 +181,8 @@ namespace sqlite_orm { * * Explicitly declared for better error messages. */ - template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + template + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P* = nullptr) noexcept requires(internal::is_unusable_for_xdestroy) { static_assert(polyfill::always_false_v, @@ -202,8 +202,8 @@ namespace sqlite_orm { * Type-safety is garanteed by checking whether the deleter or yielded function pointer * is invocable with the non-q-qualified pointer value. */ - template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + template + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P* = nullptr) noexcept requires(internal::needs_xdestroy_proxy) { return internal::xdestroy_proxy; @@ -223,27 +223,27 @@ namespace sqlite_orm { * Type-safety is garanteed by checking whether the deleter or yielded function pointer * is invocable with the non-q-qualified pointer value. */ - template - constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept + template + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P* = nullptr) noexcept requires(internal::yields_xdestroy) { return d; } #else - template, bool> = true> - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) { + template, bool> = true> + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P* = nullptr) { static_assert(polyfill::always_false_v, "A function pointer, which is not of type xdestroy_fn_t, is prohibited."); return nullptr; } - template, bool> = true> - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept { + template, bool> = true> + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P* = nullptr) noexcept { return internal::xdestroy_proxy; } - template, bool> = true> - constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept { + template, bool> = true> + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P* = nullptr) noexcept { return d; } #endif diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index f73528b6d..a1ae6f586 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -8285,8 +8285,8 @@ namespace sqlite_orm { * * Explicitly declared for better error messages. */ - template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + template + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P* = nullptr) noexcept requires(internal::is_unusable_for_xdestroy) { static_assert(polyfill::always_false_v, @@ -8306,8 +8306,8 @@ namespace sqlite_orm { * Type-safety is garanteed by checking whether the deleter or yielded function pointer * is invocable with the non-q-qualified pointer value. */ - template - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept + template + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P* = nullptr) noexcept requires(internal::needs_xdestroy_proxy) { return internal::xdestroy_proxy; @@ -8327,27 +8327,27 @@ namespace sqlite_orm { * Type-safety is garanteed by checking whether the deleter or yielded function pointer * is invocable with the non-q-qualified pointer value. */ - template - constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept + template + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P* = nullptr) noexcept requires(internal::yields_xdestroy) { return d; } #else - template, bool> = true> - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) { + template, bool> = true> + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P* = nullptr) { static_assert(polyfill::always_false_v, "A function pointer, which is not of type xdestroy_fn_t, is prohibited."); return nullptr; } - template, bool> = true> - constexpr xdestroy_fn_t obtain_xdestroy_for(D, P*) noexcept { + template, bool> = true> + constexpr xdestroy_fn_t obtain_xdestroy_for(D, P* = nullptr) noexcept { return internal::xdestroy_proxy; } - template, bool> = true> - constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P*) noexcept { + template, bool> = true> + constexpr xdestroy_fn_t obtain_xdestroy_for(D d, P* = nullptr) noexcept { return d; } #endif @@ -10904,49 +10904,44 @@ namespace sqlite_orm { namespace internal { struct udf_proxy_base { - using func_call = - std::function; - using final_call = std::function; + using func_call_fn_t = void (*)(void* udfHandle, + sqlite3_context* context, + int argsCount, + sqlite3_value** values); + using final_call_fn_t = void (*)(void* udfHandle, sqlite3_context* context); std::string name; int argumentsCount = 0; std::function create; xdestroy_fn_t destroy = nullptr; - - udf_proxy_base(decltype(name) name_, - decltype(argumentsCount) argumentsCount_, - decltype(create) create_, - decltype(destroy) destroy_) : - name(std::move(name_)), - argumentsCount(argumentsCount_), create(std::move(create_)), destroy(destroy_) {} - - virtual ~udf_proxy_base() = default; + func_call_fn_t func = nullptr; + final_call_fn_t finalAggregateCall = nullptr; + + udf_proxy_base(std::string name, + int argumentsCount, + std::function create, + xdestroy_fn_t destroy, + func_call_fn_t run) : + name(std::move(name)), + argumentsCount(argumentsCount), create(std::move(create)), destroy(destroy), func(run) {} + + udf_proxy_base(std::string name, + int argumentsCount, + std::function create, + xdestroy_fn_t destroy, + func_call_fn_t step, + final_call_fn_t finalCall) : + name(std::move(name)), + argumentsCount(argumentsCount), create(std::move(create)), destroy(destroy), func(step), + finalAggregateCall(finalCall) {} }; struct scalar_udf_proxy : udf_proxy_base { - func_call run; - - scalar_udf_proxy(decltype(name) name_, - int argumentsCount_, - decltype(create) create_, - decltype(run) run_, - decltype(destroy) destroy_) : - udf_proxy_base{std::move(name_), argumentsCount_, std::move(create_), destroy_}, - run(std::move(run_)) {} + using udf_proxy_base::udf_proxy_base; }; struct aggregate_udf_proxy : udf_proxy_base { - func_call step; - final_call finalCall; - - aggregate_udf_proxy(decltype(name) name_, - int argumentsCount_, - decltype(create) create_, - decltype(step) step_, - decltype(finalCall) finalCall_, - decltype(destroy) destroy_) : - udf_proxy_base{std::move(name_), argumentsCount_, std::move(create_), destroy_}, - step(std::move(step_)), finalCall(std::move(finalCall_)) {} + using udf_proxy_base::udf_proxy_base; }; template @@ -14841,6 +14836,8 @@ namespace sqlite_orm { // #include "util.h" +// #include "xdestroy_handling.h" + // #include "serializing_util.h" namespace sqlite_orm { @@ -15085,15 +15082,16 @@ namespace sqlite_orm { []() -> void* { return new F(); }, + /* destroy = */ + obtain_xdestroy_for(std::default_delete{}), /* call = */ - [](sqlite3_context* context, void* udfHandle, int argsCount, sqlite3_value** values) { + [](void* udfHandle, sqlite3_context* context, int argsCount, sqlite3_value** values) { F& udf = *static_cast(udfHandle); args_tuple argsTuple; values_to_tuple{}(values, argsTuple, argsCount); auto result = call(udf, std::move(argsTuple)); statement_binder().result(context, result); - }, - delete_function_callback)); + })); if(this->connection->retain_count() > 0) { sqlite3* db = this->connection->get(); @@ -15152,20 +15150,21 @@ namespace sqlite_orm { []() -> void* { return new F(); }, + /* destroy = */ + obtain_xdestroy_for(std::default_delete{}), /* step = */ - [](sqlite3_context*, void* udfHandle, int argsCount, sqlite3_value** values) { + [](void* udfHandle, sqlite3_context*, int argsCount, sqlite3_value** values) { F& udf = *static_cast(udfHandle); args_tuple argsTuple; values_to_tuple{}(values, argsTuple, argsCount); call(udf, &F::step, std::move(argsTuple)); }, /* finalCall = */ - [](sqlite3_context* context, void* udfHandle) { + [](void* udfHandle, sqlite3_context* context) { F& udf = *static_cast(udfHandle); auto result = udf.fin(); statement_binder().result(context, result); - }, - delete_function_callback)); + })); if(this->connection->retain_count() > 0) { sqlite3* db = this->connection->get(); @@ -15547,7 +15546,7 @@ namespace sqlite_orm { } udfHandle = udfProxy->create(); } - udfProxy->step(context, udfHandle, argsCount, values); + udfProxy->func(udfHandle, context, argsCount, values); } static void aggregate_function_final_callback(sqlite3_context* context) { @@ -15559,23 +15558,17 @@ namespace sqlite_orm { if(udfHandle == nullptr) { udfHandle = udfProxy->create(); } - udfProxy->finalCall(context, udfHandle); + udfProxy->finalAggregateCall(udfHandle, context); udfProxy->destroy(udfHandle); } static void scalar_function_callback(sqlite3_context* context, int argsCount, sqlite3_value** values) { - auto udfProxy = static_cast(sqlite3_user_data(context)); + auto* udfProxy = static_cast(sqlite3_user_data(context)); if(udfProxy->argumentsCount != -1 && udfProxy->argumentsCount != argsCount) { throw std::system_error{orm_error_code::arguments_count_does_not_match}; } - const std::unique_ptr udfHandle(udfProxy->create(), udfProxy->destroy); - udfProxy->run(context, udfHandle.get(), argsCount, values); - } - - template - static void delete_function_callback(void* udfHandle) { - F* udf = static_cast(udfHandle); - delete udf; + const std::unique_ptr udfHandle{udfProxy->create(), udfProxy->destroy}; + udfProxy->func(udfHandle.get(), context, argsCount, values); } std::string current_time(sqlite3* db) { diff --git a/tests/static_tests/function_static_tests.cpp b/tests/static_tests/function_static_tests.cpp index f29092cb4..7cd8e0122 100644 --- a/tests/static_tests/function_static_tests.cpp +++ b/tests/static_tests/function_static_tests.cpp @@ -268,5 +268,9 @@ TEST_CASE("function static") { STATIC_REQUIRE(storage_aggregate_callable); STATIC_REQUIRE_FALSE(storage_scalar_callable); #endif + + // must be veneers (no additional data members) + STATIC_REQUIRE(sizeof(internal::scalar_udf_proxy) == sizeof(internal::udf_proxy_base)); + STATIC_REQUIRE(sizeof(internal::aggregate_udf_proxy) == sizeof(internal::udf_proxy_base)); } }