Skip to content

Commit

Permalink
Merge pull request #1249 from FireDaemon/dedicated_function_traits
Browse files Browse the repository at this point in the history
Function traits have been moved to a separate header file
  • Loading branch information
trueqbit authored Nov 23, 2023
2 parents e04f3ef + 7833a70 commit 78c6736
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 82 deletions.
8 changes: 4 additions & 4 deletions dev/ast_iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -479,13 +479,13 @@ namespace sqlite_orm {
}
};

template<class F, class... Args>
struct ast_iterator<function_call<F, Args...>, void> {
using node_type = function_call<F, Args...>;
template<class F, class... CallArgs>
struct ast_iterator<function_call<F, CallArgs...>, void> {
using node_type = function_call<F, CallArgs...>;

template<class L>
void operator()(const node_type& f, L& lambda) const {
iterate_ast(f.args, lambda);
iterate_ast(f.callArgs, lambda);
}
};

Expand Down
44 changes: 14 additions & 30 deletions dev/function.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "functional/cxx_universal.h"
#include "functional/cxx_type_traits_polyfill.h"
#include "functional/function_traits.h"
#include "tags.h"

namespace sqlite_orm {
Expand Down Expand Up @@ -44,47 +45,30 @@ namespace sqlite_orm {
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_udf_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;
using args_tuple = function_arguments<scalar_call_function_t<F>, std::tuple, std::decay_t>;
using return_type = function_return_type_t<scalar_call_function_t<F>>;
};

template<class F>
struct callable_arguments_impl<F, std::enable_if_t<is_aggregate_udf_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;
using args_tuple = function_arguments<aggregate_step_function_t<F>, std::tuple, std::decay_t>;
using return_type = function_return_type_t<aggregate_fin_function_t<F>>;
};

template<class F>
struct callable_arguments : callable_arguments_impl<F> {};

template<class UDF, class... Args>
template<class UDF, class... CallArgs>
struct function_call {
using udf_type = UDF;
using args_tuple = std::tuple<Args...>;
using args_tuple = std::tuple<CallArgs...>;

args_tuple args;
args_tuple callArgs;
};

template<class T>
Expand All @@ -95,8 +79,8 @@ namespace sqlite_orm {
struct unpacked_arg {
using type = T;
};
template<class F, class... Args>
struct unpacked_arg<function_call<F, Args...>> {
template<class F, class... CallArgs>
struct unpacked_arg<function_call<F, CallArgs...>> {
using type = typename callable_arguments<F>::return_type;
};
template<class T>
Expand Down Expand Up @@ -185,9 +169,9 @@ namespace sqlite_orm {
*/
template<class UDF>
struct function : polyfill::type_identity<UDF> {
template<typename... Args>
function_call<UDF, Args...> operator()(Args... args) const {
using args_tuple = std::tuple<Args...>;
template<typename... CallArgs>
function_call<UDF, CallArgs...> operator()(CallArgs... callArgs) const {
using args_tuple = std::tuple<CallArgs...>;
using function_args_tuple = typename callable_arguments<UDF>::args_tuple;
constexpr size_t argsCount = std::tuple_size<args_tuple>::value;
constexpr size_t functionArgsCount = std::tuple_size<function_args_tuple>::value;
Expand All @@ -197,7 +181,7 @@ namespace sqlite_orm {
polyfill::index_constant<std::min(functionArgsCount, argsCount) - 1>{})) ||
std::is_same<function_args_tuple, std::tuple<arg_values>>::value,
"The number of arguments does not match");
return {{std::forward<Args>(args)...}};
return {{std::forward<CallArgs>(callArgs)...}};
}
};
}
Expand Down
63 changes: 63 additions & 0 deletions dev/functional/function_traits.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#pragma once
#include "cxx_type_traits_polyfill.h"
#include "mpl.h"

namespace sqlite_orm {
namespace internal {
template<class F>
struct function_traits;

/*
* A function's return type
*/
template<class F>
using function_return_type_t = typename function_traits<F>::return_type;

/*
* A function's arguments tuple
*/
template<class F,
template<class...>
class Tuple,
template<class...> class ProjectOp = polyfill::type_identity_t>
using function_arguments = typename function_traits<F>::template arguments_tuple<Tuple, ProjectOp>;

/*
* Define nested typenames:
* - return_type
* - arguments_tuple
*/
template<class R, class... Args>
struct function_traits<R(Args...)> {
using return_type = R;

template<template<class...> class Tuple, template<class...> class ProjectOp>
using arguments_tuple = Tuple<mpl::invoke_fn_t<ProjectOp, Args>...>;
};

// non-exhaustive partial specializations of `function_traits`

template<class R, class... Args>
struct function_traits<R(Args...) const> : function_traits<R(Args...)> {};

#ifdef SQLITE_ORM_NOTHROW_ALIASES_SUPPORTED
template<class R, class... Args>
struct function_traits<R(Args...) noexcept> : function_traits<R(Args...)> {};

template<class R, class... Args>
struct function_traits<R(Args...) const noexcept> : function_traits<R(Args...)> {};
#endif

/*
* Pick signature of function pointer
*/
template<class R, class... Args>
struct function_traits<R (*)(Args...)> : function_traits<R(Args...)> {};

/*
* Pick signature of pointer-to-member function
*/
template<class F, class O>
struct function_traits<F O::*> : function_traits<F> {};
}
}
8 changes: 4 additions & 4 deletions dev/statement_serializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -363,14 +363,14 @@ namespace sqlite_orm {
struct statement_serializer<built_in_aggregate_function_t<R, S, Args...>, void>
: statement_serializer<built_in_function_t<R, S, Args...>, void> {};

template<class F, class... Args>
struct statement_serializer<function_call<F, Args...>, void> {
using statement_type = function_call<F, Args...>;
template<class F, class... CallArgs>
struct statement_serializer<function_call<F, CallArgs...>, void> {
using statement_type = function_call<F, CallArgs...>;

template<class Ctx>
std::string operator()(const statement_type& statement, const Ctx& context) const {
std::stringstream ss;
ss << F::name() << "(" << streaming_expressions_tuple(statement.args, context) << ")";
ss << F::name() << "(" << streaming_expressions_tuple(statement.callArgs, context) << ")";
return ss.str();
}
};
Expand Down
1 change: 1 addition & 0 deletions dev/storage_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,7 @@ namespace sqlite_orm {
auto result = polyfill::apply(udf, std::move(argsTuple));
statement_binder<return_type>().result(context, result);
},
/* finalCall = */
nullptr,
allocate_udf_storage<F>());

Expand Down
Loading

0 comments on commit 78c6736

Please sign in to comment.