[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

`+

  1. 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

`