Giter Site home page Giter Site logo

fmtlib / fmt Goto Github PK

View Code? Open in Web Editor NEW
19.3K 320.0 2.4K 14.64 MB

A modern formatting library

Home Page: https://fmt.dev

License: Other

Makefile 0.01% C++ 96.50% Python 1.64% CMake 1.69% HTML 0.02% Shell 0.08% Cuda 0.04% Starlark 0.02% C 0.01%
c-plus-plus formatting printf output chrono performance multiplatform cross-platform cpp ranges

fmt's Introduction

{fmt}

image image image fmt is continuously fuzzed at oss-fuzz Ask questions at StackOverflow with the tag fmt image

{fmt} is an open-source formatting library providing a fast and safe alternative to C stdio and C++ iostreams.

If you like this project, please consider donating to one of the funds that help victims of the war in Ukraine: https://www.stopputin.net/.

Documentation

Cheat Sheets

Q&A: ask questions on StackOverflow with the tag fmt.

Try {fmt} in Compiler Explorer.

Features

  • Simple format API with positional arguments for localization
  • Implementation of C++20 std::format and C++23 std::print
  • Format string syntax similar to Python's format
  • Fast IEEE 754 floating-point formatter with correct rounding, shortness and round-trip guarantees using the Dragonbox algorithm
  • Portable Unicode support
  • Safe printf implementation including the POSIX extension for positional arguments
  • Extensibility: support for user-defined types
  • High performance: faster than common standard library implementations of (s)printf, iostreams, to_string and to_chars, see Speed tests and Converting a hundred million integers to strings per second
  • Small code size both in terms of source code with the minimum configuration consisting of just three files, core.h, format.h and format-inl.h, and compiled code; see Compile time and code bloat
  • Reliability: the library has an extensive set of tests and is continuously fuzzed
  • Safety: the library is fully type-safe, errors in format strings can be reported at compile time, automatic memory management prevents buffer overflow errors
  • Ease of use: small self-contained code base, no external dependencies, permissive MIT license
  • Portability with consistent output across platforms and support for older compilers
  • Clean warning-free codebase even on high warning levels such as -Wall -Wextra -pedantic
  • Locale independence by default
  • Optional header-only configuration enabled with the FMT_HEADER_ONLY macro

See the documentation for more details.

Examples

Print to stdout (run)

#include <fmt/core.h>

int main() {
  fmt::print("Hello, world!\n");
}

Format a string (run)

std::string s = fmt::format("The answer is {}.", 42);
// s == "The answer is 42."

Format a string using positional arguments (run)

std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");
// s == "I'd rather be happy than right."

Print dates and times (run)

#include <fmt/chrono.h>

int main() {
  auto now = std::chrono::system_clock::now();
  fmt::print("Date and time: {}\n", now);
  fmt::print("Time: {:%H:%M}\n", now);
}

Output:

Date and time: 2023-12-26 19:10:31.557195597
Time: 19:10

Print a container (run)

#include <vector>
#include <fmt/ranges.h>

int main() {
  std::vector<int> v = {1, 2, 3};
  fmt::print("{}\n", v);
}

Output:

[1, 2, 3]

Check a format string at compile time

std::string s = fmt::format("{:d}", "I am not a number");

This gives a compile-time error in C++20 because d is an invalid format specifier for a string.

Write a file from a single thread

#include <fmt/os.h>

int main() {
  auto out = fmt::output_file("guide.txt");
  out.print("Don't {}", "Panic");
}

This can be 5 to 9 times faster than fprintf.

Print with colors and text styles

#include <fmt/color.h>

int main() {
  fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold,
             "Hello, {}!\n", "world");
  fmt::print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) |
             fmt::emphasis::underline, "Olá, {}!\n", "Mundo");
  fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::italic,
             "你好{}!\n", "世界");
}

Output on a modern terminal with Unicode support:

image

Benchmarks

Speed tests

Library Method Run Time, s
libc printf 0.91
libc++ std::ostream 2.49
{fmt} 9.1 fmt::print 0.74
Boost Format 1.80 boost::format 6.26
Folly Format folly::format 1.87

{fmt} is the fastest of the benchmarked methods, ~20% faster than printf.

The above results were generated by building tinyformat_test.cpp on macOS 12.6.1 with clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT, and taking the best of three runs. In the test, the format string "%0.10f:%04d:%+g:%s:%p:%c:%%\n" or equivalent is filled 2,000,000 times with output sent to /dev/null; for further details refer to the source.

{fmt} is up to 20-30x faster than std::ostringstream and sprintf on IEEE754 float and double formatting (dtoa-benchmark) and faster than double-conversion and ryu:

image

Compile time and code bloat

The script bloat-test.py from format-benchmark tests compile time and code bloat for nontrivial projects. It generates 100 translation units and uses printf() or its alternative five times in each to simulate a medium-sized project. The resulting executable size and compile time (Apple clang version 15.0.0 (clang-1500.1.0.2.5), macOS Sonoma, best of three) is shown in the following tables.

Optimized build (-O3)

Method Compile Time, s Executable size, KiB Stripped size, KiB
printf 1.6 54 50
IOStreams 25.9 98 84
fmt 83652df 4.8 54 50
tinyformat 29.1 161 136
Boost Format 55.0 530 317

{fmt} is fast to compile and is comparable to printf in terms of per-call binary size (within a rounding error on this system).

Non-optimized build

Method Compile Time, s Executable size, KiB Stripped size, KiB
printf 1.4 54 50
IOStreams 23.4 92 68
{fmt} 83652df 4.4 89 85
tinyformat 24.5 204 161
Boost Format 36.4 831 462

