discord-bot/libs/sqlite_orm-1.8.2/dev/function.h

247 lines
11 KiB
C
Raw Permalink Normal View History

2024-02-25 14:05:45 -05:00
#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)...)};
}
}