4 #include <unordered_map> 21 using string_list = std::vector<std::string>;
24 void s(
const std::string& k,
const std::string& v) {
31 void d(
const std::string& k,
const T& v) {
32 strings_[k] = std::to_string(v);
38 const std::string& s(
const std::string& k)
const {
39 if (strings_.count(k) == 0) {
45 return strings_.at(k);
49 void v(
const std::string& k,
const string_list& v) {
56 const string_list& v(
const std::string& k)
const {
57 if (lists_.count(k) == 0) {
67 bool keyIsString(
const std::string& k)
const {
68 if (strings_.count(k) > 0)
70 if (lists_.count(k) > 0)
73 return parent->keyIsString(k);
78 [[noreturn]]
void notFound(
const std::string& k)
const {
80 ss <<
"key not found: " << k;
81 throw std::logic_error(ss.str());
83 std::unordered_map<std::string, std::string> strings_;
84 std::unordered_map<std::string, string_list> lists_;
98 CodeTemplate(std::string t) : template_text(std::move(t)) {}
101 std::stringstream out;
104 bool all_whitespace =
true;
105 while (pos < template_text.size()) {
106 char c = template_text[pos];
108 std::stringstream kss;
111 size_t new_pos = parseKey(pos, kss, comma_before, comma_after);
112 std::string k = kss.str();
113 bool is_string = env.keyIsString(k);
114 if (all_whitespace) {
116 emitStringWithIndents(out, indent, env.s(k));
118 emitLinesIndented(out, indent, env.v(k));
123 emitCommaSeparatedList(out, env.v(k), comma_before, comma_after);
125 all_whitespace =
false;
130 all_whitespace =
false;
134 all_whitespace =
true;
143 using string_list = std::vector<std::string>;
144 char charAt(
size_t p)
const {
145 if (p >= template_text.size())
146 throw std::logic_error(
"EOS found in key");
147 return template_text[p];
153 bool& comma_after)
const {
154 comma_before =
false;
157 if (charAt(pos) ==
'{') {
159 if (charAt(pos) ==
',') {
163 pos = parseIdent(pos, k);
164 if (charAt(pos) ==
',') {
168 if (charAt(pos) !=
'}')
169 throw std::logic_error(
"missing terminating '}'");
173 return parseIdent(pos, k);
176 size_t parseIdent(
size_t pos, std::ostream& k)
const {
177 while (pos < template_text.size() &&
178 (isalnum(template_text[pos]) || template_text[pos] ==
'_')) {
179 k << template_text[pos];
184 void emitCommaSeparatedList(
186 const string_list& strings,
188 bool comma_after)
const {
189 if (comma_before && strings.size() > 0)
191 for (
size_t i = 0; i < strings.size(); ++i) {
196 if (comma_after && strings.size() > 0)
203 void emitIndent(std::ostream& out,
size_t indent)
const {
204 for (
size_t i = 0; i < indent; ++i) {
208 void emitStringWithIndents(
211 const std::string& str)
const {
215 emitIndent(out, indent);
219 void emitLinesIndented(
220 std::stringstream& out,
222 const string_list& strings)
const {
223 for (
size_t i = 0; i < strings.size(); ++i) {
225 emitIndent(out, indent);
226 emitStringWithIndents(out, indent, strings[i]);
227 if (i + 1 != strings.size())
231 std::string template_text;
233 static inline std::string format(
const std::string& fmt,
TemplateEnv& env) {