Skip to content

Commit 3d3d4fa

Browse files
committed
Add reflection and 'sort' filter
1 parent de61db6 commit 3d3d4fa

File tree

6 files changed

+197
-20
lines changed

6 files changed

+197
-20
lines changed

include/jinja2cpp/reflected_value.h

Lines changed: 91 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,60 @@ namespace jinja2
99
template<typename T>
1010
Value Reflect(T&& val);
1111

12-
#if 0
12+
template<typename T, bool val>
13+
struct TypeReflectedImpl : std::integral_constant<bool, val>
14+
{
15+
};
16+
17+
template<typename T>
18+
struct TypeReflected : TypeReflectedImpl<T, true>
19+
{
20+
using FieldAccessor = std::function<Value (const T& value)>;
21+
};
22+
23+
24+
25+
template<typename T>
26+
struct TypeReflection : TypeReflectedImpl<T, false>
27+
{
28+
};
29+
1330
template<typename Derived>
14-
class ReflectedMapImplBase : public ReflectedMap::ItemAccessor
31+
class ReflectedMapImplBase : public MapItemAccessor
1532
{
1633
public:
1734
bool HasValue(const std::string& name) const override
1835
{
1936
return Derived::GetAccessors().count(name) != 0;
2037
}
21-
Value GetValue(const std::string& name) const override
38+
Value GetValueByName(const std::string& name) const override
2239
{
2340
auto& accessors = Derived::GetAccessors();
2441
auto p = accessors.find(name);
2542
if (p == accessors.end())
2643
throw std::runtime_error("Invalid field access");
2744

45+
return static_cast<const Derived*>(this)->GetField(p->second);
46+
}
47+
std::vector<std::string> GetKeys() const
48+
{
49+
std::vector<std::string> result;
50+
auto& accessors = Derived::GetAccessors();
51+
for (auto& i : accessors)
52+
result.push_back(i.first);
53+
54+
return result;
55+
}
56+
size_t GetSize() const override
57+
{
58+
return Derived::GetAccessors().size();
59+
}
60+
virtual Value GetValueByIndex(int64_t idx) const
61+
{
62+
auto& accessors = Derived::GetAccessors();
63+
auto p = accessors.begin();
64+
std::advance(p, idx);
65+
2866
return static_cast<const Derived*>(this)->GetField(p->second);
2967
}
3068
};
@@ -34,30 +72,31 @@ class ReflectedMapImpl : public ReflectedMapImplBase<ReflectedMapImpl<T>>
3472
{
3573
public:
3674
ReflectedMapImpl(T val) : m_value(val) {}
37-
using FieldAccessor = std::function<Value (const T& value)>;
75+
ReflectedMapImpl(const T* val) : m_valuePtr(val) {}
3876

39-
static auto& GetAccessors();
40-
static std::string ToString(const T& value);
77+
static auto GetAccessors() {return TypeReflection<T>::GetAccessors();}
4178
template<typename Fn>
4279
Value GetField(Fn&& accessor) const
4380
{
44-
return accessor(m_value);
81+
return accessor(m_valuePtr ? *m_valuePtr : m_value);
4582
}
4683

47-
std::string ToString() const override
48-
{
49-
return ToString(m_value);
50-
}
5184
private:
5285
T m_value;
86+
const T* m_valuePtr = nullptr;
5387
};
54-
#endif
5588

