|
1 | 1 | #pragma once |
2 | 2 |
|
3 | | -#include <type_traits> // std::enable_if, std::is_member_function_pointer, std::is_function, std::remove_const, std::remove_pointer, std::decay, std::is_same, std::false_type, std::true_type |
| 3 | +#include <type_traits> // std::enable_if, std::is_member_function_pointer, std::is_function, std::remove_const, std::decay, std::is_convertible, std::is_same, std::false_type, std::true_type |
4 | 4 | #ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED |
5 | 5 | #include <concepts> // std::copy_constructible |
6 | 6 | #endif |
7 | 7 | #include <tuple> // std::tuple, std::tuple_size, std::tuple_element |
8 | 8 | #include <algorithm> // std::min, std::copy_n |
9 | 9 | #include <utility> // std::move, std::forward |
10 | 10 |
|
11 | | -#include "functional/cxx_universal.h" // ::size_t |
| 11 | +#include "functional/cxx_universal.h" // ::size_t, ::nullptr_t |
12 | 12 | #include "functional/cxx_type_traits_polyfill.h" |
13 | 13 | #include "functional/cstring_literal.h" |
14 | 14 | #include "functional/function_traits.h" |
@@ -229,98 +229,115 @@ namespace sqlite_orm { |
229 | 229 | template<class T> |
230 | 230 | using unpacked_arg_t = typename unpacked_arg<T>::type; |
231 | 231 |
|
232 | | - template<size_t I, class FnArg, class CallArg> |
| 232 | + template<size_t I, class FnParam, class CallArg> |
233 | 233 | SQLITE_ORM_CONSTEVAL bool expected_pointer_value() { |
234 | | - static_assert(polyfill::always_false_v<FnArg, CallArg>, "Expected a pointer value for I-th argument"); |
| 234 | + static_assert(polyfill::always_false_v<FnParam, CallArg>, "Expected a pointer value for I-th argument"); |
235 | 235 | return false; |
236 | 236 | } |
237 | 237 |
|
238 | | - template<size_t I, class FnArg, class CallArg, class EnableIfTag = void> |
239 | | - constexpr bool is_same_pvt_v = expected_pointer_value<I, FnArg, CallArg>(); |
| 238 | + template<size_t I, class FnParam, class CallArg, class EnableIfTag = void> |
| 239 | + constexpr bool is_same_pvt_v = expected_pointer_value<I, FnParam, CallArg>(); |
240 | 240 |
|
241 | 241 | // Always allow binding nullptr to a pointer argument |
242 | 242 | template<size_t I, class PointerArg> |
243 | 243 | constexpr bool is_same_pvt_v<I, PointerArg, nullptr_t, polyfill::void_t<typename PointerArg::tag>> = true; |
| 244 | + // Always allow binding nullptr to a pointer argument |
| 245 | + template<size_t I, class P, class T, class D> |
| 246 | + constexpr bool is_same_pvt_v<I, pointer_arg<P, T>, pointer_binding<nullptr_t, T, D>, void> = true; |
| 247 | + |
| 248 | + template<size_t I, class PointerArgDataType, class BindingDataType> |
| 249 | + SQLITE_ORM_CONSTEVAL bool assert_same_pointer_data_type() { |
| 250 | + constexpr bool valid = std::is_convertible<BindingDataType*, PointerArgDataType*>::value; |
| 251 | + static_assert(valid, "Pointer data types of I-th argument do not match"); |
| 252 | + return valid; |
| 253 | + } |
244 | 254 |
|
245 | 255 | #if __cplusplus >= 201703L // C++17 or later |
246 | 256 | template<size_t I, const char* PointerArg, const char* Binding> |
247 | | - SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { |
| 257 | + SQLITE_ORM_CONSTEVAL bool assert_same_pointer_tag() { |
248 | 258 | constexpr bool valid = Binding == PointerArg; |
249 | | - static_assert(valid, "Pointer value types of I-th argument do not match"); |
| 259 | + static_assert(valid, "Pointer types (tags) of I-th argument do not match"); |
250 | 260 | return valid; |
251 | 261 | } |
252 | | - |
253 | 262 | template<size_t I, class PointerArg, class Binding> |
254 | 263 | constexpr bool |
255 | 264 | is_same_pvt_v<I, PointerArg, Binding, polyfill::void_t<typename PointerArg::tag, typename Binding::tag>> = |
256 | | - assert_same_pointer_type<I, PointerArg::tag::value, Binding::tag::value>(); |
| 265 | + assert_same_pointer_tag<I, PointerArg::tag::value, Binding::tag::value>() && |
| 266 | + assert_same_pointer_data_type<I, |
| 267 | + typename PointerArg::qualified_type, |
| 268 | + typename Binding::qualified_type>(); |
257 | 269 | #else |
258 | 270 | template<size_t I, class PointerArg, class Binding> |
259 | | - SQLITE_ORM_CONSTEVAL bool assert_same_pointer_type() { |
| 271 | + constexpr bool assert_same_pointer_tag() { |
260 | 272 | constexpr bool valid = Binding::value == PointerArg::value; |
261 | | - static_assert(valid, "Pointer value types of I-th argument do not match"); |
| 273 | + static_assert(valid, "Pointer types (tags) of I-th argument do not match"); |
262 | 274 | return valid; |
263 | 275 | } |
264 | 276 |
|
265 | 277 | template<size_t I, class PointerArg, class Binding> |
266 | 278 | constexpr bool |
267 | 279 | is_same_pvt_v<I, PointerArg, Binding, polyfill::void_t<typename PointerArg::tag, typename Binding::tag>> = |
268 | | - assert_same_pointer_type<I, typename PointerArg::tag, typename Binding::tag>(); |
| 280 | + assert_same_pointer_tag<I, typename PointerArg::tag, typename Binding::tag>(); |
269 | 281 | #endif |
270 | 282 |
|
271 | | - template<size_t I, class FnArg, class CallArg> |
| 283 | + // not a pointer value, currently leave it unchecked |
| 284 | + template<size_t I, class FnParam, class CallArg> |
272 | 285 | SQLITE_ORM_CONSTEVAL bool validate_pointer_value_type(std::false_type) { |
273 | 286 | return true; |
274 | 287 | } |
275 | 288 |
|
276 | | - template<size_t I, class FnArg, class CallArg> |
| 289 | + // check the type of pointer values |
| 290 | + template<size_t I, class FnParam, class CallArg> |
277 | 291 | SQLITE_ORM_CONSTEVAL bool validate_pointer_value_type(std::true_type) { |
278 | | - return is_same_pvt_v<I, FnArg, CallArg>; |
| 292 | + return is_same_pvt_v<I, FnParam, CallArg>; |
279 | 293 | } |
280 | 294 |
|
281 | | - template<class FnArgs, class CallArgs> |
| 295 | + template<class FnParams, class CallArgs> |
282 | 296 | SQLITE_ORM_CONSTEVAL bool validate_pointer_value_types(polyfill::index_constant<size_t(-1)>) { |
283 | 297 | return true; |
284 | 298 | } |
285 | | - template<class FnArgs, class CallArgs, size_t I> |
| 299 | + template<class FnParams, class CallArgs, size_t I> |
286 | 300 | SQLITE_ORM_CONSTEVAL bool validate_pointer_value_types(polyfill::index_constant<I>) { |
287 | | - using func_arg_t = std::tuple_element_t<I, FnArgs>; |
288 | | - using passed_arg_t = unpacked_arg_t<std::tuple_element_t<I, CallArgs>>; |
| 301 | + using func_param_type = std::tuple_element_t<I, FnParams>; |
| 302 | + using call_arg_type = unpacked_arg_t<std::tuple_element_t<I, CallArgs>>; |
289 | 303 |
|
290 | 304 | #ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED |
291 | 305 | constexpr bool valid = validate_pointer_value_type<I, |
292 | | - std::tuple_element_t<I, FnArgs>, |
| 306 | + std::tuple_element_t<I, FnParams>, |
293 | 307 | unpacked_arg_t<std::tuple_element_t<I, CallArgs>>>( |
294 | | - polyfill::bool_constant < (polyfill::is_specialization_of_v<func_arg_t, pointer_arg>) || |
295 | | - (polyfill::is_specialization_of_v<passed_arg_t, pointer_binding>) > {}); |
| 308 | + polyfill::bool_constant < (polyfill::is_specialization_of_v<func_param_type, pointer_arg>) || |
| 309 | + (polyfill::is_specialization_of_v<call_arg_type, pointer_binding>) > {}); |
296 | 310 |
|
297 | | - return validate_pointer_value_types<FnArgs, CallArgs>(polyfill::index_constant<I - 1>{}) && valid; |
| 311 | + return validate_pointer_value_types<FnParams, CallArgs>(polyfill::index_constant<I - 1>{}) && valid; |
298 | 312 | #else |
299 | | - return validate_pointer_value_types<FnArgs, CallArgs>(polyfill::index_constant<I - 1>{}) && |
| 313 | + return validate_pointer_value_types<FnParams, CallArgs>(polyfill::index_constant<I - 1>{}) && |
300 | 314 | validate_pointer_value_type<I, |
301 | | - std::tuple_element_t<I, FnArgs>, |
| 315 | + std::tuple_element_t<I, FnParams>, |
302 | 316 | unpacked_arg_t<std::tuple_element_t<I, CallArgs>>>( |
303 | | - polyfill::bool_constant < (polyfill::is_specialization_of_v<func_arg_t, pointer_arg>) || |
304 | | - (polyfill::is_specialization_of_v<passed_arg_t, pointer_binding>) > {}); |
| 317 | + polyfill::bool_constant < (polyfill::is_specialization_of_v<func_param_type, pointer_arg>) || |
| 318 | + (polyfill::is_specialization_of_v<call_arg_type, pointer_binding>) > {}); |
305 | 319 | #endif |
306 | 320 | } |
307 | 321 |
|
| 322 | + /* |
| 323 | + * Note: Currently the number of call arguments is checked and whether the types of pointer values match, |
| 324 | + * but other call argument types are not checked against the parameter types of the function. |
| 325 | + */ |
308 | 326 | template<typename UDF, typename... CallArgs> |
309 | 327 | #ifdef SQLITE_ORM_RELAXED_CONSTEXPR_SUPPORTED |
310 | | - SQLITE_ORM_CONSTEVAL |
| 328 | + SQLITE_ORM_CONSTEVAL void check_function_call() { |
| 329 | +#else |
| 330 | + void check_function_call() { |
311 | 331 | #endif |
312 | | - void |
313 | | - check_function_call() { |
314 | | - using args_tuple = std::tuple<CallArgs...>; |
315 | | - using function_args_tuple = typename callable_arguments<UDF>::args_tuple; |
316 | | - constexpr size_t argsCount = std::tuple_size<args_tuple>::value; |
317 | | - constexpr size_t functionArgsCount = std::tuple_size<function_args_tuple>::value; |
318 | | - static_assert((argsCount == functionArgsCount && |
319 | | - !std::is_same<function_args_tuple, std::tuple<arg_values>>::value && |
320 | | - validate_pointer_value_types<function_args_tuple, args_tuple>( |
321 | | - polyfill::index_constant<std::min(functionArgsCount, argsCount) - 1>{})) || |
322 | | - std::is_same<function_args_tuple, std::tuple<arg_values>>::value, |
323 | | - "The number of arguments does not match"); |
| 332 | + using call_args_tuple = std::tuple<CallArgs...>; |
| 333 | + using function_params_tuple = typename callable_arguments<UDF>::args_tuple; |
| 334 | + constexpr size_t callArgsCount = std::tuple_size<call_args_tuple>::value; |
| 335 | + constexpr size_t functionParamsCount = std::tuple_size<function_params_tuple>::value; |
| 336 | + static_assert(std::is_same<function_params_tuple, std::tuple<arg_values>>::value || |
| 337 | + (callArgsCount == functionParamsCount && |
| 338 | + validate_pointer_value_types<function_params_tuple, call_args_tuple>( |
| 339 | + polyfill::index_constant<std::min(functionParamsCount, callArgsCount) - 1>{})), |
| 340 | + "Check the number and types of the function call arguments"); |
324 | 341 | } |
325 | 342 |
|
326 | 343 | /* |
@@ -475,6 +492,9 @@ namespace sqlite_orm { |
475 | 492 |
|
476 | 493 | /** @short Call a user-defined function. |
477 | 494 | * |
| 495 | + * Note: Currently the number of call arguments is checked and whether the types of pointer values match, |
| 496 | + * but other call argument types are not checked against the parameter types of the function. |
| 497 | + * |
478 | 498 | * Example: |
479 | 499 | * struct IdFunc { int oeprator(int arg)() const { return arg; } }; |
480 | 500 | * // inline: |
|
0 commit comments