boost_sqlite 1
A sqlite C++ library
Loading...
Searching...
No Matches
scalar_function.hpp
1// Copyright (c) 2023 Klemens D. Morgenstern
2//
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5#ifndef BOOST_SQLITE_DETAIL_SCALAR_FUNCTION_HPP
6#define BOOST_SQLITE_DETAIL_SCALAR_FUNCTION_HPP
7
8#include <boost/sqlite/detail/config.hpp>
9#include <boost/sqlite/cstring_ref.hpp>
10#include <boost/sqlite/memory.hpp>
11#include <boost/sqlite/result.hpp>
12#include <boost/sqlite/value.hpp>
13
14#include <boost/callable_traits/args.hpp>
15#include <boost/callable_traits/return_type.hpp>
16#include <boost/callable_traits/has_void_return.hpp>
17#include <boost/core/span.hpp>
18
19
20BOOST_SQLITE_BEGIN_NAMESPACE
21
22template<typename ... Args>
23struct context;
24
25namespace detail
26{
27
28template<typename Func, typename ... Args, std::size_t Extent>
29auto create_scalar_function_impl(sqlite3 * db,
30 cstring_ref name,
31 Func && func,
32 std::tuple<context<Args...>, boost::span<value, Extent>> * ,
33 std::false_type /* void return */,
34 std::false_type /* is pointer */) -> int
35{
36 using func_type = typename std::decay<Func>::type;
37 return sqlite3_create_function_v2(
38 db, name.c_str(),
39 Extent == boost::dynamic_extent ? -1 : static_cast<int>(Extent),
40 SQLITE_UTF8,
41 new (memory_tag{}) func_type(std::forward<Func>(func)),
42 +[](sqlite3_context* ctx, int len, sqlite3_value** args)
43 {
44 auto cc = context<Args...>(ctx);
45 auto aa = reinterpret_cast<value*>(args);
46 auto &f = *reinterpret_cast<func_type*>(sqlite3_user_data(ctx));
47 boost::span<value, Extent> vals{aa, static_cast<std::size_t>(len)};
48
49 execute_context_function(ctx, f, cc, vals);
50 }, nullptr, nullptr,
51 +[](void * ptr) noexcept {delete_(static_cast<func_type*>(ptr));}
52 );
53}
54
55template<typename Func, typename ... Args, std::size_t Extent>
56auto create_scalar_function_impl(sqlite3 * db,
57 cstring_ref name,
58 Func && func,
59 std::tuple<context<Args...>, boost::span<value, Extent>> * ,
60 std::true_type /* void return */,
61 std::false_type /* is pointer */) -> int
62{
63 using func_type = typename std::decay<Func>::type;
64 return sqlite3_create_function_v2(
65 db,
66 name.c_str(),
67 (Extent == boost::dynamic_extent) ? -1 : static_cast<int>(Extent),
68 SQLITE_UTF8,
69 new (memory_tag{}) func_type(std::forward<Func>(func)),
70 +[](sqlite3_context* ctx, int len, sqlite3_value** args)
71 {
72 auto cc = context<Args...>(ctx);
73 auto aa = reinterpret_cast<value*>(args);
74 auto &f = *reinterpret_cast<func_type*>(sqlite3_user_data(ctx));
75 boost::span<value, Extent> vals{aa, static_cast<std::size_t>(len)};
76
77 execute_context_function(
78 ctx,
79 [&]()
80 {
81 f(cc, vals);
82 return result<void>();
83 });
84
85 }, nullptr, nullptr,
86 +[](void * ptr){delete_(static_cast<func_type*>(ptr));}
87 );
88}
89
90
91template<typename Func, typename ... Args, std::size_t Extent>
92auto create_scalar_function_impl(sqlite3 * db,
93 cstring_ref name,
94 Func && func,
95 std::tuple<context<Args...>, boost::span<value, Extent>> * ,
96 std::false_type /* void return */,
97 std::true_type /* is pointer */) -> int
98{
99 return sqlite3_create_function_v2(
100 db, name.c_str(),
101 Extent == boost::dynamic_extent ? -1 : static_cast<int>(Extent),
102 SQLITE_UTF8,
103 reinterpret_cast<void*>(func),
104 +[](sqlite3_context* ctx, int len, sqlite3_value** args)
105 {
106 auto cc = context<Args...>(ctx);
107 auto aa = reinterpret_cast<value*>(args);
108 auto &f = *reinterpret_cast<Func*>(sqlite3_user_data(ctx));
109
110 boost::span<value, Extent> vals{aa, static_cast<std::size_t>(len)};
111
112 execute_context_function(
113 ctx, f, cc, vals);
114 }, nullptr, nullptr, nullptr);
115}
116
117template<typename Func, typename ... Args, std::size_t Extent>
118auto create_scalar_function_impl(sqlite3 * db,
119 cstring_ref name,
120 Func && func,
121 std::tuple<context<Args...>, boost::span<value, Extent>> * ,
122 std::true_type /* void return */,
123 std::true_type /* is pointer */) -> int
124{
125 return sqlite3_create_function_v2(
126 db,
127 name.c_str(),
128 (Extent == boost::dynamic_extent) ? -1 : static_cast<int>(Extent),
129 SQLITE_UTF8,
130 reinterpret_cast<void*>(func),
131 +[](sqlite3_context* ctx, int len, sqlite3_value** args)
132 {
133 auto cc = context<Args...>(ctx);
134 auto aa = reinterpret_cast<value*>(args);
135 auto &f = *reinterpret_cast<Func*>(sqlite3_user_data(ctx));
136 boost::span<value, Extent> vals{aa, static_cast<std::size_t>(len)};
137 execute_context_function(
138 ctx,
139 [&]()
140 {
141 f(cc, vals);
142 return result<void>();
143 });
144
145 }, nullptr, nullptr, nullptr);
146}
147
148template<typename Func>
149auto create_scalar_function(sqlite3 * db,
150 cstring_ref name,
151 Func && func)
152 -> decltype(create_scalar_function_impl(
153 db, name, std::forward<Func>(func),
154 static_cast<callable_traits::args_t<Func>*>(nullptr),
155 callable_traits::has_void_return<Func>{},
156 std::is_pointer<typename std::decay<Func>::type>{}
157 ))
158{
159 return create_scalar_function_impl(db, name, std::forward<Func>(func),
160 static_cast<callable_traits::args_t<Func>*>(nullptr),
161 callable_traits::has_void_return<Func>{},
162 std::is_pointer<typename std::decay<Func>::type>{});
163}
164
165
166}
167
168BOOST_SQLITE_END_NAMESPACE
169
170#endif //BOOST_SQLITE_DETAIL_SCALAR_FUNCTION_HPP