Jim Flynn | 05c342a | 2020-07-23 11:20:59 +0100 | [diff] [blame] | 1 | {fmt} |
| 2 | ===== |
| 3 | |
| 4 | .. image:: https://travis-ci.org/fmtlib/fmt.png?branch=master |
| 5 | :target: https://travis-ci.org/fmtlib/fmt |
| 6 | |
| 7 | .. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v |
| 8 | :target: https://ci.appveyor.com/project/vitaut/fmt |
| 9 | |
| 10 | .. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/libfmt.svg |
| 11 | :alt: fmt is continuously fuzzed at oss-fuzz |
| 12 | :target: https://bugs.chromium.org/p/oss-fuzz/issues/list?\ |
| 13 | colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20\ |
| 14 | Summary&q=proj%3Dlibfmt&can=1 |
| 15 | |
| 16 | .. image:: https://img.shields.io/badge/stackoverflow-fmt-blue.svg |
| 17 | :alt: Ask questions at StackOverflow with the tag fmt |
| 18 | :target: https://stackoverflow.com/questions/tagged/fmt |
| 19 | |
| 20 | **{fmt}** is an open-source formatting library for C++. |
| 21 | It can be used as a safe and fast alternative to (s)printf and iostreams. |
| 22 | |
| 23 | `Documentation <https://fmt.dev>`__ |
| 24 | |
| 25 | Q&A: ask questions on `StackOverflow with the tag fmt |
| 26 | <https://stackoverflow.com/questions/tagged/fmt>`_. |
| 27 | |
| 28 | Features |
| 29 | -------- |
| 30 | |
| 31 | * Simple `format API <https://fmt.dev/latest/api.html>`_ with positional arguments |
| 32 | for localization |
| 33 | * Implementation of `C++20 std::format |
| 34 | <https://en.cppreference.com/w/cpp/utility/format>`__ |
| 35 | * `Format string syntax <https://fmt.dev/latest/syntax.html>`_ similar to Python's |
| 36 | `format <https://docs.python.org/3/library/stdtypes.html#str.format>`_ |
| 37 | * Safe `printf implementation |
| 38 | <https://fmt.dev/latest/api.html#printf-formatting>`_ including the POSIX |
| 39 | extension for positional arguments |
| 40 | * Extensibility: `support for user-defined types |
| 41 | <https://fmt.dev/latest/api.html#formatting-user-defined-types>`_ |
| 42 | * High performance: faster than common standard library implementations of |
| 43 | ``(s)printf``, iostreams, ``to_string`` and ``to_chars``, see `Speed tests`_ |
| 44 | and `Converting a hundred million integers to strings per second |
| 45 | <http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html>`_ |
| 46 | * Small code size both in terms of source code with the minimum configuration |
| 47 | consisting of just three files, ``core.h``, ``format.h`` and ``format-inl.h``, |
| 48 | and compiled code; see `Compile time and code bloat`_ |
| 49 | * Reliability: the library has an extensive set of `unit tests |
| 50 | <https://github.com/fmtlib/fmt/tree/master/test>`_ and is continuously fuzzed |
| 51 | * Safety: the library is fully type safe, errors in format strings can be |
| 52 | reported at compile time, automatic memory management prevents buffer overflow |
| 53 | errors |
| 54 | * Ease of use: small self-contained code base, no external dependencies, |
| 55 | permissive MIT `license |
| 56 | <https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_ |
| 57 | * `Portability <https://fmt.dev/latest/index.html#portability>`_ with |
| 58 | consistent output across platforms and support for older compilers |
| 59 | * Clean warning-free codebase even on high warning levels such as |
| 60 | ``-Wall -Wextra -pedantic`` |
| 61 | * Locale-independence by default |
| 62 | * Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro |
| 63 | |
| 64 | See the `documentation <https://fmt.dev>`_ for more details. |
| 65 | |
| 66 | Examples |
| 67 | -------- |
| 68 | |
| 69 | Print ``Hello, world!`` to ``stdout``: |
| 70 | |
| 71 | .. code:: c++ |
| 72 | |
| 73 | #include <fmt/core.h> |
| 74 | |
| 75 | int main() { |
| 76 | fmt::print("Hello, world!\n"); |
| 77 | } |
| 78 | |
| 79 | Format a string: |
| 80 | |
| 81 | .. code:: c++ |
| 82 | |
| 83 | std::string s = fmt::format("The answer is {}.", 42); |
| 84 | // s == "The answer is 42." |
| 85 | |
| 86 | Format a string using positional arguments: |
| 87 | |
| 88 | .. code:: c++ |
| 89 | |
| 90 | std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy"); |
| 91 | // s == "I'd rather be happy than right." |
| 92 | |
| 93 | Print chrono durations: |
| 94 | |
| 95 | .. code:: c++ |
| 96 | |
| 97 | #include <fmt/chrono.h> |
| 98 | |
| 99 | int main() { |
| 100 | using namespace std::literals::chrono_literals; |
| 101 | fmt::print("Default format: {} {}\n", 42s, 100ms); |
| 102 | fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s); |
| 103 | } |
| 104 | |
| 105 | * Output:: |
| 106 | |
| 107 | Default format: 42s 100ms |
| 108 | strftime-like format: 03:15:30 |
| 109 | |
| 110 | Print a container: |
| 111 | |
| 112 | .. code:: c++ |
| 113 | |
| 114 | #include <vector> |
| 115 | #include <fmt/ranges.h> |
| 116 | |
| 117 | int main() { |
| 118 | std::vector<int> v = {1, 2, 3}; |
| 119 | fmt::print("{}\n", v); |
| 120 | } |
| 121 | |
| 122 | * Output:: |
| 123 | |
| 124 | {1, 2, 3} |
| 125 | |
| 126 | Check a format string at compile time: |
| 127 | |
| 128 | .. code:: c++ |
| 129 | |
| 130 | std::string s = fmt::format(FMT_STRING("{:d}"), "don't panic"); |
| 131 | |
| 132 | This gives a compile-time error because ``d`` is an invalid format specifier for |
| 133 | a string. |
| 134 | |
| 135 | Write a file from a single thread: |
| 136 | |
| 137 | .. code:: c++ |
| 138 | |
| 139 | #include <fmt/os.h> |
| 140 | |
| 141 | int main() { |
| 142 | auto out = fmt::output_file("guide.txt"); |
| 143 | out.print("Don't {}", "Panic"); |
| 144 | } |
| 145 | |
| 146 | This is up to 6x faster than glibc's ``fprintf``. |
| 147 | |
| 148 | Benchmarks |
| 149 | ---------- |
| 150 | |
| 151 | Speed tests |
| 152 | ~~~~~~~~~~~ |
| 153 | |
| 154 | ================= ============= =========== |
| 155 | Library Method Run Time, s |
| 156 | ================= ============= =========== |
| 157 | libc printf 1.04 |
| 158 | libc++ std::ostream 3.05 |
| 159 | {fmt} 6.1.1 fmt::print 0.75 |
| 160 | Boost Format 1.67 boost::format 7.24 |
| 161 | Folly Format folly::format 2.23 |
| 162 | ================= ============= =========== |
| 163 | |
| 164 | {fmt} is the fastest of the benchmarked methods, ~35% faster than ``printf``. |
| 165 | |
| 166 | The above results were generated by building ``tinyformat_test.cpp`` on macOS |
| 167 | 10.14.6 with ``clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT``, and taking the |
| 168 | best of three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"`` |
| 169 | or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for |
| 170 | further details refer to the `source |
| 171 | <https://github.com/fmtlib/format-benchmark/blob/master/tinyformat_test.cpp>`_. |
| 172 | |
| 173 | {fmt} is up to 10x faster than ``std::ostringstream`` and ``sprintf`` on |
| 174 | floating-point formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_) |
| 175 | and faster than `double-conversion <https://github.com/google/double-conversion>`_: |
| 176 | |
| 177 | .. image:: https://user-images.githubusercontent.com/576385/ |
| 178 | 69767160-cdaca400-112f-11ea-9fc5-347c9f83caad.png |
| 179 | :target: https://fmt.dev/unknown_mac64_clang10.0.html |
| 180 | |
| 181 | Compile time and code bloat |
| 182 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 183 | |
| 184 | The script `bloat-test.py |
| 185 | <https://github.com/fmtlib/format-benchmark/blob/master/bloat-test.py>`_ |
| 186 | from `format-benchmark <https://github.com/fmtlib/format-benchmark>`_ |
| 187 | tests compile time and code bloat for nontrivial projects. |
| 188 | It generates 100 translation units and uses ``printf()`` or its alternative |
| 189 | five times in each to simulate a medium sized project. The resulting |
| 190 | executable size and compile time (Apple LLVM version 8.1.0 (clang-802.0.42), |
| 191 | macOS Sierra, best of three) is shown in the following tables. |
| 192 | |
| 193 | **Optimized build (-O3)** |
| 194 | |
| 195 | ============= =============== ==================== ================== |
| 196 | Method Compile Time, s Executable size, KiB Stripped size, KiB |
| 197 | ============= =============== ==================== ================== |
| 198 | printf 2.6 29 26 |
| 199 | printf+string 16.4 29 26 |
| 200 | iostreams 31.1 59 55 |
| 201 | {fmt} 19.0 37 34 |
| 202 | Boost Format 91.9 226 203 |
| 203 | Folly Format 115.7 101 88 |
| 204 | ============= =============== ==================== ================== |
| 205 | |
| 206 | As you can see, {fmt} has 60% less overhead in terms of resulting binary code |
| 207 | size compared to iostreams and comes pretty close to ``printf``. Boost Format |
| 208 | and Folly Format have the largest overheads. |
| 209 | |
| 210 | ``printf+string`` is the same as ``printf`` but with extra ``<string>`` |
| 211 | include to measure the overhead of the latter. |
| 212 | |
| 213 | **Non-optimized build** |
| 214 | |
| 215 | ============= =============== ==================== ================== |
| 216 | Method Compile Time, s Executable size, KiB Stripped size, KiB |
| 217 | ============= =============== ==================== ================== |
| 218 | printf 2.2 33 30 |
| 219 | printf+string 16.0 33 30 |
| 220 | iostreams 28.3 56 52 |
| 221 | {fmt} 18.2 59 50 |
| 222 | Boost Format 54.1 365 303 |
| 223 | Folly Format 79.9 445 430 |
| 224 | ============= =============== ==================== ================== |
| 225 | |
| 226 | ``libc``, ``lib(std)c++`` and ``libfmt`` are all linked as shared libraries to |
| 227 | compare formatting function overhead only. Boost Format is a |
| 228 | header-only library so it doesn't provide any linkage options. |
| 229 | |
| 230 | Running the tests |
| 231 | ~~~~~~~~~~~~~~~~~ |
| 232 | |
| 233 | Please refer to `Building the library`__ for the instructions on how to build |
| 234 | the library and run the unit tests. |
| 235 | |
| 236 | __ https://fmt.dev/latest/usage.html#building-the-library |
| 237 | |
| 238 | Benchmarks reside in a separate repository, |
| 239 | `format-benchmarks <https://github.com/fmtlib/format-benchmark>`_, |
| 240 | so to run the benchmarks you first need to clone this repository and |
| 241 | generate Makefiles with CMake:: |
| 242 | |
| 243 | $ git clone --recursive https://github.com/fmtlib/format-benchmark.git |
| 244 | $ cd format-benchmark |
| 245 | $ cmake . |
| 246 | |
| 247 | Then you can run the speed test:: |
| 248 | |
| 249 | $ make speed-test |
| 250 | |
| 251 | or the bloat test:: |
| 252 | |
| 253 | $ make bloat-test |
| 254 | |
| 255 | Projects using this library |
| 256 | --------------------------- |
| 257 | |
| 258 | * `0 A.D. <https://play0ad.com/>`_: A free, open-source, cross-platform |
| 259 | real-time strategy game |
| 260 | |
| 261 | * `AMPL/MP <https://github.com/ampl/mp>`_: |
| 262 | An open-source library for mathematical programming |
| 263 | |
| 264 | * `Aseprite <https://github.com/aseprite/aseprite>`_: |
| 265 | Animated sprite editor & pixel art tool |
| 266 | |
| 267 | * `AvioBook <https://www.aviobook.aero/en>`_: A comprehensive aircraft |
| 268 | operations suite |
| 269 | |
| 270 | * `Celestia <https://celestia.space/>`_: Real-time 3D visualization of space |
| 271 | |
| 272 | * `Ceph <https://ceph.com/>`_: A scalable distributed storage system |
| 273 | |
| 274 | * `ccache <https://ccache.dev/>`_: A compiler cache |
| 275 | |
| 276 | * `ClickHouse <https://github.com/ClickHouse/ClickHouse>`_: analytical database |
| 277 | management system |
| 278 | |
| 279 | * `CUAUV <http://cuauv.org/>`_: Cornell University's autonomous underwater |
| 280 | vehicle |
| 281 | |
| 282 | * `Drake <https://drake.mit.edu/>`_: A planning, control, and analysis toolbox |
| 283 | for nonlinear dynamical systems (MIT) |
| 284 | |
| 285 | * `Envoy <https://lyft.github.io/envoy/>`_: C++ L7 proxy and communication bus |
| 286 | (Lyft) |
| 287 | |
| 288 | * `FiveM <https://fivem.net/>`_: a modification framework for GTA V |
| 289 | |
| 290 | * `Folly <https://github.com/facebook/folly>`_: Facebook open-source library |
| 291 | |
| 292 | * `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_: |
| 293 | Player vs Player Gaming Network with tweaks |
| 294 | |
| 295 | * `KBEngine <https://github.com/kbengine/kbengine>`_: An open-source MMOG server |
| 296 | engine |
| 297 | |
| 298 | * `Keypirinha <https://keypirinha.com/>`_: A semantic launcher for Windows |
| 299 | |
| 300 | * `Kodi <https://kodi.tv/>`_ (formerly xbmc): Home theater software |
| 301 | |
| 302 | * `Knuth <https://kth.cash/>`_: High-performance Bitcoin full-node |
| 303 | |
| 304 | * `Microsoft Verona <https://github.com/microsoft/verona>`_: |
| 305 | Research programming language for concurrent ownership |
| 306 | |
| 307 | * `MongoDB <https://mongodb.com/>`_: Distributed document database |
| 308 | |
| 309 | * `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to |
| 310 | generate randomized datasets |
| 311 | |
| 312 | * `OpenSpace <https://openspaceproject.com/>`_: An open-source |
| 313 | astrovisualization framework |
| 314 | |
| 315 | * `PenUltima Online (POL) <https://www.polserver.com/>`_: |
| 316 | An MMO server, compatible with most Ultima Online clients |
| 317 | |
| 318 | * `PyTorch <https://github.com/pytorch/pytorch>`_: An open-source machine |
| 319 | learning library |
| 320 | |
| 321 | * `quasardb <https://www.quasardb.net/>`_: A distributed, high-performance, |
| 322 | associative database |
| 323 | |
| 324 | * `readpe <https://bitbucket.org/sys_dev/readpe>`_: Read Portable Executable |
| 325 | |
| 326 | * `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: A Redis cluster |
| 327 | proxy |
| 328 | |
| 329 | * `redpanda <https://vectorized.io/redpanda>`_: A 10x faster Kafka® replacement |
| 330 | for mission critical systems written in C++ |
| 331 | |
| 332 | * `rpclib <http://rpclib.net/>`_: A modern C++ msgpack-RPC server and client |
| 333 | library |
| 334 | |
| 335 | * `Salesforce Analytics Cloud |
| 336 | <https://www.salesforce.com/analytics-cloud/overview/>`_: |
| 337 | Business intelligence software |
| 338 | |
| 339 | * `Scylla <https://www.scylladb.com/>`_: A Cassandra-compatible NoSQL data store |
| 340 | that can handle 1 million transactions per second on a single server |
| 341 | |
| 342 | * `Seastar <http://www.seastar-project.org/>`_: An advanced, open-source C++ |
| 343 | framework for high-performance server applications on modern hardware |
| 344 | |
| 345 | * `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging library |
| 346 | |
| 347 | * `Stellar <https://www.stellar.org/>`_: Financial platform |
| 348 | |
| 349 | * `Touch Surgery <https://www.touchsurgery.com/>`_: Surgery simulator |
| 350 | |
| 351 | * `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: Open-source |
| 352 | MMORPG framework |
| 353 | |
| 354 | * `Windows Terminal <https://github.com/microsoft/terminal>`_: The new Windows |
| 355 | Terminal |
| 356 | |
| 357 | `More... <https://github.com/search?q=fmtlib&type=Code>`_ |
| 358 | |
| 359 | If you are aware of other projects using this library, please let me know |
| 360 | by `email <mailto:victor.zverovich@gmail.com>`_ or by submitting an |
| 361 | `issue <https://github.com/fmtlib/fmt/issues>`_. |
| 362 | |
| 363 | Motivation |
| 364 | ---------- |
| 365 | |
| 366 | So why yet another formatting library? |
| 367 | |
| 368 | There are plenty of methods for doing this task, from standard ones like |
| 369 | the printf family of function and iostreams to Boost Format and FastFormat |
| 370 | libraries. The reason for creating a new library is that every existing |
| 371 | solution that I found either had serious issues or didn't provide |
| 372 | all the features I needed. |
| 373 | |
| 374 | printf |
| 375 | ~~~~~~ |
| 376 | |
| 377 | The good thing about ``printf`` is that it is pretty fast and readily available |
| 378 | being a part of the C standard library. The main drawback is that it |
| 379 | doesn't support user-defined types. ``printf`` also has safety issues although |
| 380 | they are somewhat mitigated with `__attribute__ ((format (printf, ...)) |
| 381 | <https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ in GCC. |
| 382 | There is a POSIX extension that adds positional arguments required for |
| 383 | `i18n <https://en.wikipedia.org/wiki/Internationalization_and_localization>`_ |
| 384 | to ``printf`` but it is not a part of C99 and may not be available on some |
| 385 | platforms. |
| 386 | |
| 387 | iostreams |
| 388 | ~~~~~~~~~ |
| 389 | |
| 390 | The main issue with iostreams is best illustrated with an example: |
| 391 | |
| 392 | .. code:: c++ |
| 393 | |
| 394 | std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n"; |
| 395 | |
| 396 | which is a lot of typing compared to printf: |
| 397 | |
| 398 | .. code:: c++ |
| 399 | |
| 400 | printf("%.2f\n", 1.23456); |
| 401 | |
| 402 | Matthew Wilson, the author of FastFormat, called this "chevron hell". iostreams |
| 403 | don't support positional arguments by design. |
| 404 | |
| 405 | The good part is that iostreams support user-defined types and are safe although |
| 406 | error handling is awkward. |
| 407 | |
| 408 | Boost Format |
| 409 | ~~~~~~~~~~~~ |
| 410 | |
| 411 | This is a very powerful library which supports both ``printf``-like format |
| 412 | strings and positional arguments. Its main drawback is performance. According to |
| 413 | various, benchmarks it is much slower than other methods considered here. Boost |
| 414 | Format also has excessive build times and severe code bloat issues (see |
| 415 | `Benchmarks`_). |
| 416 | |
| 417 | FastFormat |
| 418 | ~~~~~~~~~~ |
| 419 | |
| 420 | This is an interesting library which is fast, safe and has positional arguments. |
| 421 | However, it has significant limitations, citing its author: |
| 422 | |
| 423 | Three features that have no hope of being accommodated within the |
| 424 | current design are: |
| 425 | |
| 426 | * Leading zeros (or any other non-space padding) |
| 427 | * Octal/hexadecimal encoding |
| 428 | * Runtime width/alignment specification |
| 429 | |
| 430 | It is also quite big and has a heavy dependency, STLSoft, which might be too |
| 431 | restrictive for using it in some projects. |
| 432 | |
| 433 | Boost Spirit.Karma |
| 434 | ~~~~~~~~~~~~~~~~~~ |
| 435 | |
| 436 | This is not really a formatting library but I decided to include it here for |
| 437 | completeness. As iostreams, it suffers from the problem of mixing verbatim text |
| 438 | with arguments. The library is pretty fast, but slower on integer formatting |
| 439 | than ``fmt::format_to`` with format string compilation on Karma's own benchmark, |
| 440 | see `Converting a hundred million integers to strings per second |
| 441 | <http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html>`_. |
| 442 | |
| 443 | License |
| 444 | ------- |
| 445 | |
| 446 | {fmt} is distributed under the MIT `license |
| 447 | <https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_. |
| 448 | |
| 449 | Documentation License |
| 450 | --------------------- |
| 451 | |
| 452 | The `Format String Syntax <https://fmt.dev/latest/syntax.html>`_ |
| 453 | section in the documentation is based on the one from Python `string module |
| 454 | documentation <https://docs.python.org/3/library/string.html#module-string>`_. |
| 455 | For this reason the documentation is distributed under the Python Software |
| 456 | Foundation license available in `doc/python-license.txt |
| 457 | <https://raw.github.com/fmtlib/fmt/master/doc/python-license.txt>`_. |
| 458 | It only applies if you distribute the documentation of {fmt}. |
| 459 | |
| 460 | Maintainers |
| 461 | ----------- |
| 462 | |
| 463 | The {fmt} library is maintained by Victor Zverovich (`vitaut |
| 464 | <https://github.com/vitaut>`_) and Jonathan Müller (`foonathan |
| 465 | <https://github.com/foonathan>`_) with contributions from many other people. |
| 466 | See `Contributors <https://github.com/fmtlib/fmt/graphs/contributors>`_ and |
| 467 | `Releases <https://github.com/fmtlib/fmt/releases>`_ for some of the names. |
| 468 | Let us know if your contribution is not listed or mentioned incorrectly and |
| 469 | we'll make it right. |