This repository has been archived by the owner on Jan 3, 2024. It is now read-only.
forked from fnc12/sqlite_orm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfunction.h
246 lines (205 loc) · 10.9 KB
/
function.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
#pragma once
#include <sqlite3.h>
#include <type_traits>
#include <string> // std::string
#include <tuple> // std::tuple
#include <functional> // std::function
#include <algorithm> // std::min
#include <utility> // std::move, std::forward
#include "functional/cxx_universal.h"
#include "functional/cxx_type_traits_polyfill.h"
namespace sqlite_orm {
struct arg_values;
template<class T, class P>
struct pointer_arg;
template<class T, class P, class D>
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<void(sqlite3_context* context, void* functionPointer)>;
std::string name;
int argumentsCount = 0;
std::function<int*()> 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<class F>
using scalar_call_function_t = decltype(&F::operator());
template<class F>
using aggregate_step_function_t = decltype(&F::step);
template<class F>
using aggregate_fin_function_t = decltype(&F::fin);
template<class F, class = void>
SQLITE_ORM_INLINE_VAR constexpr bool is_scalar_function_v = false;
template<class F>
SQLITE_ORM_INLINE_VAR constexpr bool is_scalar_function_v<F, polyfill::void_t<scalar_call_function_t<F>>> =
true;
template<class F, class = void>
SQLITE_ORM_INLINE_VAR constexpr bool is_aggregate_function_v = false;
template<class F>
SQLITE_ORM_INLINE_VAR constexpr bool is_aggregate_function_v<
F,
polyfill::void_t<aggregate_step_function_t<F>,
aggregate_fin_function_t<F>,
std::enable_if_t<std::is_member_function_pointer<aggregate_step_function_t<F>>::value>,
std::enable_if_t<std::is_member_function_pointer<aggregate_fin_function_t<F>>::value>>> =
true;
template<class T>
struct member_function_arguments;
template<class O, class R, class... Args>
struct member_function_arguments<R (O::*)(Args...) const> {
using member_function_type = R (O::*)(Args...) const;
using tuple_type = std::tuple<std::decay_t<Args>...>;
using return_type = R;
};
template<class O, class R, class... Args>
struct member_function_arguments<R (O::*)(Args...)> {
using member_function_type = R (O::*)(Args...);
using tuple_type = std::tuple<std::decay_t<Args>...>;
using return_type = R;
};
template<class F, class SFINAE = void>
struct callable_arguments_impl;
template<class F>
struct callable_arguments_impl<F, std::enable_if_t<is_scalar_function_v<F>>> {
using args_tuple = typename member_function_arguments<scalar_call_function_t<F>>::tuple_type;
using return_type = typename member_function_arguments<scalar_call_function_t<F>>::return_type;
};
template<class F>
struct callable_arguments_impl<F, std::enable_if_t<is_aggregate_function_v<F>>> {
using args_tuple = typename member_function_arguments<aggregate_step_function_t<F>>::tuple_type;
using return_type = typename member_function_arguments<aggregate_fin_function_t<F>>::return_type;
};
template<class F>
struct callable_arguments : callable_arguments_impl<F> {};
template<class F, class... Args>
struct function_call {
using function_type = F;
using args_tuple = std::tuple<Args...>;
args_tuple args;
};
template<class T>
struct unpacked_arg {
using type = T;
};
template<class F, class... Args>
struct unpacked_arg<function_call<F, Args...>> {
using type = typename callable_arguments<F>::return_type;
};
template<class T>
using unpacked_arg_t = typename unpacked_arg<T>::type;
template<size_t I, class FnArg, class CallArg>
SQLITE_ORM_CONSTEVAL bool expected_pointer_value() {
static_assert(polyfill::always_false_v<FnArg, CallArg>, "Expected a pointer value for I-th argument");
return false;
}
template<size_t I, class FnArg, class CallArg, class EnableIfTag = void>
constexpr bool is_same_pvt_v = expected_pointer_value<I, FnArg, CallArg>();
// Always allow binding nullptr to a pointer argument
template<size_t I, class PointerArg>
constexpr bool is_same_pvt_v<I, PointerArg, nullptr_t, polyfill::void_t<typename PointerArg::tag>> = true;
#if __cplusplus >= 201703L // C++17 or later
template<size_t I, const char* PointerArg, const char* Binding>
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<size_t I, class PointerArg, class Binding>
constexpr bool
is_same_pvt_v<I, PointerArg, Binding, polyfill::void_t<typename PointerArg::tag, typename Binding::tag>> =
assert_same_pointer_type<I, PointerArg::tag::value, Binding::tag::value>();
#else
template<size_t I, class PointerArg, class Binding>
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<size_t I, class PointerArg, class Binding>
constexpr bool
is_same_pvt_v<I, PointerArg, Binding, polyfill::void_t<typename PointerArg::tag, typename Binding::tag>> =
assert_same_pointer_type<I, typename PointerArg::tag, typename Binding::tag>();
#endif
template<size_t I, class FnArg, class CallArg>
SQLITE_ORM_CONSTEVAL bool validate_pointer_value_type(std::false_type) {
return true;
}
template<size_t I, class FnArg, class CallArg>
SQLITE_ORM_CONSTEVAL bool validate_pointer_value_type(std::true_type) {
return is_same_pvt_v<I, FnArg, CallArg>;
}
template<class FnArgs, class CallArgs>
SQLITE_ORM_CONSTEVAL bool validate_pointer_value_types(polyfill::index_constant<size_t(-1)>) {
return true;
}
template<class FnArgs, class CallArgs, size_t I>
SQLITE_ORM_CONSTEVAL bool validate_pointer_value_types(polyfill::index_constant<I>) {
using func_arg_t = std::tuple_element_t<I, FnArgs>;
using passed_arg_t = unpacked_arg_t<std::tuple_element_t<I, CallArgs>>;
#ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED
constexpr bool valid = validate_pointer_value_type<I,
std::tuple_element_t<I, FnArgs>,
unpacked_arg_t<std::tuple_element_t<I, CallArgs>>>(
polyfill::bool_constant < (polyfill::is_specialization_of_v<func_arg_t, pointer_arg>) ||
(polyfill::is_specialization_of_v<passed_arg_t, pointer_binding>) > {});
return validate_pointer_value_types<FnArgs, CallArgs>(polyfill::index_constant<I - 1>{}) && valid;
#else
return validate_pointer_value_types<FnArgs, CallArgs>(polyfill::index_constant<I - 1>{}) &&
validate_pointer_value_type<I,
std::tuple_element_t<I, FnArgs>,
unpacked_arg_t<std::tuple_element_t<I, CallArgs>>>(
polyfill::bool_constant < (polyfill::is_specialization_of_v<func_arg_t, pointer_arg>) ||
(polyfill::is_specialization_of_v<passed_arg_t, pointer_binding>) > {});
#endif
}
}
/**
* Used to call user defined function: `func<MyFunc>(...);`
*/
template<class F, class... Args>
internal::function_call<F, Args...> func(Args... args) {
using args_tuple = std::tuple<Args...>;
using function_args_tuple = typename internal::callable_arguments<F>::args_tuple;
constexpr auto argsCount = std::tuple_size<args_tuple>::value;
constexpr auto functionArgsCount = std::tuple_size<function_args_tuple>::value;
static_assert((argsCount == functionArgsCount &&
!std::is_same<function_args_tuple, std::tuple<arg_values>>::value &&
internal::validate_pointer_value_types<function_args_tuple, args_tuple>(
polyfill::index_constant<std::min<>(functionArgsCount, argsCount) - 1>{})) ||
std::is_same<function_args_tuple, std::tuple<arg_values>>::value,
"Number of arguments does not match");
return {std::make_tuple(std::forward<Args>(args)...)};
}
}