Skip to content

Commit e3a0e0e

Browse files
committed
Update single_include/inja.hpp
1 parent 68dbcde commit e3a0e0e

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_
@@ -2790,6 +2813,8 @@ class Renderer : public NodeVisitor {
27902813

27912814
// #include "throw.hpp"
27922815

2816+
// #include "utils.hpp"
2817+
27932818

27942819
namespace 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+
28032863
protected:
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

Comments
 (0)