#pragma once #include #include #include // std::string #include // std::tuple #include // std::function #include // std::min #include // std::move, std::forward #include "functional/cxx_universal.h" #include "functional/cxx_type_traits_polyfill.h" namespace sqlite_orm { struct arg_values; template struct pointer_arg; template class pointer_binding; namespace internal { struct user_defined_function_base { using func_call = std::function< void(sqlite3_context* context, void* functionPointer, int argsCount, sqlite3_value** values)>; using final_call = std::function; std::string name; int argumentsCount = 0; std::function create; void (*destroy)(int*) = nullptr; #ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED user_defined_function_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_) {} #endif }; struct user_defined_scalar_function_t : user_defined_function_base { func_call run; user_defined_scalar_function_t(decltype(name) name_, int argumentsCount_, decltype(create) create_, decltype(run) run_, decltype(destroy) destroy_) : user_defined_function_base{std::move(name_), argumentsCount_, std::move(create_), destroy_}, run(std::move(run_)) {} }; struct user_defined_aggregate_function_t : user_defined_function_base { func_call step; final_call finalCall; user_defined_aggregate_function_t(decltype(name) name_, int argumentsCount_, decltype(create) create_, decltype(step) step_, decltype(finalCall) finalCall_, decltype(destroy) destroy_) : user_defined_function_base{std::move(name_), argumentsCount_, std::move(create_), destroy_}, step(std::move(step_)), finalCall(std::move(finalCall_)) {} }; template using scalar_call_function_t = decltype(&F::operator()); template using aggregate_step_function_t = decltype(&F::step); template using aggregate_fin_function_t = decltype(&F::fin); template SQLITE_ORM_INLINE_VAR constexpr bool is_scalar_function_v = false; template SQLITE_ORM_INLINE_VAR constexpr bool is_scalar_function_v>> = true; template SQLITE_ORM_INLINE_VAR constexpr bool is_aggregate_function_v = false; template SQLITE_ORM_INLINE_VAR constexpr bool is_aggregate_function_v< F, polyfill::void_t, aggregate_fin_function_t, std::enable_if_t>::value>, std::enable_if_t>::value>>> = true; template struct member_function_arguments; template struct member_function_arguments { using member_function_type = R (O::*)(Args...) const; using tuple_type = std::tuple...>; using return_type = R; }; template struct member_function_arguments { using member_function_type = R (O::*)(Args...); using tuple_type = std::tuple...>; using return_type = R; }; template struct callable_arguments_impl; template struct callable_arguments_impl>> { using args_tuple = typename member_function_arguments>::tuple_type; using return_type = typename member_function_arguments>::return_type; }; template struct callable_arguments_impl>> { using args_tuple = typename member_function_arguments>::tuple_type; using return_type = typename member_function_arguments>::return_type; }; template struct callable_arguments : callable_arguments_impl {}; template struct function_call { using function_type = F; using args_tuple = std::tuple; args_tuple args; }; template struct unpacked_arg { using type = T; }; template struct unpacked_arg> { using type = typename callable_arguments::return_type; }; template using unpacked_arg_t = typename unpacked_arg::type; template SQLITE_ORM_CONSTEVAL bool expected_pointer_value() { static_assert(polyfill::always_false_v, "Expected a pointer value for I-th argument"); return false; } template constexpr bool is_same_pvt_v = expected_pointer_value(); // Always allow binding nullptr to a pointer argument template constexpr bool is_same_pvt_v> = true; #if __cplusplus >= 201703L // C++17 or later template SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { constexpr bool valid = Binding == PointerArg; static_assert(valid, "Pointer value types of I-th argument do not match"); return valid; } template constexpr bool is_same_pvt_v> = assert_same_pointer_type(); #else template SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { constexpr bool valid = Binding::value == PointerArg::value; static_assert(valid, "Pointer value types of I-th argument do not match"); return valid; } template constexpr bool is_same_pvt_v> = assert_same_pointer_type(); #endif template SQLITE_ORM_CONSTEVAL bool validate_pointer_value_type(std::false_type) { return true; } template SQLITE_ORM_CONSTEVAL bool validate_pointer_value_type(std::true_type) { return is_same_pvt_v; } template SQLITE_ORM_CONSTEVAL bool validate_pointer_value_types(polyfill::index_constant) { return true; } template SQLITE_ORM_CONSTEVAL bool validate_pointer_value_types(polyfill::index_constant) { using func_arg_t = std::tuple_element_t; using passed_arg_t = unpacked_arg_t>; #ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED constexpr bool valid = validate_pointer_value_type, unpacked_arg_t>>( polyfill::bool_constant < (polyfill::is_specialization_of_v) || (polyfill::is_specialization_of_v) > {}); return validate_pointer_value_types(polyfill::index_constant{}) && valid; #else return validate_pointer_value_types(polyfill::index_constant{}) && validate_pointer_value_type, unpacked_arg_t>>( polyfill::bool_constant < (polyfill::is_specialization_of_v) || (polyfill::is_specialization_of_v) > {}); #endif } } /** * Used to call user defined function: `func(...);` */ template internal::function_call func(Args... args) { using args_tuple = std::tuple; using function_args_tuple = typename internal::callable_arguments::args_tuple; constexpr auto argsCount = std::tuple_size::value; constexpr auto functionArgsCount = std::tuple_size::value; static_assert((argsCount == functionArgsCount && !std::is_same>::value && internal::validate_pointer_value_types( polyfill::index_constant(functionArgsCount, argsCount) - 1>{})) || std::is_same>::value, "Number of arguments does not match"); return {std::make_tuple(std::forward(args)...)}; } }