@@ -156,7 +156,7 @@ InternalValue Serialize::Filter(const InternalValue& value, RenderContext& conte
156
156
return str +" \\ u003e" ;
157
157
break ;
158
158
case ' &' :
159
- return str +" \\ u0026" ;
159
+ return str +" \\ u0026" ;
160
160
break ;
161
161
case ' \' ' :
162
162
return str +" \\ u0027" ;
@@ -178,17 +178,25 @@ namespace
178
178
179
179
using FormatContext = fmt::format_context;
180
180
using FormatArgument = fmt::basic_format_arg<FormatContext>;
181
+ using FormatDynamicArgsStore = fmt::dynamic_format_arg_store<FormatContext>;
181
182
182
- template <typename ResultDecorator>
183
183
struct FormatArgumentConverter : visitors::BaseVisitor<FormatArgument>
184
184
{
185
185
using result_t = FormatArgument;
186
186
187
187
using BaseVisitor::operator ();
188
188
189
- FormatArgumentConverter (const RenderContext* context, const ResultDecorator& decorator )
189
+ FormatArgumentConverter (const RenderContext* context, FormatDynamicArgsStore& store )
190
190
: 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 )
192
200
{
193
201
}
194
202
@@ -217,62 +225,21 @@ struct FormatArgumentConverter : visitors::BaseVisitor<FormatArgument>
217
225
template <typename T>
218
226
result_t make_result (const T& t) const
219
227
{
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);
221
237
}
222
238
223
239
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;
274
241
const std::string m_name;
275
- ValuesBuffer& m_valuesBuffer ;
242
+ bool m_named = false ;
276
243
};
277
244
278
245
}
@@ -282,24 +249,18 @@ InternalValue StringFormat::Filter(const InternalValue& baseVal, RenderContext&
282
249
// Format library internally likes using non-owning views to complex arguments.
283
250
// In order to ensure proper lifetime of values and named args,
284
251
// 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;
289
253
for (auto & arg : m_params.posParams )
290
254
{
291
- args. push_back ( Apply<FormatArgumentConverter<CachingIdentity>> (arg->Evaluate (context), &context, CachingIdentity{ valuesBuffer }) );
255
+ Apply<FormatArgumentConverter> (arg->Evaluate (context), &context, store );
292
256
}
293
257
294
258
for (auto & arg : m_params.kwParams )
295
259
{
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 );
298
261
}
299
- // fmt process arguments until reaching empty argument
300
- args.push_back (FormatArgument{});
301
262
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 ));
303
264
}
304
265
305
266
class XmlAttrPrinter : public visitors ::BaseVisitor<std::string>
@@ -448,7 +409,7 @@ class XmlAttrPrinter : public visitors::BaseVisitor<std::string>
448
409
return str +" >" ;
449
410
break ;
450
411
case ' &' :
451
- return str +" &" ;
412
+ return str +" &" ;
452
413
break ;
453
414
case ' \' ' :
454
415
return str +" '" ;
0 commit comments