Skip to content

Commit 8e4fb43

Browse files
committed
Implement loop over Values and Generic lists
1 parent 23b830a commit 8e4fb43

File tree

4 files changed

+96
-15
lines changed

4 files changed

+96
-15
lines changed

include/jinja2cpp/reflected_value.h

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
namespace jinja2
77
{
88

9+
template<typename T>
10+
Value Reflect(T&& val);
11+
912
#if 0
1013
template<typename Derived>
1114
class ReflectedMapImplBase : public ReflectedMap::ItemAccessor
@@ -73,7 +76,9 @@ struct ContainerReflector
7376
}
7477
Value GetValueByIndex(int64_t idx) const override
7578
{
76-
return Reflect(m_value.begin() + idx);
79+
auto p = m_value.begin();
80+
std::advance(p, idx);
81+
return Reflect(*p);
7782
}
7883
};
7984

@@ -99,7 +104,7 @@ struct ContainerReflector
99104
};
100105

101106
template<typename T>
102-
static Value CreateFromPtr(T&& cont)
107+
static Value CreateFromValue(T&& cont)
103108
{
104109
return GenericList([accessor = ValueItemAccessor<T>(std::move(cont))]() {return &accessor;});
105110
}
@@ -116,7 +121,7 @@ struct Reflector<std::set<T>>
116121
{
117122
static auto Create(std::set<T> val)
118123
{
119-
return ContainerReflector::Create(std::move(val));
124+
return ContainerReflector::CreateFromValue(std::move(val));
120125
}
121126
static auto CreateFromPtr(const std::set<T>* val)
122127
{
@@ -129,7 +134,7 @@ struct Reflector<std::vector<T>>
129134
{
130135
static auto Create(std::vector<T> val)
131136
{
132-
return ContainerReflector::Create(std::move(val));
137+
return ContainerReflector::CreateFromValue(std::move(val));
133138
}
134139
static auto CreateFromPtr(const std::vector<T>* val)
135140
{
@@ -176,6 +181,19 @@ struct Reflector<std::string>
176181
return Value(*str);
177182
}
178183
};
184+
185+
template<>
186+
struct Reflector<int64_t>
187+
{
188+
static auto Create(int64_t val)
189+
{
190+
return Value(val);
191+
}
192+
static auto CreateFromPtr(const int64_t* val)
193+
{
194+
return Value(*val);
195+
}
196+
};
179197
} // detail
180198

181199
template<typename T>

include/jinja2cpp/value.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ class GenericList
6969
}
7070

7171
Value GetValueByIndex(int64_t idx) const;
72+
73+
auto GetAccessor() const
74+
{
75+
return m_accessor();
76+
}
7277

7378
std::function<const ListItemAccessor* ()> m_accessor;
7479
};

src/statements.cpp

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

44
namespace jinja2
55
{
6+
7+
struct ValuesListAdaptorCreator : public boost::static_visitor<std::function<const ListItemAccessor* ()>>
8+
{
9+
struct Adaptor : public ListItemAccessor
10+
{
11+
Adaptor(const ValuesList* list)
12+
: m_list(list)
13+
{
14+
}
15+
16+
size_t GetSize() const override {return m_list->size();}
17+
Value GetValueByIndex(int64_t idx) const override {return (*m_list)[idx];};
18+
19+
const ValuesList* m_list;
20+
};
21+
22+
23+
std::function<const ListItemAccessor* ()> operator() (const ValuesList& values) const
24+
{
25+
return [adaptor = Adaptor(&values)]() {return &adaptor;};
26+
}
27+
28+
std::function<const ListItemAccessor* ()> operator() (const GenericList& values) const
29+
{
30+
return [&values]() {return values.GetAccessor();};
31+
}
32+
33+
template<typename U>
34+
std::function<const ListItemAccessor* ()> operator() (U&&) const
35+
{
36+
return []() {return nullptr;};
37+
}
38+
39+
};
640

741
void ForStatement::Render(OutStream& os, RenderContext& values)
842
{
@@ -13,15 +47,11 @@ void ForStatement::Render(OutStream& os, RenderContext& values)
1347
context["loop"] = ValuesMap();
1448
auto& loopVar = context["loop"].asMap();
1549

16-
ValuesList* loopItems = nullptr;
17-
ValuesList fakeItems;
18-
19-
if (loopVal.isEmpty() || !loopVal.isList())
20-
loopItems = &fakeItems;
21-
else
22-
loopItems = &loopVal.asList();
50+
auto loopItems = boost::apply_visitor(ValuesListAdaptorCreator(), loopVal.data());
51+
if (!loopItems())
52+
return;
2353

24-
int64_t itemsNum = static_cast<int64_t>(loopItems->size());
54+
int64_t itemsNum = static_cast<int64_t>(loopItems()->GetSize());
2555
loopVar["length"] = Value(itemsNum);
2656
bool loopRendered = false;
2757
for (int64_t itemIdx = 0; itemIdx != itemsNum; ++ itemIdx)
@@ -32,13 +62,13 @@ void ForStatement::Render(OutStream& os, RenderContext& values)
3262
loopVar["first"] = Value(itemIdx == 0);
3363
loopVar["last"] = Value(itemIdx == itemsNum - 1);
3464
if (itemIdx != 0)
35-
loopVar["previtem"] = (*loopItems)[static_cast<size_t>(itemIdx - 1)];
65+
loopVar["previtem"] = loopItems()->GetValueByIndex(static_cast<size_t>(itemIdx - 1));
3666
if (itemIdx != itemsNum - 1)
37-
loopVar["nextitem"] = (*loopItems)[static_cast<size_t>(itemIdx + 1)];
67+
loopVar["nextitem"] = loopItems()->GetValueByIndex(static_cast<size_t>(itemIdx + 1));
3868
else
3969
loopVar.erase("nextitem");
4070

41-
auto& curValue = (*loopItems)[static_cast<size_t>(itemIdx)];
71+
const auto& curValue = loopItems()->GetValueByIndex(static_cast<size_t>(itemIdx));
4272
if (m_vars.size() > 1 && curValue.isMap())
4373
{
4474
for (auto& varName : m_vars)

test/forloop_test.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "gtest/gtest.h"
55

66
#include "jinja2cpp/template.h"
7+
#include "jinja2cpp/reflected_value.h"
78

89
using namespace jinja2;
910

@@ -56,6 +57,31 @@ a[2] = image[2];
5657
EXPECT_EQ(expectedResult, result);
5758
}
5859

60+
TEST(ForLoopTest, ReflectedIntegersLoop)
61+
{
62+
std::string source = R"(
63+
{% for i in its %}
64+
a[{{i}}] = image[{{i}}];
65+
{% endfor %}
66+
)";
67+
68+
Template tpl;
69+
ASSERT_TRUE(tpl.Load(source));
70+
71+
ValuesMap params = {
72+
{"its", Reflect(std::vector<int64_t>{0, 1, 2} ) }
73+
};
74+
75+
std::string result = tpl.RenderAsString(params);
76+
std::cout << result << std::endl;
77+
std::string expectedResult = R"(
78+
a[0] = image[0];
79+
a[1] = image[1];
80+
a[2] = image[2];
81+
)";
82+
EXPECT_EQ(expectedResult, result);
83+
}
84+
5985
TEST(ForLoopTest, LoopVariable)
6086
{
6187
std::string source = R"(
@@ -146,3 +172,5 @@ b[1] = image[1];
146172

147173
EXPECT_EQ(expectedResult, result);
148174
}
175+
176+

0 commit comments

Comments
 (0)