Skip to content

Commit 23b830a

Browse files
committed
Add reflection functionality and 'startsWith' tester
1 parent ae94349 commit 23b830a

File tree

7 files changed

+303
-91
lines changed

7 files changed

+303
-91
lines changed
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
#ifndef JINJA2_REFLECTED_VALUE_H
2+
#define JINJA2_REFLECTED_VALUE_H
3+
4+
#include "value.h"
5+
6+
namespace jinja2
7+
{
8+
9+
#if 0
10+
template<typename Derived>
11+
class ReflectedMapImplBase : public ReflectedMap::ItemAccessor
12+
{
13+
public:
14+
bool HasValue(const std::string& name) const override
15+
{
16+
return Derived::GetAccessors().count(name) != 0;
17+
}
18+
Value GetValue(const std::string& name) const override
19+
{
20+
auto& accessors = Derived::GetAccessors();
21+
auto p = accessors.find(name);
22+
if (p == accessors.end())
23+
throw std::runtime_error("Invalid field access");
24+
25+
return static_cast<const Derived*>(this)->GetField(p->second);
26+
}
27+
};
28+
29+
template<typename T>
30+
class ReflectedMapImpl : public ReflectedMapImplBase<ReflectedMapImpl<T>>
31+
{
32+
public:
33+
ReflectedMapImpl(T val) : m_value(val) {}
34+
using FieldAccessor = std::function<Value (const T& value)>;
35+
36+
static auto& GetAccessors();
37+
static std::string ToString(const T& value);
38+
template<typename Fn>
39+
Value GetField(Fn&& accessor) const
40+
{
41+
return accessor(m_value);
42+
}
43+
44+
std::string ToString() const override
45+
{
46+
return ToString(m_value);
47+
}
48+
private:
49+
T m_value;
50+
};
51+
#endif
52+
53+
namespace detail
54+
{
55+
template<typename T, typename Tag = void>
56+
struct Reflector;
57+
58+
struct ContainerReflector
59+
{
60+
template<typename T>
61+
struct ValueItemAccessor : ListItemAccessor
62+
{
63+
T m_value;
64+
65+
explicit ValueItemAccessor(T&& cont) noexcept
66+
: m_value(std::move(cont))
67+
{
68+
}
69+
70+
size_t GetSize() const override
71+
{
72+
return m_value.size();
73+
}
74+
Value GetValueByIndex(int64_t idx) const override
75+
{
76+
return Reflect(m_value.begin() + idx);
77+
}
78+
};
79+
80+
template<typename T>
81+
struct PtrItemAccessor : ListItemAccessor
82+
{
83+
const T* m_value;
84+
85+
PtrItemAccessor(const T* ptr)
86+
: m_value(ptr)
87+
{
88+
}
89+
size_t GetSize() const override
90+
{
91+
return m_value->size();
92+
}
93+
Value GetValueByIndex(int64_t idx) const override
94+
{
95+
auto p = m_value->begin();
96+
std::advance(p, idx);
97+
return Reflect(*p);
98+
}
99+
};
100+
101+
template<typename T>
102+
static Value CreateFromPtr(T&& cont)
103+
{
104+
return GenericList([accessor = ValueItemAccessor<T>(std::move(cont))]() {return &accessor;});
105+
}
106+
107+
template<typename T>
108+
static Value CreateFromPtr(const T* cont)
109+
{
110+
return GenericList([accessor = PtrItemAccessor<T>(cont)]() {return &accessor;});
111+
}
112+
};
113+
114+
template<typename T>
115+
struct Reflector<std::set<T>>
116+
{
117+
static auto Create(std::set<T> val)
118+
{
119+
return ContainerReflector::Create(std::move(val));
120+
}
121+
static auto CreateFromPtr(const std::set<T>* val)
122+
{
123+
return ContainerReflector::CreateFromPtr(val);
124+
}
125+
};
126+
127+
template<typename T>
128+
struct Reflector<std::vector<T>>
129+
{
130+
static auto Create(std::vector<T> val)
131+
{
132+
return ContainerReflector::Create(std::move(val));
133+
}
134+
static auto CreateFromPtr(const std::vector<T>* val)
135+
{
136+
return ContainerReflector::CreateFromPtr(val);
137+
}
138+
};
139+
140+
template<typename T>
141+
struct Reflector<const T&>
142+
{
143+
static auto Create(const T& val)
144+
{
145+
return Reflector<T>::CreateFromPtr(&val);
146+
}
147+
};
148+
149+
template<typename T>
150+
struct Reflector<const T*>
151+
{
152+
static auto Create(const T* val)
153+
{
154+
return Reflector<T>::CreateFromPtr(val);
155+
}
156+
};
157+
158+
template<typename T>
159+
struct Reflector<T*>
160+
{
161+
static auto Create(T* val)
162+
{
163+
return Reflector<T>::CreateFromPtr(val);
164+
}
165+
};
166+
167+
template<>
168+
struct Reflector<std::string>
169+
{
170+
static auto Create(std::string str)
171+
{
172+
return Value(std::move(str));
173+
}
174+
static auto CreateFromPtr(const std::string* str)
175+
{
176+
return Value(*str);
177+
}
178+
};
179+
} // detail
180+
181+
template<typename T>
182+
Value Reflect(T&& val)
183+
{
184+
return detail::Reflector<T>::Create(std::forward<T>(val));
185+
// return Value(ReflectedMap([accessor = ReflectedMapImpl<T>(std::forward<T>(val))]() -> const ReflectedMap::ItemAccessor* {return &accessor;}));
186+
}
187+
188+
} // jinja2
189+
190+
#endif // JINJA2_REFLECTED_VALUE_H