libc, lib(std)c++, and libfmt are all linked as shared libraries to compare formatting function overhead only. Boost Format is a header-only library so it doesn't provide any linkage options.

Running the tests

Please refer to Building the library for instructions on how to build the library and run the unit tests.

Benchmarks reside in a separate repository, format-benchmarks, so to run the benchmarks you first need to clone this repository and generate Makefiles with CMake:

$ git clone --recursive https://github.com/fmtlib/format-benchmark.git
$ cd format-benchmark
$ cmake .

Then you can run the speed test:

$ make speed-test

or the bloat test:

$ make bloat-test

Migrating code

clang-tidy v17 (not yet released) provides the modernize-use-std-print check that is capable of converting occurrences of printf and fprintf to fmt::print if configured to do so. (By default it converts to std::print.)

Notable projects using this library

  • 0 A.D.: a free, open-source, cross-platform real-time strategy game
  • AMPL/MP: an open-source library for mathematical programming
  • Apple's FoundationDB: an open-source, distributed, transactional key-value store
  • Aseprite: animated sprite editor & pixel art tool
  • AvioBook: a comprehensive aircraft operations suite
  • Blizzard Battle.net: an online gaming platform
  • Celestia: real-time 3D visualization of space
  • Ceph: a scalable distributed storage system
  • ccache: a compiler cache
  • ClickHouse: an analytical database management system
  • Contour: a modern terminal emulator
  • CUAUV: Cornell University's autonomous underwater vehicle
  • Drake: a planning, control, and analysis toolbox for nonlinear dynamical systems (MIT)
  • Envoy: C++ L7 proxy and communication bus (Lyft)
  • FiveM: a modification framework for GTA V
  • fmtlog: a performant fmtlib-style logging library with latency in nanoseconds
  • Folly: Facebook open-source library
  • GemRB: a portable open-source implementation of Bioware's Infinity Engine
  • Grand Mountain Adventure: a beautiful open-world ski & snowboarding game
  • HarpyWar/pvpgn: Player vs Player Gaming Network with tweaks
  • KBEngine: an open-source MMOG server engine
  • Keypirinha: a semantic launcher for Windows
  • Kodi (formerly xbmc): home theater software
  • Knuth: high-performance Bitcoin full-node
  • libunicode: a modern C++17 Unicode library
  • MariaDB: relational database management system
  • Microsoft Verona: research programming language for concurrent ownership
  • MongoDB: distributed document database
  • MongoDB Smasher: a small tool to generate randomized datasets
  • OpenSpace: an open-source astrovisualization framework
  • PenUltima Online (POL): an MMO server, compatible with most Ultima Online clients
  • PyTorch: an open-source machine learning library
  • quasardb: a distributed, high-performance, associative database
  • Quill: asynchronous low-latency logging library
  • QKW: generalizing aliasing to simplify navigation, and execute complex multi-line terminal command sequences
  • redis-cerberus: a Redis cluster proxy
  • redpanda: a 10x faster Kafka® replacement for mission-critical systems written in C++
  • rpclib: a modern C++ msgpack-RPC server and client library
  • Salesforce Analytics Cloud: business intelligence software
  • Scylla: a Cassandra-compatible NoSQL data store that can handle 1 million transactions per second on a single server
  • Seastar: an advanced, open-source C++ framework for high-performance server applications on modern hardware
  • spdlog: super fast C++ logging library
  • Stellar: financial platform
  • Touch Surgery: surgery simulator
  • TrinityCore: open-source MMORPG framework
  • 🐙 userver framework: open-source asynchronous framework with a rich set of abstractions and database drivers
  • Windows Terminal: the new Windows terminal

More...

If you are aware of other projects using this library, please let me know by email or by submitting an issue.

Motivation

So why yet another formatting library?

There are plenty of methods for doing this task, from standard ones like the printf family of function and iostreams to Boost Format and FastFormat libraries. The reason for creating a new library is that every existing solution that I found either had serious issues or didn't provide all the features I needed.

printf

The good thing about printf is that it is pretty fast and readily available being a part of the C standard library. The main drawback is that it doesn't support user-defined types. printf also has safety issues although they are somewhat mitigated with __attribute__ ((format (printf, ...)) in GCC. There is a POSIX extension that adds positional arguments required for i18n to printf but it is not a part of C99 and may not be available on some platforms.

iostreams

The main issue with iostreams is best illustrated with an example:

std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n";

which is a lot of typing compared to printf:

printf("%.2f\n", 1.23456);

Matthew Wilson, the author of FastFormat, called this "chevron hell". iostreams don't support positional arguments by design.

The good part is that iostreams support user-defined types and are safe although error handling is awkward.

Boost Format

This is a very powerful library that supports both printf-like format strings and positional arguments. Its main drawback is performance. According to various benchmarks, it is much slower than other methods considered here. Boost Format also has excessive build times and severe code bloat issues (see Benchmarks).

FastFormat

This is an interesting library that is fast, safe and has positional arguments. However, it has significant limitations, citing its author:

Three features that have no hope of being accommodated within the current design are:

  • Leading zeros (or any other non-space padding)
  • Octal/hexadecimal encoding
  • Runtime width/alignment specification

It is also quite big and has a heavy dependency, on STLSoft, which might be too restrictive for use in some projects.

Boost Spirit.Karma

