// Copyright (c) 2023 Klemens D. Morgenstern // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_SQLITE_DETAIL_SCALAR_FUNCTION_HPP #define BOOST_SQLITE_DETAIL_SCALAR_FUNCTION_HPP #include #include #include #include #include #include #include #include #include BOOST_SQLITE_BEGIN_NAMESPACE template struct context; namespace detail { template auto create_scalar_function_impl(sqlite3 * db, cstring_ref name, Func && func, int flags, std::tuple, boost::span> * , std::false_type /* void return */, std::false_type /* is pointer */) -> int { using func_type = typename std::decay::type; return sqlite3_create_function_v2( db, name.c_str(), Extent == boost::dynamic_extent ? -1 : static_cast(Extent), SQLITE_UTF8 | flags, new (memory_tag{}) func_type(std::forward(func)), +[](sqlite3_context* ctx, int len, sqlite3_value** args) { auto cc = context(ctx); auto aa = reinterpret_cast(args); auto &f = *reinterpret_cast(sqlite3_user_data(ctx)); boost::span vals{aa, static_cast(len)}; execute_context_function(ctx, f, cc, vals); }, nullptr, nullptr, +[](void * ptr) noexcept {delete_(static_cast(ptr));} ); } template auto create_scalar_function_impl(sqlite3 * db, cstring_ref name, Func && func, int flags, std::tuple, boost::span> * , std::true_type /* void return */, std::false_type /* is pointer */) -> int { using func_type = typename std::decay::type; return sqlite3_create_function_v2( db, name.c_str(), (Extent == boost::dynamic_extent) ? -1 : static_cast(Extent), SQLITE_UTF8 | flags, new (memory_tag{}) func_type(std::forward(func)), +[](sqlite3_context* ctx, int len, sqlite3_value** args) { auto cc = context(ctx); auto aa = reinterpret_cast(args); auto &f = *reinterpret_cast(sqlite3_user_data(ctx)); boost::span vals{aa, static_cast(len)}; execute_context_function( ctx, [&]() { f(cc, vals); return result(); }); }, nullptr, nullptr, +[](void * ptr){delete_(static_cast(ptr));} ); } template auto create_scalar_function_impl(sqlite3 * db, cstring_ref name, Func * func, int flags, std::tuple, boost::span> * , std::false_type /* void return */, std::true_type /* is pointer */) -> int { return sqlite3_create_function_v2( db, name.c_str(), Extent == boost::dynamic_extent ? -1 : static_cast(Extent), SQLITE_UTF8 | flags, reinterpret_cast(func), +[](sqlite3_context* ctx, int len, sqlite3_value** args) { auto cc = context(ctx); auto aa = reinterpret_cast(args); auto f = reinterpret_cast(sqlite3_user_data(ctx)); boost::span vals{aa, static_cast(len)}; execute_context_function( ctx, f, cc, vals); }, nullptr, nullptr, nullptr); } template auto create_scalar_function_impl(sqlite3 * db, cstring_ref name, Func * func, int flags, std::tuple, boost::span> * , std::true_type /* void return */, std::true_type /* is pointer */) -> int { return sqlite3_create_function_v2( db, name.c_str(), (Extent == boost::dynamic_extent) ? -1 : static_cast(Extent), SQLITE_UTF8 | flags, reinterpret_cast(func), +[](sqlite3_context* ctx, int len, sqlite3_value** args) { auto cc = context(ctx); auto aa = reinterpret_cast(args); auto f = *reinterpret_cast(sqlite3_user_data(ctx)); boost::span vals{aa, static_cast(len)}; execute_context_function( ctx, [&]() { f(cc, vals); return result(); }); }, nullptr, nullptr, nullptr); } template auto create_scalar_function(sqlite3 * db, cstring_ref name, Func && func, int flags) -> decltype(create_scalar_function_impl( db, name, std::forward(func), flags, static_cast*>(nullptr), callable_traits::has_void_return{}, std::is_pointer::type>{} )) { return create_scalar_function_impl(db, name, std::forward(func), flags, static_cast*>(nullptr), callable_traits::has_void_return{}, std::is_pointer::type>{}); } } BOOST_SQLITE_END_NAMESPACE #endif //BOOST_SQLITE_DETAIL_SCALAR_FUNCTION_HPP