@@ -156,7 +156,7 @@ InternalValue Serialize::Filter(const InternalValue& value, RenderContext& conte
156156 return str +" \\ u003e" ;
157157 break ;
158158 case ' &' :
159- return str +" \\ u0026" ;
159+ return str +" \\ u0026" ;
160160 break ;
161161 case ' \' ' :
162162 return str +" \\ u0027" ;
@@ -178,17 +178,25 @@ namespace
178178
179179using FormatContext = fmt::format_context;
180180using FormatArgument = fmt::basic_format_arg<FormatContext>;
181+ using FormatDynamicArgsStore = fmt::dynamic_format_arg_store<FormatContext>;
181182
182- template <typename ResultDecorator>
183183struct FormatArgumentConverter : visitors::BaseVisitor<FormatArgument>
184184{
185185 using result_t = FormatArgument;
186186
187187 using BaseVisitor::operator ();
188188
189- FormatArgumentConverter (const RenderContext* context, const ResultDecorator& decorator )
189+ FormatArgumentConverter (const RenderContext* context, FormatDynamicArgsStore& store )
190190 : m_context(context)
191- , m_decorator(decorator)
191+ , m_store(store)
192+ {
193+ }
194+
195+ FormatArgumentConverter (const RenderContext* context, FormatDynamicArgsStore& store, const std::string& name)
196+ : m_context(context)
197+ , m_store(store)
198+ , m_name(name)
199+ , m_named(true )
192200 {
193201 }
194202
@@ -217,62 +225,21 @@ struct FormatArgumentConverter : visitors::BaseVisitor<FormatArgument>
217225 template <typename T>
218226 result_t make_result (const T& t) const
219227 {
220- return fmt::detail::make_arg<FormatContext>(m_decorator (t));
228+ if (!m_named)
229+ {
230+ m_store.push_back (t);
231+ }
232+ else
233+ {
234+ m_store.push_back (fmt::arg (m_name.c_str (), t));
235+ }
236+ return fmt::detail::make_arg<FormatContext>(t);
221237 }
222238
223239 const RenderContext* m_context;
224- const ResultDecorator& m_decorator;
225- };
226-
227- template <typename T>
228- using NamedArgument = fmt::detail::named_arg<char , T>;
229-
230- using ValueHandle =
231- nonstd::variant<bool , std::string, int64_t , double , NamedArgument<bool >, NamedArgument<std::string>, NamedArgument<int64_t >, NamedArgument<double >>;
232- using ValuesBuffer = std::vector<ValueHandle>;
233-
234- struct CachingIdentity
235- {
236- public:
237- explicit CachingIdentity (ValuesBuffer& values)
238- : m_values(values)
239- {
240- }
241-
242- template <typename T>
243- const auto & operator ()(const T& t) const
244- {
245- m_values.push_back (t);
246- return nonstd::get<T>(m_values.back ());
247- }
248-
249- private:
250- ValuesBuffer& m_values;
251- };
252-
253- class NamedArgumentCreator
254- {
255- public:
256- NamedArgumentCreator (const std::string& name, ValuesBuffer& valuesBuffer)
257- : m_name(name)
258- , m_valuesBuffer(valuesBuffer)
259- {
260- }
261-
262- template <typename T>
263- const auto & operator ()(const T& t) const
264- {
265- m_valuesBuffer.push_back (m_name);
266- const auto & name = nonstd::get<std::string>(m_valuesBuffer.back ());
267- m_valuesBuffer.push_back (t);
268- const auto & value = nonstd::get<T>(m_valuesBuffer.back ());
269- m_valuesBuffer.emplace_back (fmt::arg (name.c_str (), value));
270- return nonstd::get<NamedArgument<T>>(m_valuesBuffer.back ());
271- }
272-
273- private:
240+ FormatDynamicArgsStore& m_store;
274241 const std::string m_name;
275- ValuesBuffer& m_valuesBuffer ;
242+ bool m_named = false ;
276243};
277244
278245}
@@ -282,24 +249,18 @@ InternalValue StringFormat::Filter(const InternalValue& baseVal, RenderContext&
282249 // Format library internally likes using non-owning views to complex arguments.
283250 // In order to ensure proper lifetime of values and named args,
284251 // helper buffer is created and passed to visitors.
285- ValuesBuffer valuesBuffer;
286- valuesBuffer.reserve (m_params.posParams .size () + 3 * m_params.kwParams .size ());
287-
288- std::vector<FormatArgument> args;
252+ FormatDynamicArgsStore store;
289253 for (auto & arg : m_params.posParams )
290254 {
291- args. push_back ( Apply<FormatArgumentConverter<CachingIdentity>> (arg->Evaluate (context), &context, CachingIdentity{ valuesBuffer }) );
255+ Apply<FormatArgumentConverter> (arg->Evaluate (context), &context, store );
292256 }
293257
294258 for (auto & arg : m_params.kwParams )
295259 {
296- args.push_back (
297- Apply<FormatArgumentConverter<NamedArgumentCreator>>(arg.second ->Evaluate (context), &context, NamedArgumentCreator{ arg.first , valuesBuffer }));
260+ Apply<FormatArgumentConverter>(arg.second ->Evaluate (context), &context, store, arg.first );
298261 }
299- // fmt process arguments until reaching empty argument
300- args.push_back (FormatArgument{});
301262
302- return InternalValue (fmt::vformat (AsString (baseVal), fmt::format_args (args. data (), static_cast < unsigned >(args. size () - 1 )) ));
263+ return InternalValue (fmt::vformat (AsString (baseVal), store ));
303264}
304265
305266class XmlAttrPrinter : public visitors ::BaseVisitor<std::string>
@@ -448,7 +409,7 @@ class XmlAttrPrinter : public visitors::BaseVisitor<std::string>
448409 return str +" >" ;
449410 break ;
450411 case ' &' :
451- return str +" &" ;
412+ return str +" &" ;
452413 break ;
453414 case ' \' ' :
454415 return str +" '" ;
0 commit comments