@@ -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_
@@ -2834,6 +2857,8 @@ class Renderer : public NodeVisitor {
28342857
28352858// #include "throw.hpp"
28362859
2860+ // #include "utils.hpp"
2861+
28372862
28382863namespace inja {
28392864
@@ -2844,6 +2869,41 @@ class Environment {
28442869 FunctionStorage function_storage;
28452870 TemplateStorage template_storage;
28462871
2872+ template <class Arg >
2873+ static Arg get_callback_argument (const Arguments &args, size_t index) {
2874+ using BasicArg = std::remove_const_t <
2875+ std::remove_pointer_t <std::remove_reference_t <std::decay_t <Arg>>>>;
2876+
2877+ static constexpr bool check =
2878+ std::is_const_v<std::remove_reference_t <Arg>> ||
2879+ std::is_same_v<BasicArg, Arg>;
2880+ static_assert (check, " Arguments should be either const& or a value type" );
2881+
2882+ if constexpr (std::is_same_v<BasicArg, json>) {
2883+ return *args[index];
2884+ } else if constexpr (std::is_lvalue_reference_v<Arg>) {
2885+ return args[index]->get_ref <Arg>();
2886+ } else {
2887+ return args[index]->get <Arg>();
2888+ }
2889+ }
2890+
2891+ template <class Ret , class Func , class ... Args, size_t ... Is>
2892+ void add_callback_closure (const std::string &name, Func func,
2893+ function_signature::ArgsList<Args...> /* args*/ ,
2894+ std::index_sequence<Is...> /* seq*/ ) {
2895+ add_callback (name, sizeof ...(Args),
2896+ [func = std::move (func)] //
2897+ ([[maybe_unused]] const Arguments &args) -> json {
2898+ if constexpr (std::is_same_v<Ret, void >) {
2899+ func (get_callback_argument<Args>(args, Is)...);
2900+ return {};
2901+ } else {
2902+ return func (get_callback_argument<Args>(args, Is)...);
2903+ }
2904+ });
2905+ }
2906+
28472907protected:
28482908 LexerConfig lexer_config;
28492909 ParserConfig parser_config;
@@ -2998,10 +3058,42 @@ class Environment {
29983058 }
29993059
30003060 /* !
3001- @brief Adds a variadic callback
3061+ @brief Adds a callback
30023062 */
3003- void add_callback (const std::string& name, const CallbackFunction& callback) {
3004- add_callback (name, -1 , callback);
3063+ template <class Callback >
3064+ void add_callback (const std::string &name, Callback callback) {
3065+ static constexpr auto get_sig = [] {
3066+ if constexpr (std::is_class_v<Callback>) {
3067+ return function_signature::Get<decltype (&Callback::operator ())> {};
3068+ } else {
3069+ return function_signature::Get<Callback>{};
3070+ }
3071+ };
3072+ using Sig = decltype (get_sig ());
3073+ static constexpr size_t num_args =
3074+ std::tuple_size_v<typename Sig::ArgsTuple>;
3075+
3076+ static constexpr auto is_arguments_vector = [] {
3077+ if constexpr (num_args == 1 ) {
3078+ return std::is_same_v<
3079+ std::remove_cv_t <std::remove_reference_t <
3080+ std::tuple_element_t <0 , typename Sig::ArgsTuple>>>,
3081+ Arguments>;
3082+ } else {
3083+ return false ;
3084+ }
3085+ };
3086+
3087+ if constexpr (is_arguments_vector ()) {
3088+ // If callback has the only argument of `Arguments` - fallback to adding a
3089+ // variadic callback
3090+ add_callback (name, -1 , callback);
3091+ } else {
3092+ // If it has other arguments - use it in a closure
3093+ add_callback_closure<typename Sig::Ret>(
3094+ name, std::move (callback), typename Sig::ArgsList{},
3095+ std::make_index_sequence<num_args>{});
3096+ }
30053097 }
30063098
30073099 /* !
0 commit comments