5689
namespace detail
5790
{
5891
template<typename T, typename Tag = void>
5992
struct Reflector;
6093

94+
template<typename T>
95+
using IsReflectedType = std::enable_if_t<TypeReflection<T>::value>;
96+
97+
// using IsReflectedType = std::enable_if_t<std::is_same<decltype(ReflectedMapImpl<T>::GetAccessors())::key_type, std::string>::value>;
98+
// using IsReflectedType = typename Type2Void<typename Type2TypeT<decltype(TypeReflection<T>::GetAccessors())>::key_type>::type;
99+
61100
struct ContainerReflector
62101
{
63102
template<typename T>
@@ -136,9 +175,29 @@ struct Reflector<std::vector<T>>
136175
{
137176
return ContainerReflector::CreateFromValue(std::move(val));
138177
}
139-
static auto CreateFromPtr(const std::vector<T>* val)
178+
template<typename U>
179+
static auto CreateFromPtr(U&& val)
140180
{
141-
return ContainerReflector::CreateFromPtr(val);
181+
return ContainerReflector::CreateFromPtr(std::forward<U>(val));
182+
}
183+
};
184+
185+
template<typename T>
186+
struct Reflector<T, IsReflectedType<T>>
187+
{
188+
static auto Create(const T& val)
189+
{
190+
return GenericMap([accessor = ReflectedMapImpl<T>(val)]() {return &accessor;});
191+
}
192+
193+
static auto CreateFromPtr(const T* val)
194+
{
195+
return GenericMap([accessor = ReflectedMapImpl<T>(static_cast<const T*>(val))]() {return &accessor;});
196+
}
197+
198+
static auto CreateFromPtr(std::shared_ptr<T> val)
199+
{
200+
return GenericMap([accessor = ReflectedMapImpl<T>(val.get())]() {return &accessor;});
142201
}
143202
};
144203

@@ -151,6 +210,15 @@ struct Reflector<const T&>
151210
}
152211
};
153212

213+
template<typename T>
214+
struct Reflector<T&>
215+
{
216+
static auto Create(T& val)
217+
{
218+
return Reflector<T>::Create(val);
219+
}
220+
};
221+
154222
template<typename T>
155223
struct Reflector<const T*>
156224
{
@@ -169,6 +237,15 @@ struct Reflector<T*>
169237
}
170238
};
171239

240+
template<typename T>
241+
struct Reflector<std::shared_ptr<T>>
242+
{
243+
static auto Create(std::shared_ptr<T> val)
244+
{
245+
return Reflector<T>::CreateFromPtr(val);
246+
}
247+
};
248+
172249
template<>
173250
struct Reflector<std::string>
174251
{

src/expression_evaluator.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace jinja2
1010

1111
std::unordered_map<std::string, ExpressionFilter::FilterFactoryFn> ExpressionFilter::s_filters = {
1212
{"join", &FilterFactory<filters::Join>::Create},
13+
{"sort", &FilterFactory<filters::Sort>::Create},
1314
};
1415

1516
std::unordered_map<std::string, IsExpression::TesterFactoryFn> IsExpression::s_testers = {

src/filters.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,70 @@ Value Join::Filter(const Value& baseVal, RenderContext& context)
3636
return result;
3737
}
3838

39+
Sort::Sort(FilterParams params)
40+
{
41+
helpers::FindParam(params, "", "attribute", m_attrNameEvaluator);
42+
}
43+
44+
struct GetAsValuesListVisitor : boost::static_visitor<ValuesList>
45+
{
46+
GetAsValuesListVisitor(Value attr = Value())
47+
: m_attr(std::move(attr))
48+
{}
49+
50+
ValuesList operator() (const ValuesList& values) const
51+
{
52+
if (m_attr.isEmpty())
53+
return values;
54+
55+
ValuesList result;
56+
std::transform(values.begin(), values.end(), std::back_inserter(result), [this](const Value& val) {return val.subscript(m_attr);});
57+
return result;
58+
}
59+
60+
ValuesList operator() (const GenericList& values) const
61+
{
62+
int64_t size = values.GetSize();
63+
64+
ValuesList result;
65+
for (int64_t idx = 0; idx < size; ++ idx)
66+
{
67+
auto val = values.GetValueByIndex(idx);
68+
if (!m_attr.isEmpty())
69+
result.push_back(val.subscript(m_attr));
70+
else
71+
result.push_back(val);
72+
}
73+
74+
return result;
75+
}
76+
77+
template<typename U>
78+
ValuesList operator() (U&&) const
79+
{
80+
return ValuesList();
81+
}
82+
83+
Value m_attr;
84+
};
85+
86+
Value Sort::Filter(const Value& baseVal, RenderContext& context)
87+
{
88+
Value attrName = m_attrNameEvaluator->Evaluate(context);
89+
ValuesList values = boost::apply_visitor(GetAsValuesListVisitor(), baseVal.data());
90+
91+
std::sort(values.begin(), values.end(), [&attrName](auto& val1, auto& val2) {
92+
Value cmpRes;
93+
if (attrName.isEmpty())
94+
cmpRes = boost::apply_visitor(visitors::BinaryMathOperation(BinaryExpression::LogicalLt), val1.data(), val2.data());
95+
else
96+
cmpRes = boost::apply_visitor(visitors::BinaryMathOperation(BinaryExpression::LogicalLt), val1.subscript(attrName).data(), val2.subscript(attrName).data());
97+
98+
return boost::apply_visitor(visitors::BooleanEvaluator(), cmpRes.data());
99+
});
100+
101+
return values;
102+
}
103+
39104
} // filters
40105
} // jinja2

