c++ object support

This commit is contained in:
Daniel Sipka 2015-04-21 15:04:11 +02:00
parent 812b4bdb41
commit 8f7210f95d
19 changed files with 173 additions and 87 deletions

View File

@ -12,8 +12,9 @@ namespace mstch {
template<class N> template<class N>
class object_t { class object_t {
public: public:
N at(const std::string &name) const { const N& at(const std::string& name) const {
return (methods.at(name))(); cache[name] = (methods.at(name))();
return cache[name];
} }
bool has(const std::string name) const { bool has(const std::string name) const {
@ -21,14 +22,13 @@ namespace mstch {
} }
protected: protected:
template<class S> template<class S>
void register_method(std::string name, S* sub, N(S::*method)()) { void register_methods(S* sub, std::map<std::string,N(S::*)()> methods) {
this->methods.insert({name, std::bind(method, sub)}); for(auto& item: methods)
} this->methods.insert({item.first, std::bind(item.second, sub)});
void register_method(std::string name, const N& node) {
this->methods.insert({name, [node](){return node;}});
} }
private: private:
std::map<std::string, std::function<N()>> methods; std::map<std::string, std::function<N()>> methods;
mutable std::map<std::string, N> cache;
}; };
} }

View File

@ -10,6 +10,7 @@ set(SRC
state/in_section.cpp state/in_section.cpp
state/outside_section.cpp state/outside_section.cpp
visitor/get_token.cpp visitor/get_token.cpp
visitor/has_token.cpp
visitor/is_node_empty.cpp visitor/is_node_empty.cpp
visitor/render_node.cpp visitor/render_node.cpp
visitor/render_section.cpp visitor/render_section.cpp

View File

@ -2,6 +2,7 @@
#include "utils.hpp" #include "utils.hpp"
#include "state/outside_section.hpp" #include "state/outside_section.hpp"
#include "visitor/get_token.hpp" #include "visitor/get_token.hpp"
#include "visitor/has_token.hpp"
using namespace mstch; using namespace mstch;
@ -34,7 +35,7 @@ render_context::render_context(
new state::outside_section)); new state::outside_section));
} }
mstch::node render_context::find_node( const mstch::node& render_context::find_node(
const std::string& token, const std::string& token,
const std::deque<node>& current_nodes) const std::deque<node>& current_nodes)
{ {
@ -43,14 +44,13 @@ mstch::node render_context::find_node(
token.substr(token.rfind('.') + 1), token.substr(token.rfind('.') + 1),
{find_node(token.substr(0, token.rfind('.')), current_nodes)}); {find_node(token.substr(0, token.rfind('.')), current_nodes)});
else else
for (auto& node: current_nodes) { for (auto& n: current_nodes)
auto ret = boost::apply_visitor(visitor::get_token(token, node), node); if (boost::apply_visitor(visitor::has_token(token), n))
if(ret.first) return ret.second; return boost::apply_visitor(visitor::get_token(token, n), n);
}
return null_node; return null_node;
} }
mstch::node render_context::get_node(const std::string& token) { const mstch::node& render_context::get_node(const std::string& token) {
return find_node(token, nodes); return find_node(token, nodes);
} }

View File

@ -24,7 +24,7 @@ namespace mstch {
render_context( render_context(
const mstch::node& node, const mstch::node& node,
const std::map<std::string,template_type>& partials); const std::map<std::string,template_type>& partials);
mstch::node get_node(const std::string& token); const mstch::node& get_node(const std::string& token);
std::string render(const template_type& templt); std::string render(const template_type& templt);
std::string render_partial(const std::string& partial_name); std::string render_partial(const std::string& partial_name);
template<class T, class... Args> template<class T, class... Args>
@ -34,7 +34,7 @@ namespace mstch {
} }
private: private:
static const mstch::node null_node; static const mstch::node null_node;
mstch::node find_node( const mstch::node& find_node(
const std::string& token, const std::string& token,
const std::deque<node>& current_nodes); const std::deque<node>& current_nodes);
const std::map<std::string,template_type>& partials; const std::map<std::string,template_type>& partials;