This is not a formatting library but I decided to include it here for completeness. As iostreams, it suffers from the problem of mixing verbatim text with arguments. The library is pretty fast, but slower on integer formatting than fmt::format_to with format string compilation on Karma's own benchmark, see Converting a hundred million integers to strings per second.

License

{fmt} is distributed under the MIT license.

Documentation License

The Format String Syntax section in the documentation is based on the one from Python string module documentation. For this reason, the documentation is distributed under the Python Software Foundation license available in doc/python-license.txt. It only applies if you distribute the documentation of {fmt}.

Maintainers

The {fmt} library is maintained by Victor Zverovich (vitaut) with contributions from many other people. See Contributors and Releases for some of the names. Let us know if your contribution is not listed or mentioned incorrectly and we'll make it right.

Security Policy

To report a security issue, please disclose it at security advisory.

This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure.

fmt's People

Contributors

0x8000-0000 avatar alabuzhev avatar alexezeder avatar brevzin avatar carterli avatar chronoxor avatar danielae avatar dean0x7d avatar denchat avatar dependabot[bot] avatar dimztimz avatar eliaskosunen avatar foonathan avatar gsjaardema avatar hazardyknusperkeks avatar jgopel avatar jk-jeon avatar joycebrum avatar luncliff avatar medithe avatar mwinterb avatar neheb avatar nioshd avatar orivej avatar pauldreik avatar phprus avatar rimathia avatar shawnzhong avatar vertexwahn avatar vitaut avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fmt's Issues

Compile error when using WStringRef with <<bool

Hi, thanks for your library! I'm just evaluating it for logging purposes and came across one problem. When trying wide char version of the format string:

auto x = fmt::str(fmt::Format(L"{}") << true);
or
std::wstring xx = fmt::str(fmt::Format(L"{}") << std::wstring(L"wstring"));

I got compile time error (VC2010), complaining that:

  void Write(const std::basic_string<char> &s, ...) doesn't accept std::basic_string<wchar_t>

works fine once I changed Write method to this:

  template <typename Char>
  void Write(const std::basic_string<Char> &s, const FormatSpec &spec) {
    FormatString(s.data(), s.size(), spec);
  }

The library looks exactly what I was looking for: replacement-based API (without a need to specify type in format string), type-safe, super fast and small.
For logging purposes, however, it would be nice to be able to turn-off exceptions (replaced by debug assert() + "bad format" result?) instead of try/catch the fmt::Format calls. Have you considered header-only version?
Thanks again
Filip Jerabek

Printf like checks

some compilers (gcc,clang) can check printf like functions
in Os X it works like this

int printf(const char * __restrict, ...) __printflike(1, 2);

int sprintf(char * __restrict, const char * __restrict, ...) __printflike(2, 3);
int sscanf(const char * __restrict, const char * __restrict, ...) __scanflike(2, 3);
int vsprintf(char * __restrict, const char * __restrict, va_list) __printflike(2, 0);

int snprintf(char * __restrict, size_t, const char * __restrict, ...) __printflike(3, 4);
int vsnprintf(char * __restrict, size_t, const char * __restrict, va_list) __printflike(3, 0);

define __printflike(fmtarg, firstvararg) \

    __attribute__((__format__ (__printf__, fmtarg, firstvararg)))

i fink it good idea to add something similar to your library

you can take some additional information here https://mail-index.netbsd.org/tech-userlevel/2012/03/04/msg006197.html

Add support for printf format specification

Currently the C++ Format library uses format string syntax based on Python's str.format. It should be pretty easy to add support for printf's string syntax for legacy code.

Support char as number

This should return 0x61, but instead fails saying it needs a numeric type instead of a character type.

fmt::format("0x{0:02X}", 'a'); // Crashes

This, however, succeeds:

fmt::format("0x{0:02X}\n", (int)'a'); // Returns 0x61

build error with intel c compiler (c++11)

I've been trying to compile your library with intel c compiler and -std=c++11 flag enabled:

format.cc(55): error: more than one instance of overloaded function "signbit" matches the argument list:
function "signbit(double)"
function "std::signbit(double)"
argument types are: (double)
return signbit(value);
^

compilation aborted for format.cc (code 2)

$ icc -v
$ icc version 14.0.2 (gcc version 4.6.0 compatibility)

with -std=gnu++98 (default) everything is good.

Warnings on older GCC

/home/travis/build/cppformat/format/format.h:91:19: warning: ISO C++ 1998 does not support ‘long long’ [-Wlong-long]
/home/travis/build/cppformat/format/format.h:92:19: warning: ISO C++ 1998 does not support ‘long long’ [-Wlong-long]

https://travis-ci.org/cppformat/format

Missing support for std::wstring in BasicFormatter::Arg

BasicFormatter::Arg has a constructor from a std::string, but not a constructor from a std::wstring; this leads to std::wstring being treated as a custom type.

Arg(const std::string &value) : type(STRING), formatter(0) {
      string.value = value.c_str();
      string.size = value.size();
    }

I'm not sure if the correct solution is to add a second constructor for std::wstring:

Arg(const std::wstring &value) : type(STRING), formatter(0) {
      string.value = value.c_str();
      string.size = value.size();
    }

Or whether to use std::basic_string (which will automatically add the correct type of STL constructor based on the current char type of the formatter):

Arg(const std::basic_string<Char> &value) : type(STRING), formatter(0) {
      string.value = value.c_str();
      string.size = value.size();
    }

However both worked when I tried them.

Support for {0:02X}, 'y'

I'm still getting an error here when calling fmt::format("{0:02X}", 'x'); and I think it's because it's not liking the number alignment, but... 'x' is a number in this case.

    // format.cc:444
    if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
      throw FormatError("invalid format specifier for char");

