diff --git a/include/mstch/mstch.hpp b/include/mstch/mstch.hpp index e8aa213..6142b43 100644 --- a/include/mstch/mstch.hpp +++ b/include/mstch/mstch.hpp @@ -12,8 +12,9 @@ namespace mstch { template class object_t { public: - N at(const std::string &name) const { - return (methods.at(name))(); + const N& at(const std::string& name) const { + cache[name] = (methods.at(name))(); + return cache[name]; } bool has(const std::string name) const { @@ -21,14 +22,13 @@ namespace mstch { } protected: template - void register_method(std::string name, S* sub, N(S::*method)()) { - this->methods.insert({name, std::bind(method, sub)}); - } - void register_method(std::string name, const N& node) { - this->methods.insert({name, [node](){return node;}}); + void register_methods(S* sub, std::map methods) { + for(auto& item: methods) + this->methods.insert({item.first, std::bind(item.second, sub)}); } private: std::map> methods; + mutable std::map cache; }; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aa1db23..020409a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,6 +10,7 @@ set(SRC state/in_section.cpp state/outside_section.cpp visitor/get_token.cpp + visitor/has_token.cpp visitor/is_node_empty.cpp visitor/render_node.cpp visitor/render_section.cpp diff --git a/src/render_context.cpp b/src/render_context.cpp index 671cfcb..838c8bc 100644 --- a/src/render_context.cpp +++ b/src/render_context.cpp @@ -2,6 +2,7 @@ #include "utils.hpp" #include "state/outside_section.hpp" #include "visitor/get_token.hpp" +#include "visitor/has_token.hpp" using namespace mstch; @@ -34,7 +35,7 @@ render_context::render_context( new state::outside_section)); } -mstch::node render_context::find_node( +const mstch::node& render_context::find_node( const std::string& token, const std::deque& current_nodes) { @@ -43,14 +44,13 @@ mstch::node render_context::find_node( token.substr(token.rfind('.') + 1), {find_node(token.substr(0, token.rfind('.')), current_nodes)}); else - for (auto& node: current_nodes) { - auto ret = boost::apply_visitor(visitor::get_token(token, node), node); - if(ret.first) return ret.second; - } + for (auto& n: current_nodes) + if (boost::apply_visitor(visitor::has_token(token), n)) + return boost::apply_visitor(visitor::get_token(token, n), n); 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); } diff --git a/src/render_context.hpp b/src/render_context.hpp index 143ca2b..720c313 100644 --- a/src/render_context.hpp +++ b/src/render_context.hpp @@ -24,7 +24,7 @@ namespace mstch { render_context( const mstch::node& node, const std::map& 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_partial(const std::string& partial_name); template @@ -34,7 +34,7 @@ namespace mstch { } private: static const mstch::node null_node; - mstch::node find_node( + const mstch::node& find_node( const std::string& token, const std::deque& current_nodes); const std::map& partials; diff --git a/src/state/in_inverted_section.cpp b/src/state/in_inverted_section.cpp index c120da3..b10b376 100644 --- a/src/state/in_inverted_section.cpp +++ b/src/state/in_inverted_section.cpp @@ -18,7 +18,7 @@ std::string state::in_inverted_section::render( case token::type::section_close: if(token.content() == section_name && skipped_openings == 0) { 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)) out = render_context::push(ctx).render(section); ctx.set_state(); diff --git a/src/state/in_section.cpp b/src/state/in_section.cpp index 3c4a3f1..b3eb77e 100644 --- a/src/state/in_section.cpp +++ b/src/state/in_section.cpp @@ -14,7 +14,7 @@ std::string state::in_section::render(render_context& ctx, const token& token) { switch(token.token_type()) { case token::type::section_close: 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; if (!boost::apply_visitor(visitor::is_node_empty(), section_node)) out = boost::apply_visitor( diff --git a/src/state/outside_section.cpp b/src/state/outside_section.cpp index 7ecf4c0..f792c84 100644 --- a/src/state/outside_section.cpp +++ b/src/state/outside_section.cpp @@ -18,12 +18,11 @@ std::string state::outside_section::render( ctx.set_state(token.content()); break; case token::type::variable: - case token::type::unescaped_variable: { - auto visitor = visitor::render_node((token.token_type() == - token::type::variable)?flag::escape_html:flag::none); - auto node = ctx.get_node(token.content()); - return boost::apply_visitor(visitor, node); - } + return boost::apply_visitor(visitor::render_node(flag::escape_html), + ctx.get_node(token.content())); + case token::type::unescaped_variable: + return boost::apply_visitor(visitor::render_node(flag::none), + ctx.get_node(token.content())); case token::type::comment: break; case token::type::text: return token.content(); diff --git a/src/visitor/get_token.cpp b/src/visitor/get_token.cpp index 3c1dfce..efc44d6 100644 --- a/src/visitor/get_token.cpp +++ b/src/visitor/get_token.cpp @@ -8,36 +8,31 @@ get_token::get_token(const std::string& token, const mstch::node& node): { } -std::pair get_token::operator()(const boost::blank& blank) const { - return {token == ".", node}; +const mstch::node& get_token::operator()(const boost::blank& blank) const { + return node; } -std::pair get_token::operator()(const int& i) const { - return {token == ".", node}; +const mstch::node& get_token::operator()(const int& i) const { + return node; } -std::pair get_token::operator()(const bool& b) const { - return {token == ".", node}; +const mstch::node& get_token::operator()(const bool& b) const { + return node; } -std::pair get_token::operator()(const std::string& str) const { - return {token == ".", node}; +const mstch::node& get_token::operator()(const std::string& str) const { + return node; } -std::pair get_token::operator()(const array& arr) const { - return {token == ".", node}; +const mstch::node& get_token::operator()(const array& arr) const { + return node; } -std::pair get_token::operator()(const map& map) const { - if(map.count(token) == 1) - return {true, map.at(token)}; - else - return {false, node}; +const mstch::node& get_token::operator()(const map& map) const { + return map.at(token); } -std::pair get_token::operator()(const std::shared_ptr& obj) const { - if (obj->has(token)) - return {true, obj->at(token)}; - else - return {false, node}; +const mstch::node& get_token::operator()(const std::shared_ptr& obj) const { + return obj->at(token); } + diff --git a/src/visitor/get_token.hpp b/src/visitor/get_token.hpp index cf43125..b1b0a8a 100644 --- a/src/visitor/get_token.hpp +++ b/src/visitor/get_token.hpp @@ -6,19 +6,19 @@ namespace mstch { namespace visitor { - class get_token: public boost::static_visitor> { + class get_token: public boost::static_visitor { public: get_token(const std::string& token, const mstch::node& node); - std::pair operator()(const boost::blank& blank) const; - std::pair operator()(const int& i) const; - std::pair operator()(const bool& b) const; - std::pair operator()(const std::string& str) const; - std::pair operator()(const array& arr) const; - std::pair operator()(const map& map) const; - std::pair operator()(const std::shared_ptr& obj) const; + const mstch::node& operator()(const boost::blank& blank) const; + const mstch::node& operator()(const int& i) const; + const mstch::node& operator()(const bool& b) const; + const mstch::node& operator()(const std::string& str) const; + const mstch::node& operator()(const array& arr) const; + const mstch::node& operator()(const map& map) const; + const mstch::node& operator()(const std::shared_ptr& obj) const; private: const std::string& token; - mstch::node node; + const mstch::node& node; }; } } diff --git a/src/visitor/has_token.cpp b/src/visitor/has_token.cpp new file mode 100644 index 0000000..5ff4f3f --- /dev/null +++ b/src/visitor/has_token.cpp @@ -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& obj) const { + return obj->has(token); +} diff --git a/src/visitor/has_token.hpp b/src/visitor/has_token.hpp new file mode 100644 index 0000000..fd333b3 --- /dev/null +++ b/src/visitor/has_token.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include "mstch/mstch.hpp" + +namespace mstch { + namespace visitor { + class has_token: public boost::static_visitor { + 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& obj) const; + private: + const std::string& token; + }; + } +} diff --git a/test/data/comments.hpp b/test/data/comments.hpp index 4f938fd..a3d93b7 100644 --- a/test/data/comments.hpp +++ b/test/data/comments.hpp @@ -1,7 +1,7 @@ class comments: public mstch::object { public: comments() { - register_method("title", this, &comments::title); + register_methods(this, {{"title", &comments::title}}); } mstch::node title() { diff --git a/test/data/complex.hpp b/test/data/complex.hpp index 6cbbeb7..481580d 100644 --- a/test/data/complex.hpp +++ b/test/data/complex.hpp @@ -1,48 +1,68 @@ class complex_item: public mstch::object { private: - const std::string name; - const bool current; - const std::string url; + std::string m_name; + bool m_current; + std::string m_url; public: 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_method("current", {current}); - register_method("url", {url}); - register_method("link", this, &complex_item::link); + register_methods(this, { + {"name", &complex_item::name}, {"current", &complex_item::current}, + {"url", &complex_item::url}, {"link", &complex_item::link} + }); + } + + mstch::node current() { + return m_current; + } + + mstch::node url() { + return m_url; + } + + mstch::node name() { + return m_name; } mstch::node link() { - return !current; + return !m_current; } }; class complex: public mstch::object { private: - const std::string header; - const mstch::array item; + std::string m_header; + mstch::array m_item; public: complex(): - header{"Colors"}, - item{ + m_header{"Colors"}, + m_item{ std::make_shared("red", true, "#Red"), std::make_shared("green", false, "#Green"), std::make_shared("blue", false, "#Blue") } { - register_method("header", {header}); - register_method("item", {item}); - register_method("list", this, &complex::list); - register_method("empty", this, &complex::empty); + register_methods(this, { + {"header", &complex::header}, {"item", &complex::item}, + {"list", &complex::list}, {"empty", &complex::empty} + }); + } + + mstch::node header() { + return m_header; + } + + mstch::node item() { + return m_item; } mstch::node list() { - return item.size() != 0; + return m_item.size() != 0; } mstch::node empty() { - return item.size() == 0; + return m_item.size() == 0; } }; diff --git a/test/data/dot_notation.hpp b/test/data/dot_notation.hpp index 75c8287..d21ee50 100644 --- a/test/data/dot_notation.hpp +++ b/test/data/dot_notation.hpp @@ -1,18 +1,27 @@ class dot_notation_price: public mstch::object { private: - const int value; - const mstch::map currency; + int m_value; + mstch::map m_currency; public: 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_method("vat", this, &dot_notation_price::vat); - register_method("currency", {currency}); + register_methods(this, { + {"value", &dot_notation_price::value}, + {"vat", &dot_notation_price::vat}, + {"currency", &dot_notation_price::currency}}); + } + + mstch::node value() { + return m_value; } mstch::node vat() { - return static_cast(value * 0.2); + return static_cast(m_value * 0.2); + } + + mstch::node currency() { + return m_currency; } }; diff --git a/test/data/escaped.hpp b/test/data/escaped.hpp index f541278..23122ec 100644 --- a/test/data/escaped.hpp +++ b/test/data/escaped.hpp @@ -1,8 +1,9 @@ class escaped: public mstch::object { public: escaped() { - register_method("title", this, &escaped::title); - register_method("entities", this, &escaped::entities); + register_methods(this, { + {"title", &escaped::title}, {"entities", &escaped::entities} + }); } mstch::node title() { diff --git a/test/data/nested_higher_order_sections.hpp b/test/data/nested_higher_order_sections.hpp index 3f6b2c6..27126f9 100644 --- a/test/data/nested_higher_order_sections.hpp +++ b/test/data/nested_higher_order_sections.hpp @@ -1,8 +1,10 @@ class nested_higher_order_sections: public mstch::object { public: nested_higher_order_sections() { - register_method("bold", this, &nested_higher_order_sections::bold); - register_method("person", this, &nested_higher_order_sections::person); + register_methods(this, { + {"bold", &nested_higher_order_sections::bold}, + {"person", &nested_higher_order_sections::person} + }); } mstch::node bold() { diff --git a/test/data/partial_template.hpp b/test/data/partial_template.hpp index 3d4db5f..ca15079 100644 --- a/test/data/partial_template.hpp +++ b/test/data/partial_template.hpp @@ -1,8 +1,9 @@ class partial_template: public mstch::object { public: partial_template() { - register_method("title", this, &partial_template::title); - register_method("again", this, &partial_template::again); + register_methods(this, { + {"title", &partial_template::title}, + {"again", &partial_template::again}}); } mstch::node title() { diff --git a/test/data/section_functions_in_partials.hpp b/test/data/section_functions_in_partials.hpp index fc2e7f1..6459271 100644 --- a/test/data/section_functions_in_partials.hpp +++ b/test/data/section_functions_in_partials.hpp @@ -1,7 +1,7 @@ class section_functions_in_partials: public mstch::object { public: section_functions_in_partials() { - register_method("bold", this, §ion_functions_in_partials::bold); + register_methods(this, {{"bold", §ion_functions_in_partials::bold}}); } mstch::node bold() { diff --git a/test/data/unescaped.hpp b/test/data/unescaped.hpp index d121d25..cfca8d5 100644 --- a/test/data/unescaped.hpp +++ b/test/data/unescaped.hpp @@ -1,7 +1,7 @@ class unescaped: public mstch::object { public: unescaped() { - register_method("title", this, &unescaped::title); + register_methods(this, {{"title", &unescaped::title}}); } mstch::node title() {