src/filters.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ class Join : public ExpressionFilter::IExpressionFilter
3535
ExpressionEvaluatorPtr<> m_delimiterEval;
3636
ExpressionEvaluatorPtr<> m_attribute;
3737
};
38+
39+
class Sort : public ExpressionFilter::IExpressionFilter
40+
{
41+
public:
42+
Sort(FilterParams params);
43+
44+
Value Filter(const Value& baseVal, RenderContext& context);
45+
46+
private:
47+
ExpressionEvaluatorPtr<> m_attrNameEvaluator;
48+
ExpressionEvaluatorPtr<> m_descEvaluator;
49+
};
3850
} // filters
3951
} // jinja2
4052

src/statements.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace jinja2
55
{
6-
6+
77
struct ValuesListAdaptorCreator : public boost::static_visitor<std::function<const ListItemAccessor* ()>>
88
{
99
struct Adaptor : public ListItemAccessor
@@ -15,10 +15,10 @@ struct ValuesListAdaptorCreator : public boost::static_visitor<std::function<con
1515

1616
size_t GetSize() const override {return m_list->size();}
1717
Value GetValueByIndex(int64_t idx) const override {return (*m_list)[idx];};
18-
18+
1919
const ValuesList* m_list;
2020
};
21-
21+
2222

2323
std::function<const ListItemAccessor* ()> operator() (const ValuesList& values) const
2424
{
@@ -29,13 +29,13 @@ struct ValuesListAdaptorCreator : public boost::static_visitor<std::function<con
2929
{
3030
return [&values]() {return values.GetAccessor();};
3131
}
32-
32+
3333
template<typename U>
3434
std::function<const ListItemAccessor* ()> operator() (U&&) const
3535
{
3636
return []() {return nullptr;};
3737
}
38-
38+
3939
};
4040

4141
void ForStatement::Render(OutStream& os, RenderContext& values)
@@ -80,7 +80,7 @@ void ForStatement::Render(OutStream& os, RenderContext& values)
8080
m_mainBody->Render(os, values);
8181
}
8282

83-
if (!loopRendered)
83+
if (!loopRendered && m_elseBody)
8484
m_elseBody->Render(os, values);
8585

8686
values.ExitScope();

test/forloop_test.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,28 @@ a[2] = image[2];
5757
EXPECT_EQ(expectedResult, result);
5858
}
5959

60+
TEST(ForLoopTest, EmptyLoop)
61+
{
62+
std::string source = R"(
63+
{% for i in ints %}
64+
a[{{i}}] = image[{{i}}];
65+
{% endfor %}
66+
)";
67+
68+
Template tpl;
69+
ASSERT_TRUE(tpl.Load(source));
70+
71+
ValuesMap params = {
72+
{"ints", ValuesList()}
73+
};
74+
75+
std::string result = tpl.RenderAsString(params);
76+
std::cout << result << std::endl;
77+
std::string expectedResult = R"(
78+
)";
79+
EXPECT_EQ(expectedResult, result);
80+
}
81+
6082
TEST(ForLoopTest, ReflectedIntegersLoop)
6183
{
6284
std::string source = R"(

0 commit comments

Comments
 (0)