include/jinja2cpp/value.h

Lines changed: 39 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,27 @@ namespace jinja2
1414
struct EmptyValue {};
1515
class Value;
1616

17-
class ReflectedMap
17+
struct ListItemAccessor
1818
{
19-
public:
20-
struct ItemAccessor
21-
{
22-
virtual ~ItemAccessor() {}
23-
virtual bool HasValue(const std::string& name) const = 0;
24-
virtual Value GetValue(const std::string& name) const = 0;
25-
virtual std::string ToString() const = 0;
26-
};
19+
virtual ~ListItemAccessor() {}
2720

28-
ReflectedMap() = default;
29-
ReflectedMap(std::function<const ItemAccessor* ()> accessor)
21+
virtual size_t GetSize() const = 0;
22+
virtual Value GetValueByIndex(int64_t idx) const = 0;
23+
};
24+
25+
struct MapItemAccessor : public ListItemAccessor
26+
{
27+
virtual ~MapItemAccessor() {}
28+
virtual bool HasValue(const std::string& name) const = 0;
29+
virtual Value GetValueByName(const std::string& name) const = 0;
30+
virtual std::vector<std::string> GetKeys() const = 0;
31+
};
32+
33+
class GenericMap
34+
{
35+
public:
36+
GenericMap() = default;
37+
GenericMap(std::function<const MapItemAccessor* ()> accessor)
3038
: m_accessor(std::move(accessor))
3139
{
3240
}
@@ -36,28 +44,21 @@ class ReflectedMap
3644
return m_accessor()->HasValue(name);
3745
}
3846

39-
Value GetValue(const std::string& name) const;
40-
41-
std::string ToString() const
47+
Value GetValueByName(const std::string& name) const;
48+
size_t GetSize() const
4249
{
43-
return m_accessor()->ToString();
50+
return m_accessor()->GetSize();
4451
}
52+
Value GetValueByIndex(int64_t index) const;
4553

46-
std::function<const ItemAccessor* ()> m_accessor;
54+
std::function<const MapItemAccessor* ()> m_accessor;
4755
};
4856

49-
class ReflectedList
57+
class GenericList
5058
{
5159
public:
52-
struct ItemAccessor
53-
{
54-
virtual ~ItemAccessor() {}
55-
virtual size_t GetSize() const = 0;
56-
virtual Value GetValue(size_t idx) const = 0;
57-
};
58-
59-
ReflectedList() = default;
60-
ReflectedList(std::function<const ItemAccessor* ()> accessor)
60+
GenericList() = default;
61+
GenericList(std::function<const ListItemAccessor* ()> accessor)
6162
: m_accessor(std::move(accessor))
6263
{
6364
}
@@ -67,15 +68,14 @@ class ReflectedList
6768
return m_accessor()->GetSize();
6869
}
6970

70-
Value GetValue(int idx) const;
71+
Value GetValueByIndex(int64_t idx) const;
7172

72-
std::function<const ItemAccessor* ()> m_accessor;
73+
std::function<const ListItemAccessor* ()> m_accessor;
7374
};
7475

7576
using ValuesList = std::vector<Value>;
7677
using ValuesMap = std::unordered_map<std::string, Value>;
77-
class ReflectedMap;
78-
using ValueData = boost::variant<EmptyValue, bool, std::string, std::wstring, int64_t, double, boost::recursive_wrapper<ValuesList>, boost::recursive_wrapper<ValuesMap>, ReflectedMap>;
78+
using ValueData = boost::variant<EmptyValue, bool, std::string, std::wstring, int64_t, double, boost::recursive_wrapper<ValuesList>, boost::recursive_wrapper<ValuesMap>, GenericList, GenericMap>;
7979

