[Support] Introduce llvm::formatv() function. · llvm/llvm-project@11db264 (original) (raw)
`@@ -263,6 +263,136 @@ almost never be stored or mentioned directly. They are intended solely for use
`
263
263
`when defining a function which should be able to efficiently accept concatenated
`
264
264
`strings.
`
265
265
``
``
266
`+
.. _formatting_strings:
`
``
267
+
``
268
Formatting strings (the ``formatv`` function)
``
269
`+
`
``
270
`+
While LLVM doesn't necessarily do a lot of string manipulation and parsing, it
`
``
271
`+
does do a lot of string formatting. From diagnostic messages, to llvm tool
`
``
272
outputs such as ``llvm-readobj`` to printing verbose disassembly listings and
``
273
`+
LLDB runtime logging, the need for string formatting is pervasive.
`
``
274
+
``
275
The ``formatv`` is similar in spirit to ``printf``, but uses a different syntax
``
276
which borrows heavily from Python and C#. Unlike ``printf`` it deduces the type
``
277
`+
to be formatted at compile time, so it does not need a format specifier such as
`
``
278
``%d``. This reduces the mental overhead of trying to construct portable format
``
279
strings, especially for platform-specific types like ``size_t`` or pointer types.
``
280
Unlike both ``printf`` and Python, it additionally fails to compile if LLVM does
``
281
`+
not know how to format the type. These two properties ensure that the function
`
``
282
`+
is both safer and simpler to use than traditional formatting methods such as
`
``
283
the ``printf`` family of functions.
``
284
+
``
285
`+
Simple formatting
`
``
286
`+
^^^^^^^^^^^^^^^^^
`
``
287
+
``
288
A call to ``formatv`` involves a single **format string** consisting of 0 or more
``
289
`+
replacement sequences, followed by a variable length list of replacement values.
`
``
290
A replacement sequence is a string of the form ``{N[[,align]:style]}``.
``
291
+
``
292
``N`` refers to the 0-based index of the argument from the list of replacement
``
293
`+
values. Note that this means it is possible to reference the same parameter
`
``
294
`+
multiple times, possibly with different style and/or alignment options, in any order.
`
``
295
+
``
296
``align`` is an optional string specifying the width of the field to format
``
297
`+
the value into, and the alignment of the value within the field. It is specified as
`
``
298
`+
an optional alignment style followed by a positive integral field width. The
`
``
299
alignment style can be one of the characters ``-`` (left align), ``=`` (center align),
``
300
or ``+`` (right align). The default is right aligned.
``
301
+
``
302
``style`` is an optional string consisting of a type specific that controls the
``
303
`+
formatting of the value. For example, to format a floating point value as a percentage,
`
``
304
you can use the style option ``P``.
``
305
+
``
306
`+
Custom formatting
`
``
307
`+
^^^^^^^^^^^^^^^^^
`
``
308
+
``
309
`+
There are two ways to customize the formatting behavior for a type.
`
``
310
+
``
311
1. Provide a template specialization of ``llvm::format_provider<T>`` for your
``
312
type ``T`` with the appropriate static format method.
``
313
+
``
314
`+
.. code-block:: c++
`
``
315
+
``
316
`+
namespace llvm {
`
``
317
`+
template<>
`
``
318
`+
struct format_provider {
`
``
319
`+
static void format(const MyFooBar &V, raw_ostream &Stream, StringRef Style) {
`
``
320
`` +
// Do whatever is necessary to format V into Stream
``
``
321
`+
}
`
``
322
`+
};
`
``
323
`+
void foo() {
`
``
324
`+
MyFooBar X;
`
``
325
`+
std::string S = formatv("{0}", X);
`
``
326
`+
}
`
``
327
`+
}
`
``
328
+
``
329
`+
This is a useful extensibility mechanism for adding support for formatting your own
`
``
330
`+
custom types with your own custom Style options. But it does not help when you want
`
``
331
`+
to extend the mechanism for formatting a type that the library already knows how to
`
``
332
`+
format. For that, we need something else.
`
``
333
+
``
334
`+
- Provide a format adapter with a non-static format method.
`
``
335
+
``
336
`+
.. code-block:: c++
`
``
337
+
``
338
`+
namespace anything {
`
``
339
`+
struct format_int_custom {
`
``
340
`+
int N;
`
``
341
`+
explicit format_int_custom(int N) : N(N) {}
`
``
342
`+
void format(llvm::raw_ostream &Stream, StringRef Style) {
`
``
343
// Do whatever is necessary to format ``N`` into ``Stream``
``
344
`+
}
`
``
345
`+
};
`
``
346
`+
}
`
``
347
`+
namespace llvm {
`
``
348
`+
void foo() {
`
``
349
`+
std::string S = formatv("{0}", anything::format_int_custom(42));
`
``
350
`+
}
`
``
351
`+
}
`
``
352
+
``
353
If the search for a specialization of ``format_provider<T>`` for the given type
``
354
fails, ``formatv`` will subsequently check the argument for an instance method
``
355
named ``format`` with the signature described above. If so, it will call the
``
356
``format`` method on the argument passing in the specified style. This allows
``
357
`+
one to provide custom formatting of any type, including one which already has
`
``
358
`+
a builtin format provider.
`
``
359
+
``
360
``formatv`` Examples
``
361
`+
^^^^^^^^^^^^^^^^^^^^
`
``
362
`+
Below is intended to provide an incomplete set of examples demonstrating
`
``
363
the usage of ``formatv``. More information can be found by reading the
``
364
`+
doxygen documentation or by looking at the unit test suite.
`
``
365
+
``
366
+
``
367
`+
.. code-block:: c++
`
``
368
+
``
369
`+
std::string S;
`
``
370
`+
// Simple formatting of basic types and implicit string conversion.
`
``
371
`+
S = formatv("{0} ({1:P})", 7, 0.35); // S == "7 (35.00%)"
`
``
372
+
``
373
`+
// Out-of-order referencing and multi-referencing
`
``
374
`+
outs() << formatv("{0} {2} {1} {0}", 1, "test", 3); // prints "1 3 test 1"
`
``
375
+
``
376
`+
// Left, right, and center alignment
`
``
377
`+
S = formatv("{0,7}", 'a'); // S == " a";
`
``
378
`+
S = formatv("{0,-7}", 'a'); // S == "a ";
`
``
379
`+
S = formatv("{0,=7}", 'a'); // S == " a ";
`
``
380
`+
S = formatv("{0,+7}", 'a'); // S == " a";
`
``
381
+
``
382
`+
// Custom styles
`
``
383
`+
S = formatv("{0:N} - {0:x} - {1:E}", 12345, 123908342); // S == "12,345 - 0x3039 - 1.24E8"
`
``
384
+
``
385
`+
// Adapters
`
``
386
`+
S = formatv("{0}", fmt_align(42, AlignStyle::Center, 7)); // S == " 42 "
`
``
387
`+
S = formatv("{0}", fmt_repeat("hi", 3)); // S == "hihihi"
`
``
388
`+
S = formatv("{0}", fmt_pad("hi", 2, 6)); // S == " hi "
`
``
389
+
``
390
`+
// Ranges
`
``
391
`+
std::vector V = {8, 9, 10};
`
``
392
`+
S = formatv("{0}", make_range(V.begin(), V.end())); // S == "8, 9, 10"
`
``
393
`+
S = formatv("{0:$[+]}", make_range(V.begin(), V.end())); // S == "8+9+10"
`
``
394
`+
S = formatv("{0:$[ + ]@[x]}", make_range(V.begin(), V.end())); // S == "0x8 + 0x9 + 0xA"
`
``
395
+
266
396
`.. _error_apis:
`
267
397
``
268
398
`Error handling
`