kainjow / Mustache

Mustache text templates for modern C++
Boost Software License 1.0
350 stars 49 forks source link

partially render templates for improved performance? #67

Open dvtate opened 1 week ago

dvtate commented 1 week ago

I'd like to pre-populate some fields in a template that will always be the same in order to improve performance. For example:

Hello {{user}}, welcome to {{server}}.

I'd like to prepopulate {{server}} since it will not change and this template will be generated potentially millions of times.

My first naive attempt to do this looked like this:

kainjow::mustache::data global_data;
global_data.set("server", get_hostname());
kainjow::mustache::mustache t = kainjow::mustache::mustache(template_str).render(global_data);

However this deletes the {{user}} field so the code

t.render({ "user", provided_username });

results in

Hello , welcome to localhost.

So, two questions:

  1. Is there a way to do this without manually setting each variable to "{{variable}}"?
  2. Would could this actually improve performance?

Thanks!

KitsuneRal commented 1 week ago
  1. Not that I know of. The problem is: how do you distinguish between intentionally absent values (like user in your case) and values that can be specified or unspecified depending on a data instance? Mustache cannot enforce non-emptiness of values. If you really need to make the prefilling work (see the next point) then you can derive from kainjow::mustache::context and replace certain {{...}} sections with themselves - or, if there are just few of such sections, just do global_data.set("{{user}}", "{{user}}"); and so on for each.
  2. This is the right question, and you are the only one who can answer it because it's your application and only you know how you use Mustache. From general considerations, I would say it's highly improbable for smaller templates - very very likely I/O and memory allocations from repeated rendering will dwarf any theoretical benefits from such optimisation. Entirely off the wall, if I were to deal with big (100 kBs or MBs) templates used numerous (1000s) times with some (1000s) values prefilled and others varying - I would do performance tests and see if prefilling makes sense for this kind of payloads. Anything less than that - I wouldn't even bother, unless shaving off milliseconds would make for a business case.
dvtate commented 1 week ago

For now I'm using std::regex_replace on the templates before passing them into mustache... Maybe later I'll come up with something better.

This is a C++ framework so performance is usually pretty important for C++ devs, even if it's only a few percentage points improvement.

kainjow commented 1 week ago

If you have control of this template, you could maybe try the set delimiter tags and use different characters for the fields you want to pre-populate, then render that template with pre-populated fields, which would produce the final template for dynamic data.

For example, render this with a "server" value:

{{=[[ ]]=}}
Hello {{user}}, welcome to [[server]].

which would then produce:

Hello {{user}}, welcome to localhost.