#include "SimpleTemplate.hpp"
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/variant.hpp>
#include <cassert>
#include <ostream>
using namespace synth;
SimpleTemplate::SimpleTemplate(boost::string_ref text)
{
static char const rawMarker[] = "@@";
static boost::string_ref const marker(rawMarker, sizeof(rawMarker) - 1);
auto beg = text.find(marker);
while (beg != boost::string_ref::npos) {
m_literals.emplace_back(text.data(), beg);
text.remove_prefix(beg + marker.size());
auto end = text.find(marker);
if (end == boost::string_ref::npos) {
std::string& lit = m_literals.back();
lit.reserve(lit.size() + marker.size() + text.size());
lit.append(marker.data(), marker.size());
lit.append(text.data(), text.size());
assert(m_literals.size() == m_insertionKeys.size() + 1);
return;
}
m_insertionKeys.emplace_back(text.data(), end);
text.remove_prefix(end + marker.size());
beg = text.find(marker);
}
m_literals.emplace_back(text.data(), text.size());
assert(m_literals.size() == m_insertionKeys.size() + 1);
}
namespace {
class ValVisitor: public boost::static_visitor<> {
public:
ValVisitor(std::ostream& out)
: m_out(out)
{ }
void operator()(std::string const& s) { m_out << s; }
void operator()(SimpleTemplate::ValCallback const& cb) { cb(m_out); }
private:
std::ostream& m_out;
};
} // anonymous namespace
void SimpleTemplate::writeTo(
std::ostream& out,
SimpleTemplate::Context const& ctx) const
{
ValVisitor visitor(out);
for (std::size_t i = 0; i < m_literals.size(); ++i) {
out << m_literals[i];
if (m_insertionKeys.size() > i) {
auto it = ctx.find(m_insertionKeys[i]);
if (it == ctx.end()) {
throw std::runtime_error(
"No value for template placeholder @@"
+ m_insertionKeys[i]
+ "@@ available.");
}
boost::apply_visitor(visitor, it->second);
}
}
}