View File

@ -18,7 +18,7 @@ std::string state::in_inverted_section::render(
case token::type::section_close: case token::type::section_close:
if(token.content() == section_name && skipped_openings == 0) { if(token.content() == section_name && skipped_openings == 0) {
std::string out; std::string out;
auto section_node = ctx.get_node(section_name); auto& section_node = ctx.get_node(section_name);
if(boost::apply_visitor(visitor::is_node_empty(), section_node)) if(boost::apply_visitor(visitor::is_node_empty(), section_node))
out = render_context::push(ctx).render(section); out = render_context::push(ctx).render(section);
ctx.set_state<outside_section>(); ctx.set_state<outside_section>();

View File

@ -14,7 +14,7 @@ std::string state::in_section::render(render_context& ctx, const token& token) {
switch(token.token_type()) { switch(token.token_type()) {
case token::type::section_close: case token::type::section_close:
if(token.content() == section_name && skipped_openings == 0) { if(token.content() == section_name && skipped_openings == 0) {
auto section_node = ctx.get_node(section_name); auto& section_node = ctx.get_node(section_name);
std::string out; std::string out;
if (!boost::apply_visitor(visitor::is_node_empty(), section_node)) if (!boost::apply_visitor(visitor::is_node_empty(), section_node))
out = boost::apply_visitor( out = boost::apply_visitor(

View File

@ -18,12 +18,11 @@ std::string state::outside_section::render(
ctx.set_state<in_inverted_section>(token.content()); ctx.set_state<in_inverted_section>(token.content());
break; break;
case token::type::variable: case token::type::variable:
case token::type::unescaped_variable: { return boost::apply_visitor(visitor::render_node(flag::escape_html),
auto visitor = visitor::render_node((token.token_type() == ctx.get_node(token.content()));
token::type::variable)?flag::escape_html:flag::none); case token::type::unescaped_variable:
auto node = ctx.get_node(token.content()); return boost::apply_visitor(visitor::render_node(flag::none),
return boost::apply_visitor(visitor, node); ctx.get_node(token.content()));
}
case token::type::comment: break; case token::type::comment: break;
case token::type::text: case token::type::text:
return token.content(); return token.content();

View File

@ -8,36 +8,31 @@ get_token::get_token(const std::string& token, const mstch::node& node):
{ {
} }
std::pair<bool,node> get_token::operator()(const boost::blank& blank) const { const mstch::node& get_token::operator()(const boost::blank& blank) const {
return {token == ".", node}; return node;
} }
std::pair<bool,node> get_token::operator()(const int& i) const { const mstch::node& get_token::operator()(const int& i) const {
return {token == ".", node}; return node;
} }
std::pair<bool,node> get_token::operator()(const bool& b) const { const mstch::node& get_token::operator()(const bool& b) const {
return {token == ".", node}; return node;
} }
std::pair<bool,node> get_token::operator()(const std::string& str) const { const mstch::node& get_token::operator()(const std::string& str) const {
return {token == ".", node}; return node;
} }
std::pair<bool,node> get_token::operator()(const array& arr) const { const mstch::node& get_token::operator()(const array& arr) const {
return {token == ".", node}; return node;
} }
std::pair<bool,node> get_token::operator()(const map& map) const { const mstch::node& get_token::operator()(const map& map) const {
if(map.count(token) == 1) return map.at(token);
return {true, map.at(token)};
else
return {false, node};
} }
std::pair<bool,node> get_token::operator()(const std::shared_ptr<object>& obj) const { const mstch::node& get_token::operator()(const std::shared_ptr<object>& obj) const {
if (obj->has(token)) return obj->at(token);
return {true, obj->at(token)};
else
return {false, node};
} }

View File

@ -6,19 +6,19 @@
namespace mstch { namespace mstch {
namespace visitor { namespace visitor {
class get_token: public boost::static_visitor<std::pair<bool,mstch::node>> { class get_token: public boost::static_visitor<const mstch::node&> {
public: public:
get_token(const std::string& token, const mstch::node& node); get_token(const std::string& token, const mstch::node& node);
std::pair<bool,mstch::node> operator()(const boost::blank& blank) const; const mstch::node& operator()(const boost::blank& blank) const;
std::pair<bool,mstch::node> operator()(const int& i) const; const mstch::node& operator()(const int& i) const;
std::pair<bool,mstch::node> operator()(const bool& b) const; const mstch::node& operator()(const bool& b) const;
std::pair<bool,mstch::node> operator()(const std::string& str) const; const mstch::node& operator()(const std::string& str) const;
std::pair<bool,mstch::node> operator()(const array& arr) const; const mstch::node& operator()(const array& arr) const;
std::pair<bool,mstch::node> operator()(const map& map) const; const mstch::node& operator()(const map& map) const;
std::pair<bool,mstch::node> operator()(const std::shared_ptr<object>& obj) const; const mstch::node& operator()(const std::shared_ptr<object>& obj) const;
private: private:
const std::string& token; const std::string& token;
mstch::node node; const mstch::node& node;
}; };
} }
} }

35
src/visitor/has_token.cpp Normal file
View File

@ -0,0 +1,35 @@
#include "has_token.hpp"
using namespace mstch;
using namespace mstch::visitor;
has_token::has_token(const std::string& token): token(token) {
}
bool has_token::operator()(const boost::blank& blank) const {
return token == ".";
}
bool has_token::operator()(const int& i) const {
return token == ".";
}
bool has_token::operator()(const bool& b) const {
return token == ".";
}
bool has_token::operator()(const std::string& str) const {
return token == ".";
}
bool has_token::operator()(const array& arr) const {
return token == ".";
}
bool has_token::operator()(const map& map) const {
return map.count(token) == 1;
}
bool has_token::operator()(const std::shared_ptr<object>& obj) const {
return obj->has(token);
}

23
src/visitor/has_token.hpp Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include <boost/variant/static_visitor.hpp>
#include <boost/blank.hpp>
#include "mstch/mstch.hpp"
namespace mstch {
namespace visitor {
class has_token: public boost::static_visitor<bool> {
public:
has_token(const std::string& token);
bool operator()(const boost::blank& blank) const;
bool operator()(const int& i) const;
bool operator()(const bool& b) const;
bool operator()(const std::string& str) const;
bool operator()(const array& arr) const;
bool operator()(const map& map) const;
bool operator()(const std::shared_ptr<object>& obj) const;
private:
const std::string& token;
};
}
}

View File

@ -1,7 +1,7 @@
class comments: public mstch::object { class comments: public mstch::object {
public: public:
comments() { comments() {
register_method("title", this, &comments::title); register_methods(this, {{"title", &comments::title}});
} }
mstch::node title() { mstch::node title() {

View File

@ -1,48 +1,68 @@
class complex_item: public mstch::object { class complex_item: public mstch::object {
private: private:
const std::string name; std::string m_name;
const bool current; bool m_current;
const std::string url; std::string m_url;
public: public:
complex_item(const std::string& name, bool current, const std::string& url): complex_item(const std::string& name, bool current, const std::string& url):
name{name}, current{current}, url{url} m_name{name}, m_current{current}, m_url{url}
{ {
register_method("name", {name}); register_methods(this, {
register_method("current", {current}); {"name", &complex_item::name}, {"current", &complex_item::current},
register_method("url", {url}); {"url", &complex_item::url}, {"link", &complex_item::link}
register_method("link", this, &complex_item::link); });
}
mstch::node current() {
return m_current;
}
mstch::node url() {
return m_url;
}
mstch::node name() {
return m_name;
} }
mstch::node link() { mstch::node link() {
return !current; return !m_current;
} }
}; };
class complex: public mstch::object { class complex: public mstch::object {
private: private:
const std::string header; std::string m_header;
const mstch::array item; mstch::array m_item;
public: public:
complex(): complex():
header{"Colors"}, m_header{"Colors"},
item{ m_item{
std::make_shared<complex_item>("red", true, "#Red"), std::make_shared<complex_item>("red", true, "#Red"),
std::make_shared<complex_item>("green", false, "#Green"), std::make_shared<complex_item>("green", false, "#Green"),
std::make_shared<complex_item>("blue", false, "#Blue") std::make_shared<complex_item>("blue", false, "#Blue")
} }
{ {
register_method("header", {header}); register_methods(this, {
register_method("item", {item}); {"header", &complex::header}, {"item", &complex::item},
register_method("list", this, &complex::list); {"list", &complex::list}, {"empty", &complex::empty}
register_method("empty", this, &complex::empty); });
}
mstch::node header() {
return m_header;
}
mstch::node item() {
return m_item;
} }
mstch::node list() { mstch::node list() {
return item.size() != 0; return m_item.size() != 0;
} }
mstch::node empty() { mstch::node empty() {
return item.size() == 0; return m_item.size() == 0;
} }
}; };

View File

@ -1,18 +1,27 @@
class dot_notation_price: public mstch::object { class dot_notation_price: public mstch::object {
private: private:
const int value; int m_value;
const mstch::map currency; mstch::map m_currency;
public: public:
dot_notation_price(): dot_notation_price():
value{200}, currency{{"symbol", std::string{"$"}}, {"name", std::string{"USD"}}} m_value{200}, m_currency{{"symbol", std::string{"$"}}, {"name", std::string{"USD"}}}
{ {
register_method("value", {value}); register_methods(this, {
register_method("vat", this, &dot_notation_price::vat); {"value", &dot_notation_price::value},
register_method("currency", {currency}); {"vat", &dot_notation_price::vat},
{"currency", &dot_notation_price::currency}});
}
mstch::node value() {
return m_value;
} }
mstch::node vat() { mstch::node vat() {
return static_cast<int>(value * 0.2); return static_cast<int>(m_value * 0.2);
}
mstch::node currency() {
return m_currency;
} }
}; };

View File

@ -1,8 +1,9 @@
class escaped: public mstch::object { class escaped: public mstch::object {
public: public:
escaped() { escaped() {
register_method("title", this, &escaped::title); register_methods(this, {
register_method("entities", this, &escaped::entities); {"title", &escaped::title}, {"entities", &escaped::entities}
});
} }
mstch::node title() { mstch::node title() {

View File

@ -1,8 +1,10 @@
class nested_higher_order_sections: public mstch::object { class nested_higher_order_sections: public mstch::object {
public: public:
nested_higher_order_sections() { nested_higher_order_sections() {
register_method("bold", this, &nested_higher_order_sections::bold); register_methods(this, {
register_method("person", this, &nested_higher_order_sections::person); {"bold", &nested_higher_order_sections::bold},
{"person", &nested_higher_order_sections::person}
});
} }
mstch::node bold() { mstch::node bold() {

View File

@ -1,8 +1,9 @@
class partial_template: public mstch::object { class partial_template: public mstch::object {
public: public:
partial_template() { partial_template() {
register_method("title", this, &partial_template::title); register_methods(this, {
register_method("again", this, &partial_template::again); {"title", &partial_template::title},
{"again", &partial_template::again}});
} }
mstch::node title() { mstch::node title() {

View File

@ -1,7 +1,7 @@
class section_functions_in_partials: public mstch::object { class section_functions_in_partials: public mstch::object {
public: public:
section_functions_in_partials() { section_functions_in_partials() {
register_method("bold", this, &section_functions_in_partials::bold); register_methods(this, {{"bold", &section_functions_in_partials::bold}});
} }
mstch::node bold() { mstch::node bold() {

View File

@ -1,7 +1,7 @@
class unescaped: public mstch::object { class unescaped: public mstch::object {
public: public:
unescaped() { unescaped() {
register_method("title", this, &unescaped::title); register_methods(this, {{"title", &unescaped::title}});
} }
mstch::node title() { mstch::node title() {