@@ -74,8 +74,6 @@ std::abort(); \
7474#include < string>
7575#include < string_view>
7676
77- // #include "json.hpp"
78-
7977// #include "config.hpp"
8078#ifndef INCLUDE_INJA_CONFIG_HPP_
8179#define INCLUDE_INJA_CONFIG_HPP_
@@ -336,6 +334,29 @@ inline bool starts_with(std::string_view view, std::string_view prefix) {
336334}
337335} // namespace string_view
338336
337+ namespace function_signature {
338+ template <class ... Args> struct ArgsList {};
339+ template <class Func > struct Get {};
340+ template <class R , class ... A> //
341+ struct Get <R (*)(A...)> {
342+ using Ret = R;
343+ using ArgsList = ArgsList<A...>;
344+ using ArgsTuple = std::tuple<A...>;
345+ };
346+ template <class R , class C , class ... A> //
347+ struct Get <R (C::*)(A...)> {
348+ using Ret = R;
349+ using ArgsList = ArgsList<A...>;
350+ using ArgsTuple = std::tuple<A...>;
351+ };
352+ template <class R , class C , class ... A> //
353+ struct Get <R (C::*)(A...) const > {
354+ using Ret = R;
355+ using ArgsList = ArgsList<A...>;
356+ using ArgsTuple = std::tuple<A...>;
357+ };
358+ } // namespace function_signature
359+
339360inline SourceLocation get_source_location (std::string_view content, size_t pos) {
340361 // Get line and offset position (starts at 1:1)
341362 auto sliced = string_view::slice (content, 0 , pos);
@@ -922,6 +943,8 @@ struct RenderConfig {
922943
923944// #include "function_storage.hpp"
924945
946+ // #include "json.hpp"
947+
925948// #include "parser.hpp"
926949#ifndef INCLUDE_INJA_PARSER_HPP_
927950#define INCLUDE_INJA_PARSER_HPP_
@@ -2790,6 +2813,8 @@ class Renderer : public NodeVisitor {
27902813
27912814// #include "throw.hpp"
27922815
2816+ // #include "utils.hpp"
2817+
27932818
27942819namespace inja {
27952820
@@ -2800,6 +2825,41 @@ class Environment {
28002825 FunctionStorage function_storage;
28012826 TemplateStorage template_storage;
28022827
2828+ template <class Arg >
2829+ static Arg get_callback_argument (const Arguments &args, size_t index) {
2830+ using BasicArg = std::remove_const_t <
2831+ std::remove_pointer_t <std::remove_reference_t <std::decay_t <Arg>>>>;
2832+
2833+ static constexpr bool check =
2834+ std::is_const_v<std::remove_reference_t <Arg>> ||
2835+ std::is_same_v<BasicArg, Arg>;
2836+ static_assert (check, " Arguments should be either const& or a value type" );
2837+
2838+ if constexpr (std::is_same_v<BasicArg, json>) {
2839+ return *args[index];
2840+ } else if constexpr (std::is_lvalue_reference_v<Arg>) {
2841+ return args[index]->get_ref <Arg>();
2842+ } else {
2843+ return args[index]->get <Arg>();
2844+ }
2845+ }
2846+
2847+ template <class Ret , class Func , class ... Args, size_t ... Is>
2848+ void add_callback_closure (const std::string &name, Func func,
2849+ function_signature::ArgsList<Args...> /* args*/ ,
2850+ std::index_sequence<Is...> /* seq*/ ) {
2851+ add_callback (name, sizeof ...(Args),
2852+ [func = std::move (func)] //
2853+ ([[maybe_unused]] const Arguments &args) -> json {
2854+ if constexpr (std::is_same_v<Ret, void >) {
2855+ func (get_callback_argument<Args>(args, Is)...);
2856+ return {};
2857+ } else {
2858+ return func (get_callback_argument<Args>(args, Is)...);
2859+ }
2860+ });
2861+ }
2862+
28032863protected:
28042864 LexerConfig lexer_config;
28052865 ParserConfig parser_config;
@@ -2954,10 +3014,42 @@ class Environment {
29543014 }
29553015
29563016 /* !
2957- @brief Adds a variadic callback
3017+ @brief Adds a callback
29583018 */
2959- void add_callback (const std::string& name, const CallbackFunction& callback) {
2960- add_callback (name, -1 , callback);
3019+ template <class Callback >
3020+ void add_callback (const std::string &name, Callback callback) {
3021+ static constexpr auto get_sig = [] {
3022+ if constexpr (std::is_class_v<Callback>) {
3023+ return function_signature::Get<decltype (&Callback::operator ())> {};
3024+ } else {
3025+ return function_signature::Get<Callback>{};
3026+ }
3027+ };
3028+ using Sig = decltype (get_sig ());
3029+ static constexpr size_t num_args =
3030+ std::tuple_size_v<typename Sig::ArgsTuple>;
3031+
3032+ static constexpr auto is_arguments_vector = [] {
3033+ if constexpr (num_args == 1 ) {
3034+ return std::is_same_v<
3035+ std::remove_cv_t <std::remove_reference_t <
3036+ std::tuple_element_t <0 , typename Sig::ArgsTuple>>>,
3037+ Arguments>;
3038+ } else {
3039+ return false ;
3040+ }
3041+ };
3042+
3043+ if constexpr (is_arguments_vector ()) {
3044+ // If callback has the only argument of `Arguments` - fallback to adding a
3045+ // variadic callback
3046+ add_callback (name, -1 , callback);
3047+ } else {
3048+ // If it has other arguments - use it in a closure
3049+ add_callback_closure<typename Sig::Ret>(
3050+ name, std::move (callback), typename Sig::ArgsList{},
3051+ std::make_index_sequence<num_args>{});
3052+ }
29613053 }
29623054
29633055 /* !
0 commit comments