Inconsistent naming of action classes

Action classes are named inconsistently:

  • NoAction
  • Write
  • ColorWriter

Also there should be clear distinction between writer and action classes.

As the action classes are rarely used explicitly, their names can be fairly verbose, e.g. EmptyAction, FileWriteAction, ColoredWriteAction or something like that.

Xcode 6 beta 6 util-test crash

Here's how to reproduce:

  1. mkdir build && cd build && cmake -G Xcode ..
  2. Open Xcode build project, and run util-test target.

Here's the crash report:

Process:         util-test [99663]
Path:            /Users/USER/Desktop/*/util-test
Identifier:      util-test
Version:         0
Code Type:       X86-64 (Native)
Parent Process:  util-test [99660]
Responsible:     Xcode [99349]
User ID:         501

Date/Time:       2014-08-21 08:49:37.471 -0700
OS Version:      Mac OS X 10.9.4 (13E28)
Report Version:  11
Anonymous UUID:  A313BD1C-E57C-0B66-D31B-15AC4B26A391

Sleep/Wake UUID: 8804A7BB-AD23-4561-B5BC-CE0436895581

Crashed Thread:  0  Dispatch queue: com.apple.main-thread

Exception Type:  EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000

Application Specific Information:
crashed on child side of fork pre-exec

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib          0x00007fff8a95d866 __pthread_kill + 10
1   libsystem_pthread.dylib         0x00007fff93e7235c pthread_kill + 92
2   libsystem_c.dylib               0x00007fff8fb48b1a abort + 125
3   libsystem_c.dylib               0x00007fff8fb1298e __assert_rtn + 272
4   util-test                       0x000000010005681f fmt::internal::StrError(int, char*&, unsigned long) + 111 (format.cc:263)
5   util-test                       0x00000001000020a4 UtilTest_StrError_Test::TestBody() + 580 (util-test.cc:141)
6   util-test                       0x000000010004bf13 void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) + 131 (gtest.cc:2090)
7   util-test                       0x0000000100038267 void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) + 119 (gtest.cc:2126)
8   util-test                       0x000000010001e475 testing::Test::Run() + 197 (gtest.cc:2161)
9   util-test                       0x000000010001f5ab testing::TestInfo::Run() + 219 (gtest.cc:2338)
10  util-test                       0x0000000100020387 testing::TestCase::Run() + 231 (gtest.cc:2444)
11  util-test                       0x00000001000276ee testing::internal::UnitTestImpl::RunAllTests() + 926 (gtest.cc:4236)
12  util-test                       0x0000000100048c53 bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) + 131 (gtest.cc:2090)
13  util-test                       0x000000010003a9e7 bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) + 119 (gtest.cc:2126)
14  util-test                       0x0000000100027334 testing::UnitTest::Run() + 100 (gtest.cc:3871)
15  util-test                       0x0000000100013a33 main + 51 (test-main.cc:43)
16  libdyld.dylib                   0x00007fff954985fd start + 1

How to use this library?

Is there an example how to use this library? I have downloaded 0.9.0 release, add two files in my vs2013 project solution: format.h and format.cc, then #include format.h in my program.
But I receive a lot of compile errors.
Should I use cmake before or it is not necessary?

Warning 1   warning C4627: '#include "format.h"': skipped when looking for precompiled header use   m:\projects\test\format.cс 34  1   test
Warning 2   warning C4603: '_CRT_SECURE_NO_WARNINGS' : macro is not defined or definition is different after precompiled header use m:\projects\test\format.cс 30  1   test
Warning 3   warning C4603: '_SCL_SECURE_NO_WARNINGS' : macro is not defined or definition is different after precompiled header use m:\projects\test\format.cс 32  1   test
Error   4   error C2653: 'fmt' : is not a class or namespace name   m:\projects\test\format.cс 52  1   test
Error   5   error C2873: 'ULongLong' : symbol cannot be used in a using-declaration m:\projects\test\format.cс 52  1   test
Error   6   error C3861: '_ecvt_s': identifier not found    m:\projects\test\format.cс 90  1   test
Error   7   error C3861: '_finite': identifier not found    m:\projects\test\format.cс 94  1   test
Error   8   error C2653: 'fmt' : is not a class or namespace name   m:\projects\test\format.cс 108 1   test
Error   9   error C2065: 'Writer' : undeclared identifier   m:\projects\test\format.cс 108 1   test
Error   10  error C2059: syntax error : ',' m:\projects\test\format.cс 108 1   test
Error   11  error C2065: 'FormatFunc' : undeclared identifier   m:\projects\test\format.cс 110 1   test
Error   12  error C2146: syntax error : missing ')' before identifier 'func'    m:\projects\test\format.cс 110 1   test
Error   13  error C2182: 'ReportError' : illegal use of type 'void' m:\projects\test\format.cс 110 1   test
Error   14  error C2653: 'fmt' : is not a class or namespace name   m:\projects\test\format.cс 111 1   test
Error   15  error C2059: syntax error : ')' m:\projects\test\format.cс 111 1   test
Error   16  error C2143: syntax error : missing ';' before '{'  m:\projects\test\format.cс 111 1   test
Error   17  error C2447: '{' : missing function header (old-style formal list?) m:\projects\test\format.cс 111 1   test
Error   18  error C2653: 'fmt' : is not a class or namespace name   m:\projects\test\format.cс 122 1   test
Error   19  error C2143: syntax error : missing ';' before '<'  m:\projects\test\format.cс 122 1   test
Error   20  error C2988: unrecognizable template declaration/definition m:\projects\test\format.cс 122 1   test
Error   21  error C2059: syntax error : '<' m:\projects\test\format.cс 122 1   test
Error   22  error C2039: 'FormatFloat' : is not a member of '`global namespace''    m:\projects\test\format.cс 122 1   test
Error   23  error C2039: 'size_t' : is not a member of 'std'    m:\projects\test\format.cс 123 1   test
Error   24  error C2653: 'fmt' : is not a class or namespace name   m:\projects\test\format.cс 136 1   test
Error   25  error C2039: 'FormatFloat' : is not a member of '`global namespace''    m:\projects\test\format.cс 136 1   test
Error   26  error C2039: 'size_t' : is not a member of 'std'    m:\projects\test\format.cс 137 1   test
Error   27  error C2143: syntax error : missing ';' before '{'  m:\projects\test\format.cс 138 1   test
Error   28  error C2447: '{' : missing function header (old-style formal list?) m:\projects\test\format.cс 138 1   test
Error   29  error C2653: 'fmt' : is not a class or namespace name   m:\projects\test\format.cс 149 1   test
Error   30  error C4430: missing type specifier - int assumed. Note: C++ does not support default-int   m:\projects\test\format.cс 167 1   test
Error   31  error C2653: 'fmt' : is not a class or namespace name   m:\projects\test\format.cс 167 1   test
Error   32  error C2146: syntax error : missing ';' before identifier 'POWERS_OF_10_32' m:\projects\test\format.cс 167 1   test
Error   33  error C4430: missing type specifier - int assumed. Note: C++ does not support default-int   m:\projects\test\format.cс 168 1   test
Error   34  error C2653: 'fmt' : is not a class or namespace name   m:\projects\test\format.cс 168 1   test
Error   35  error C2146: syntax error : missing ';' before identifier 'POWERS_OF_10_64' m:\projects\test\format.cс 168 1   test
Error   36  error C3861: 'ULongLong': identifier not found  m:\projects\test\format.cс 171 1   test
Error   37  error C1903: unable to recover from previous error(s); stopping compilation m:\projects\test\format.cс 171 1   test

Improve error reporting

Formatters need a more consistent approach to error reporting. Currently there are three ways to report a format error:

  1. Throw FormatError immediately.
  2. Set FormatterBase::error_ which is checked at the end of formatting and FormatError is thrown if it is set.
  3. Use report_error_ (BasicFormatter only).

An important question is whether we want to report errors as soon as they are found or have the ability to override an earlier error with a later, but more important one. The first case is simpler, we just throw FormatError as soon as an error is found. The second case requires keeping track of an error which complicates the logic.

It seems that Python's str.format uses the first approach. The only case I found were a later error seem to override an earlier one is the case of unbalanced braces, for example:

>>> '{-1:'.format(42)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: unmatched '{' in format

However, this is probably because str.format processes nested arguments first, so it's not really an exception from the rule.

The printf function has rudimentary error checking. For example, neither of the following is reported as an error:

  printf("%s")
  printf("%d", "a");

A rare case of an error caught by printf:

 printf("%10000000000d", 0);

This sets errno to EOVERFLOW which gives generic error message "Value too large for defined data type".

Considering that

  • pretty much any error reporting is an improvement on printf's
  • format strings are usually small which makes it easy to locate errors

I think it makes sense to go with option 1 which is the simplest.

Terminate character

Current version of FormatInt class set terminating '\0' character automatically. I think it's better to follow principle don't pay for what you don't use and let user set '\0' when he really wants it.

Compiling errors VC2010 , QT4.8

Not sure what is causing this error or what compilerbut a similar problem is described here:
http://heifner.blogspot.co.uk/2008/02/stdmin-and-stdmax.html.

I have manage to get it to compile by:
using namespace std;
and changing std::max to max on line 106 and 662 of format.h.

Here's the original compile error. there are also warnings shown with this fix.

M:\mmgit\mmcyb\inc\format.h(106): error C2589: '(' : illegal token on right side of '::'
1> M:\mmgit\mmcyb\inc\format.h(105) : while compiling class template member function 'void fmt::internal::Array<T,SIZE>::Grow(size_t)'
1> with
1> [
1> T=char,
1> SIZE=500
1> ]
1> M:\mmgit\mmcyb\inc\format.h(425) : see reference to class template instantiation 'fmt::internal::Array<T,SIZE>' being compiled
1> with
1> [
1> T=char,
1> SIZE=500
1> ]
1> M:\mmgit\mmcyb\inc\format.h(872) : see reference to class template instantiation 'fmt::BasicWriter' being compiled
1> with
1> [
1> Char=char
1> ]
1> M:\mmgit\mmcyb\inc\format.h(1128) : see reference to class template instantiation 'fmt::BasicFormatter' being compiled
1> with
1> [
1> Char=char
1> ]
1>M:\mmgit\mmcyb\inc\format.h(106): error C2059: syntax error : '::'
1>M:\mmgit\mmcyb\inc\format.h(106): error C2589: '(' : illegal token on right side of '::'
1> M:\mmgit\mmcyb\inc\format.h(105) : while compiling class template member function 'void fmt::internal::Array<T,SIZE>::Grow(size_t)'
1> with
1> [
1> T=const fmt::BasicFormatter::Arg *,
1> SIZE=10
1> ]
1> M:\mmgit\mmcyb\inc\format.h(979) : see reference to class template instantiation 'fmt::internal::Array<T,SIZE>' being compiled
1> with
1> [
1> T=const fmt::BasicFormatter::Arg *,
1> SIZE=10
1> ]
1>M:\mmgit\mmcyb\inc\format.h(106): error C2059: syntax error : '::'
1>
1>Build FAILED.
1>
1>Time Elapsed 00:00:00.98

Missing initializer_list header in VS2012 (Update 4)

VS 2012 (Update 4) doesn't have the initializer_list header and fails to compile because of the FMT_USE_INITIALIZER_LIST test.

There's a workaround for VS2012, but it's still in some alpha stage. I'd suggest changing the minimum version to 1800 (VS 2013).

32bit performance

64bit build:

1: Converting 14 long long with 10 base-10 digits (no sign) to buffer 300 bytes
1: sizeof(short, int, long, long long): 2 4 8 8
1: Run tests #1 #2 #3 #4 #5 Results: 
1:                       (!) fmt::FormatInt [avg:26419050 var:0.0692767% ms:26 runs:50 conv_ops:49999600]
1:             (+183%) boost::spirit::karma [avg:74907132 var:0.162081% ms:74 runs:50 conv_ops:49999600]

32bit build:

1: Converting 14 long long with 10 base-10 digits (no sign) to buffer 300 bytes
1: sizeof(short, int, long, long long): 2 4 4 8
1: Run tests #1 #2 #3 #4 #5 Results: 
1:                       (!) fmt::FormatInt [avg:115024795 var:0.554144% ms:115 runs:50 conv_ops:49999600]
1:              (+98%) boost::spirit::karma [avg:228828029 var:0.15578% ms:228 runs:50 conv_ops:49999600]

In some cases boost::karma works better:

1: Converting 25 int with 4 base-10 digits to buffer 300 bytes
1: sizeof(short, int, long, long long): 2 4 4 8
1: Run tests #1 #2 #3 #4 #5 Results: 
1:                    (+75%) fmt::FormatInt [avg:45775614 var:0.0263464% ms:45 runs:50 conv_ops:50000000]
1:                 (!) boost::spirit::karma [avg:26063573 var:1.59616% ms:26 runs:50 conv_ops:50000000]

It's probably because every type converting to uint64_t. May be template parameter is more appropriate?

32bit: https://s3.amazonaws.com/archive.travis-ci.org/jobs/19018932/log.txt
64bit: https://s3.amazonaws.com/archive.travis-ci.org/jobs/19018934/log.txt

Support for variadic version of the Format function

The stream operator << dosen't work as expected, based on the use being equivalent to std::ostream.

fmt::Formatter<> msg = fmt::Format(format);
msg << arg1;
msg << arg2;
...
msg << argN;
result = fmt::str(msg);

throws exception, to many formatting tokens on the second line, as it immediately attempts to format the string, but not all arguments have been passed.

P.S. I need to use this method as my code is actually

template<typename... Args> inline std::string const & Format(std::string const &format,Args const & ... args) {
        fmt::Formatter<> msg = fmt::Format(format);
        RescursiveFormat(msg,args...);
        return *new std::string(fmt::str(msg)); }

Where RescursiveFormat(msg,args...); reduce to (by template meta programing, and compiler optimization)

msg << arg1;
msg << arg2;
...
msg << argN;

For however may arguments are passed.

This allows formatting to be done by
Format(<format_string>,...) i.e. like sprintf, by type-safe, and using format as the underlining formatting method.

Uppercase versions of base prefixes 0X and 0B

Clarify in the documentation that '#' used together with 'X' adds prefix "0X" (note uppercase 'X') to the output value. Similarly 'B' specifier that adds prefix '0B' should be added. See also #4

Are all tests supposed to be "passed"?

I just built everything from the master today on Win8.1-64 with mingw64 GCC4.9 and running the test EXEs produced a number of "failed" tests. Are they supposed to fail or should all be green and "passed"?

Warnings when compiling in Visual Studio 2012

Hi,

Firstly thanks for the library, it will help me produce better error messages!

I am very new to C++ in general so I may be doing something very wrong but after adding the header and the code file I get 47 warnings all of the types:

Warning 1 warning C4521: 'fmt::BasicFormatter' : multiple copy constructors specified d:\light bot\code\lightbot\lightbot\3rdparty\format\format.h 1015 1 LightBot
Warning 2 warning C4521: 'fmt::Formatter<>' : multiple copy constructors specified d:\light bot\code\lightbot\lightbot\3rdparty\format\format.h 1138 1 LightBot
Warning 3 warning C4521: 'fmt::BasicFormatter' : multiple copy constructors specified d:\light bot\code\lightbot\lightbot\3rdparty\format\format.h 1015 1 LightBot
Warning 4 warning C4521: 'fmt::Formatter<Action,Char>' : multiple copy constructors specified d:\light bot\code\lightbot\lightbot\3rdparty\format\format.h 1138 1 LightBot

I don't believe I am doing something wrong? Additionally is the library cross platform?

Exception in FromatDouble if buffer.capacity == offset

// Format using snprintf.
Char fill = static_cast<Char>(spec.fill());
for (;;) {
    std::size_t size = buffer_.capacity() - offset;
    Char *start = &buffer_[offset];
    int n = internal::CharTraits<Char>::FormatFloat(start, size, format, width_for_sprintf, precision, value);

It is possible for size to be equal 0.
As a workaround , I added GrowBuffer(1000) and recalculated size again.

Buffer full behaviour under Visual Studio with formatDouble

sprintf_s calls the invalid_parameter_handler function if the buffer size does not fit the input, instead of directly returning the written count.
A fix could be to use instead _vsnprintf_s with _TRUNCATE to get an error return value.

Small test is:

fmt::Writer writer;
int i = 0;
while ( i++ < 130 )
{
  std::cout << i << std::endl;
  writer << 1.01;
}

This fails with Visual Studio.

Add support for formatting via variadic templates where possible

I feel that C++11 variadic templates would provide a nice alternative to the streaming syntax that format uses by default.

I've implemented a version of this for my own project, and have had a go at rolling it back into format itself in a more generic form.

The change can be found here: https://github.com/jdale88/format/commit/5a2eb12a783246f87c1a0d1b5355fe8df22ec6d2

At present, the syntax for using that change is as follows (it will accept any number of parameters after the initial format string):

std::string str = fmt::VariadicFormat<fmt::Formatter<>>("Hello {0}", "World");
std::wstring wstr = fmt::VariadicFormat<fmt::Formatter<fmt::NoAction, wchar_t>>(L"Hello {0}", L"World");

I felt it best to discuss this feature before submitting a pull request, as it might be completely unsuitable, or you might want to approach it differently. This bug is really just to open up a discussion about it.

Thanks.

EDIT:
I improved upon that initial commit a bit.

std::string str = fmt::Format("Hello {0}", "World");
std::wstring wstr = fmt::Format(L"Hello {0}", L"World");

Small issues in docs

Hi, interesting to set yet another take on this problem :)

I had a look at the docs out of curiosity and have a few comments (maybe I am
just expecting too much, since this library seems to be only a few hours old!)

Support for user-defined types

I wanted to see how you achieved this, but I can't see that it works as
expected. For instance, the following is a compile error:

format::Print("a string: {0}\n") << std::string("asdf");

I thought about implementing positional arguments in tinyformat, and the best
solution I came up with involved a type of variant class as follows:

class Arg
{
    public:
        virtual void print(std::ostream& out) = 0;
};

template<typename T>
class ArgT : public Arg
{
    const T& m_value;
    public:
        virtual void print(std::ostream& out)
        {
            out << m_value;
        }
};

You'd then construct a std::vector<Arg*> as you sweep through the arguments,
creating an ArgT for the Nth argument. (The could be stack-allocated
in the tinyformat case, though unfortunately not with the << based interface.)
Reordering can then be achived simply using indexing.

In the end I didn't do it because I didn't need the functionality and it would
introduce some extra complexity to tinyformat, which is alreay a lot less tiny
than I would like ;-) It also means a virtual function call per argument which
is less than ideal...

i18n in printf
posix printf does have a notation to support positional arguments for i18n,
and this is implemented in glibc even though it's not in C99. For example,
try out:

printf("%2$s  %1$s\n", "first_arg", "second_arg");

Good luck with your implementation!
~Chris

Benchmark against Karma needed

Hi,

I've found the speed-test below on another library page where a guy compared "format" (not a unique name btw.) against Boost Karma, among others. And Karma generally was either as fast as format or even faster.

I would love to see how you benchmark this and how you explain this. Thanks in advance.

------------------------------------snip--------------------------------------
Well, README.md of project https://github.com/vitaut/format
reference to spirit.karma, but I don't have any speed test results, so
I've cloned your project and find only one test called int-generator.
I've tested it on Visual Studio 2013 x64 compiler with full optimization (/Ox):

cl /c /W3 /WX- /Ox /Ob2 /D WIN32 /D _WINDOWS /D NDEBUG /D HAVE_BOOST /D "CMAKE_INTDIR="Release"" /D _MBCS /Gm- /EHsc /MD /GS /fp:precise /Zc:wchar_t /Zc:forScope /GR /Fo"format.dir\Release" /Fd"format.dir\Release\vc120.pdb" /Gd /TP /errorReport:prompt ..\format.cc

cl /c /W3 /WX- /Ox /Ob2 /D WIN32 /D _WINDOWS /D NDEBUG /D HAVE_BOOST /D "CMAKE_INTDIR="Release"" /D _MBCS /Gm- /EHsc /MD /GS /fp:precise /Zc:wchar_t /Zc:forScope /GR /Fo"int-generator.dir\Release" /Fd"int-generator.dir\Release\vc120.pdb" /Gd /TP /errorReport:prompt "....\format-benchmark\int_generator.cpp"

Results (MAX_ITERATION = 1e8):

ltoa: 12.3518 [s]
sprintf: 23.7584 [s]
sprintf+std::string: 25.3529 [s]
std::stringstream: 71.6845 [s]
std::to_string: 28.8839 [s]
boost::lexical_cast: 14.7594 [s]
karma::generate: 4.68553 [s]
karma::generate+std::string: 6.09963 [s]
fmt::Writer: 3.75357 [s]
fmt::Writer+std::string: 6.60581 [s]
fmt::Format: 10.4957 [s]
fmt::Format+std::string: 13.3467 [s]
fmt::FormatInt: 3.61697 [s]
cppx::decimal_from: 3.82345 [s]

As you can see boost libraries lexical_cast and karma are "among the slickest and fastest".
lexical_cast is twice faster then c-style sprintf and STL-style stringstream and to_string
and only ~20% slower then c-style ltoa.

Boost.karma already works better then fmt::* with std::string:

karma::generate+std::string: 6.09963 [s]
fmt::Writer+std::string: 6.60581 [s]
fmt::Format+std::string: 13.3467 [s]

Boost.karma works about twice faster than fmt::Format:
karma::generate: 4.68553 [s]
fmt::Format: 10.4957 [s]

FormatInt is not working with int64 type (ostringstream, to_string, boost.karma and boost.lexical_cast works fine).

So only fmt::Writer is rest:
karma::generate: 4.68553 [s]
fmt::Writer: 3.75357 [s]

Let's test it with little numbers. Patched fill function:

struct random_fill {
int operator()() const {
int scale = std::rand() / 100 + 1;

  •  return ((std::rand() \* std::rand()) / scale);
    
  •  return ((std::rand() \* std::rand()) / scale) % 100;
    
    }
    };

Voila!

karma::generate: 1.35417 [s]
fmt::Writer: 1.88881 [s]

And modulus 10:

struct random_fill {
int operator()() const {
int scale = std::rand() / 100 + 1;

  •  return ((std::rand() \* std::rand()) / scale) % 10;
    
  •  return ((std::rand() \* std::rand()) / scale);
    
    }
    };

Result (karma twice faster!):
karma::generate: 0.855458 [s]
fmt::Writer: 1.61517 [s]

Inconsistency in the Writer class?

I tried this with today's master:

fmt::Writer wo;
wo.write ("The answer in hexadecimal is {}", fmt::hex (1337) );
wo << "The answer in hexadecimal is (" << fmt::hex (1337) << ")";

The streaming example with the << operator worked fine, but the wo.write() failed. Shouldn't both be possible? And if not, for what reason?

cppformat usage for localization

I'm going to add localization in the project https://github.com/HarpyWar/pvpgn, and I find your library is well suited for this purpose.

Now I use code like this:

fmt::Formatter<> localize(t_connection c, const char *format)
{
    // localization stuff here (t_connection is needed to get user language)
    ...
    fmt::Formatter<> f(format);
    return f;
}

std::string text = str(localize(c, "Account {} has been muted.") << username);

Is there way to avoid additional str wrapper? I'm not a good C++ programmer and I just want to make sure that I do it correctly, and there is no a better/shorter way like this:

std::string text = localize(c, "Account {} has been muted.") << username;
   or
std::string text = localize(c, "Account {} has been muted.", username);

Latest version of format package does not compile with C++98

/format.h: In function 'fmt::Formatter<fmt::NoAction, char> fmt::Format(fmt::StringRef)':
/format.h:1112: error: 'fmt::Formatter<Action, Char>::Formatter(const fmt::Formatter<Action, Char>&) [with Action = fmt::NoAction, Char = char]' is private
/format.h:1226: error: within this context
/format.h: In function 'fmt::Formatter<fmt::NoAction, wchar_t> fmt::Format(fmt::WStringRef)':
/format.h:1112: error: 'fmt::Formatter<Action, Char>::Formatter(const fmt::Formatter<Action, Char>&) [with Action = fmt::NoAction, Char = wchar_t]' is private
/format.h:1230: error: within this context
/format.h: In function 'fmt::Formatter<fmt::Write, char> fmt::Print(fmt::StringRef)':
/format.h:1112: error: 'fmt::Formatter<Action, Char>::Formatter(const fmt::Formatter<Action, Char>&) [with Action = fmt::Write, Char = char]' is private
/format.h:1246: error: within this context
In file included from /format.cc:34:
/format.h: In function 'fmt::Formatter<fmt::NoAction, char> fmt::Format(fmt::StringRef)':
/format.h:1112: error: 'fmt::Formatter<Action, Char>::Formatter(const fmt::Formatter<Action, Char>&) [with Action = fmt::NoAction, Char = char]' is private
/format.h:1226: error: within this context
/format.h: In function 'fmt::Formatter<fmt::NoAction, wchar_t> fmt::Format(fmt::WStringRef)':
/format.h:1112: error: 'fmt::Formatter<Action, Char>::Formatter(const fmt::Formatter<Action, Char>&) [with Action = fmt::NoAction, Char = wchar_t]' is private
/format.h:1230: error: within this context
/format.h: In function 'fmt::Formatter<fmt::Write, char> fmt::Print(fmt::StringRef)':
/format.h:1112: error: 'fmt::Formatter<Action, Char>::Formatter(const fmt::Formatter<Action, Char>&) [with Action = fmt::Write, Char = char]' is private
/format.h:1246: error: within this context

error C2039: 'Format' : is not a member of 'fmt::BasicWriter<Char>'

I have tried this code from the examples
fmt::Writer out;
out << "The answer is " << 42 << "\n";
out.Format("({:+f}, {:+f})") << -3.14 << 3.14;

it gives the error:

m:\mmgit\mmcyb\src\mm\cmmaxes.cpp(307): error C2039: 'Format' : is not a member of 'fmt::BasicWriter'
3> with
3> [
3> Char=char
3> ]

C++11 support

Hello

Is an upgrade using new C++11 features si to be expected ? I believe some parts of the code could be replaced by new standard templates, particularly regarding the traits (IsDouble and things like that).

A compile-time parsing of the format strings using constexpr features could be done, but that is a more tricky part.

Improve function naming consistency.

Currently there is an inconsistency in function naming. Some functions are named according to Google C++ Style Guide:

  • Format
  • Print
  • Clear
  • ReportSystemError
    ...

Other follow standard library conventions:

  • c_str
  • str
  • clear
  • resize
  • reserve
  • printf
  • sprintf
    ...

The names should be unified before the version 1.0 of the API is released. This is pretty arbitrary, but it's probably better to follow standard library conventions for public API for consistency with printf and because its done already for most functions.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.