8080
class Value {
8181
public:
@@ -116,7 +116,7 @@ class Value {
116116

117117
bool isList() const
118118
{
119-
return boost::get<ValuesList>(&m_data) != nullptr;
119+
return boost::get<ValuesList>(&m_data) != nullptr || boost::get<GenericList>(&m_data) != nullptr;
120120
}
121121
auto& asList()
122122
{
@@ -128,7 +128,7 @@ class Value {
128128
}
129129
bool isMap() const
130130
{
131-
return boost::get<ValuesMap>(&m_data) != nullptr || boost::get<ReflectedMap>(&m_data) != nullptr;
131+
return boost::get<ValuesMap>(&m_data) != nullptr || boost::get<GenericMap>(&m_data) != nullptr;
132132
}
133133
auto& asMap()
134134
{
@@ -149,58 +149,19 @@ class Value {
149149
ValueData m_data;
150150
};
151151

152-
inline Value ReflectedMap::GetValue(const std::string& name) const
152+
inline Value GenericMap::GetValueByName(const std::string& name) const
153153
{
154-
return m_accessor()->GetValue(name);
154+
return m_accessor()->GetValueByName(name);
155155
}
156156

157-
158-
template<typename Derived>
159-
class ReflectedMapImplBase : public ReflectedMap::ItemAccessor
160-
{
161-
public:
162-
bool HasValue(const std::string& name) const override
163-
{
164-
return Derived::GetAccessors().count(name) != 0;
165-
}
166-
Value GetValue(const std::string& name) const override
167-
{
168-
auto& accessors = Derived::GetAccessors();
169-
auto p = accessors.find(name);
170-
if (p == accessors.end())
171-
throw std::runtime_error("Invalid field access");
172-
173-
return static_cast<const Derived*>(this)->GetField(p->second);
174-
}
175-
};
176-
177-
template<typename T>
178-
class ReflectedMapImpl : public ReflectedMapImplBase<ReflectedMapImpl<T>>
157+
inline Value GenericMap::GetValueByIndex(int64_t index) const
179158
{
180-
public:
181-
ReflectedMapImpl(T val) : m_value(val) {}
182-
using FieldAccessor = std::function<Value (const T& value)>;
183-
184-
static auto& GetAccessors();
185-
static std::string ToString(const T& value);
186-
template<typename Fn>
187-
Value GetField(Fn&& accessor) const
188-
{
189-
return accessor(m_value);
190-
}
191-
192-
std::string ToString() const override
193-
{
194-
return ToString(m_value);
195-
}
196-
private:
197-
T m_value;
198-
};
159+
return m_accessor()->GetValueByIndex(index);
160+
}
199161

200-
template<typename T>
201-
Value AsReflectedMap(T&& val)
162+
inline Value GenericList::GetValueByIndex(int64_t index) const
202163
{
203-
return Value(ReflectedMap([accessor = ReflectedMapImpl<T>(std::forward<T>(val))]() -> const ReflectedMap::ItemAccessor* {return &accessor;}));
164+
return m_accessor()->GetValueByIndex(index);
204165
}
205166

206167
} // jinja2

src/expression_evaluator.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ std::unordered_map<std::string, ExpressionFilter::FilterFactoryFn> ExpressionFil
1414

1515
std::unordered_map<std::string, IsExpression::TesterFactoryFn> IsExpression::s_testers = {
1616
{"defined", &TesterFactory<testers::Defined>::Create},
17+
{"startsWith", &TesterFactory<testers::StartsWith>::Create},
1718
};
1819

1920
Value FullExpressionEvaluator::Evaluate(RenderContext& values)

src/testers.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,18 @@ bool Defined::Test(const Value& baseVal, RenderContext& context)
1111
return boost::get<EmptyValue>(&baseVal.data()) == nullptr;
1212
}
1313

14+
StartsWith::StartsWith(TesterParams params)
15+
{
16+
helpers::FindParam(params, "param0", "param0", m_stringEval);
17+
}
18+
19+
bool StartsWith::Test(const Value& baseVal, RenderContext& context)
20+
{
21+
Value val = m_stringEval->Evaluate(context);
22+
std::string baseStr = baseVal.asString();
23+
std::string str = val.asString();
24+
return baseStr.find(str) == 0;
25+
}
26+
1427
}
1528
}

0 commit comments

Comments
 (0)