Skip to content

Commit 5de2a4e

Browse files
committed
Update single_include/inja.hpp
1 parent afe31e4 commit 5de2a4e

File tree

1 file changed

+97
-5
lines changed

1 file changed

+97
-5
lines changed

single_include/inja/inja.hpp

Lines changed: 97 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
339360
inline 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

28382863
namespace 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+
28472907
protected:
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

Comments
 (0)