Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
TEST(PerfTests, PlainText)
{
std::string source = "Hello World from Parser!";
Template tpl;
ASSERT_TRUE(tpl.Load(source));
jinja2::ValuesMap params;
std::cout << tpl.RenderAsString(params) << std::endl;
std::string result;
for (int n = 0; n < Iterations * 100; ++ n)
result = tpl.RenderAsString(params);
std::cout << result << std::endl;
}
TEST(PerfTests, SimpleSubstituteText)
{
std::string source = "{{ message }} from Parser!";
Template tpl;
ASSERT_TRUE(tpl.Load(source));
jinja2::ValuesMap params = {{"message", "Hello World!"}};
std::cout << tpl.RenderAsString(params) << std::endl;
std::string result;
for (int n = 0; n < Iterations * 100; ++ n)
result = tpl.RenderAsString(params);
std::cout << result << std::endl;
}import unittest
from jinja2 import Template
class PerfTestCase(unittest.TestCase):
def _test_plait_text_render(self):
tpl = Template('Hello World from Parser!')
result = tpl.render()
print (result)
for n in range(0, 10000 * 100):
tpl.render()
print (result)
def test_simple_substitute_text(self):
tpl = Template('{{ message }} from Parser!')
result = tpl.render(message='Hello World!')
print (result)
for n in range(0, 10000 * 100):
tpl.render(message='Hello World!')
print (result)
[----------] 2 tests from PerfTests
[ RUN ] PerfTests.PlainText
Hello World from Parser!
Hello World from Parser!
[ OK ] PerfTests.PlainText (2084 ms)
[ RUN ] PerfTests.SimpleSubstituteText
Hello World! from Parser!
Hello World! from Parser!
[ OK ] PerfTests.SimpleSubstituteText (2581 ms)
[----------] 2 tests from PerfTests (4665 ms total)
d:\projects\work\Personal\Jinja2Cpp\python_jinja2>python -m unittest perf_test.PerfTestCase._test_plait_text_render
Hello World from Parser!
Hello World from Parser!
.
----------------------------------------------------------------------
Ran 1 test in 5.474s
OK
d:\projects\work\Personal\Jinja2Cpp\python_jinja2>python -m unittest perf_test.PerfTestCase.test_simple_substitute_text
Hello World! from Parser!
Hello World! from Parser!
.
----------------------------------------------------------------------
Ran 1 test in 6.543s
OK{% for i in range(20)%} {{i}} {%endfor%}"{% for i in range(20)%} {{i}}-{{loop.index}} {%endfor%}" — и всё. Снова проигрывает.Частичный ответ на первый вопрос: https://jinja2cpp.dev/docs/j2_compatibility.html#jinja2c-performance
Делал нечто подобное, правда скорее придерживался стиля Go(text/template) (с изменениями вызова функций и индексации элементов). Jinja вроде похож. Вот пара идей, которые вам могут показаться полезными:
1. В токенах имеет смысл указывать span, т.е. от и до, причём позицию удобно отслеживать сразу в виде {byte_pos, line, column} (обратите внимание, что для того чтобы правильно считать column понадобится рудиментарная поддержка юникод). Это пригодится при выводе сообщений об ошибках.
2. В грамматику языка ввести сырой текст как терминал.
3. Дать лексеру два состояния: парсинг выражений; парсинг сырого текста. Читать лексером посимвольно и дать ему понимание что состояние надо переключать в момент порождения токенов начала/конца выражений.
4. Избавиться от boost::variant и позволить Value быть функцией (с С++11 можно на шаблонах заворачивать произвольные функции и лямбды, давая возможность их проброса в движок в виде Value)
struct CallParams
{
std::unordered_map<std::string, Value> kwParams;
std::vector<Value> posParams;
};
Шаблоны третьего порядка, или как я портировал Jinja2 на C++