Compare commits

..

601 Commits
4.1.0 ... 5.1.0

Author SHA1 Message Date
Victor Zverovich
c2ce7e4f07 Update version 2018-07-05 06:22:54 -07:00
Victor Zverovich
434eb9167e Update README.rst 2018-07-04 18:07:17 -07:00
Victor Zverovich
09d94162f9 Update changelog 2018-07-04 17:47:46 -07:00
Florin Iucha
e6362642cf Fix pedantic conversion warning 2018-07-04 17:45:28 -07:00
Victor Zverovich
f0110e8125 Update changelog and CI 2018-07-04 17:43:07 -07:00
Victor Zverovich
479ee2a8c6 Fix MSVC build, take 2 2018-07-04 14:24:07 -07:00
Victor Zverovich
e928b6724c Fix MSVC 2013 build 2018-07-04 12:33:15 -07:00
Dhruv Paranjape
ec218a3ad1 Fix redefinition warning for RESET_COLOR 2018-07-04 07:52:19 -07:00
Victor Zverovich
c04fb91b03 Fix handling of user-defined types in format_to (#793) 2018-07-04 07:40:56 -07:00
Victor Zverovich
323b92bffe Force linking of inline functions into the library (#795) 2018-07-03 19:10:23 -07:00
Jonathan Müller
c6d9730ddb Fix sign conversion warnings (#790) 2018-06-27 14:31:20 +02:00
Victor Zverovich
2e95823ef7 Move new color support to format.h and mark old as deprecated 2018-06-24 06:39:22 -07:00
Victor Zverovich
ab2d88ca8e Make format_to work with basic_memory_buffer (#776) 2018-06-23 08:29:26 -07:00
Victor Zverovich
3abd036c47 Fix compilation on gcc 4 2018-06-23 07:18:59 -07:00
Victor Zverovich
c2f3805488 Add vformat_to_n (#769) 2018-06-23 07:03:00 -07:00
Remotion
ce500635c7 Renamed enum color to colors.
Added enum colors conversion to rgb struct.
Added colors_test.cpp.

Removed print_colored.
Renamed enum colors back to color.

Removed unnecessary inline keyword.
Removed print_rgb.
2018-06-23 06:14:44 -07:00
Victor Zverovich
0508bbc7ae Add wchar_t overload of format_to_n (#764) 2018-06-13 08:24:32 +02:00
gabime
c2fbadb9cf Fixed issue #779 2018-06-12 07:39:44 +02:00
Remotion
47268ecd80 Fixed GCC version test 2018-06-10 20:35:38 +02:00
Victor Zverovich
9ff3b6af2e Fix handling of compile-time strings when including ostream.h (#768) 2018-06-10 19:05:27 +02:00
Victor Zverovich
e3707ef14b Document that file should be in wide-oriented mode for wide print 2018-06-09 09:12:49 +02:00
Victor Zverovich
45fa4ee949 Merge branch 'master' of github.com:fmtlib/fmt 2018-06-08 21:43:56 +02:00
Remotion
9c07b37fff Using enum class now.
Renamed from hex to color.
Changed colr names to snake case.
2018-06-08 21:40:35 +02:00
Remotion
5b5886a993 Fixed line length. 2018-06-08 19:48:41 +02:00
Remotion
d2bfee13e2 Added quotes for strings in ranges and tuple likes. 2018-06-08 19:48:41 +02:00
Remotion
aff6e45e14 Added support for rgb color output. 2018-06-07 22:49:16 +02:00
Victor Zverovich
1b8a7f8fa0 Fix postincrement in truncating and counting iterators 2018-06-07 20:20:36 +02:00
Victor Zverovich
4bc26f0a7b Merge branch 'master' of github.com:fmtlib/fmt 2018-06-07 18:42:30 +02:00
Victor Zverovich
fc6e0fe992 Fix FP formatting to a non-back_insert_iterator with sign & numeric alignment (#756) 2018-06-07 18:41:40 +02:00
Dror Levin
cd5b5670ba Make is_range and is_tuple_like public API, fix #751 2018-06-06 21:49:14 +02:00
Victor Zverovich
6322b47e60 Minor cleanup 2018-06-06 16:51:35 +02:00
Elias Kosunen
691a7a91a1 Add more compilers to CI and increase FMT_PEDANTIC warning levels (#736)
* Add a _lot_ more warnings to FMT_PEDANTIC
Fix these warnings

* Add more compilers to CI
Fix (some) of the compiler errors with them

* Enable -Werror on CI
Increase warning level on MSVC when compiling with FMT_PEDANTIC

* Add VS 2013 and 2015 to Appveyor

* Fix Appveyor tests
Formatting

* Implement requested changes
Fix some of the MSVC warnings
Implement C++11 integer_sequence

* Reintroduce appveyor-build.py

* Remove ranges-test from tests

* Remove (some) explicit warning suppressions
Fix C++ standard setting in CI

* Remove (some) explicit warning suppressions
Fix C++ standard setting in CI

* Fix test builds with C++11

* Enable pedantic warnings on tests

* Fix warnings from edits to master

* Cleanups

* Add C++11 support to ranges.h
Re-enable ranges-test
Fix a Visual Studio error about function not returning a value in printf.h
Fix a bug in .travis.yml
2018-06-06 15:57:59 +02:00
Victor Zverovich
dd1a5ef7f9 Let requests close the file 2018-06-05 16:58:02 +02:00
Victor Zverovich
d5c462596b Fix formatting of more than 15 named arguments (#754) 2018-06-05 08:32:28 +02:00
Victor Zverovich
47d147b65d Simplify the nvcc warning fix 2018-06-04 21:27:20 +02:00
Victor Zverovich
911a75114b Fix nvcc warnings (#752) 2018-06-04 21:00:28 +02:00
Victor Zverovich
94b476283c Fix docs 2018-06-04 19:56:22 +02:00
Victor Zverovich
252f11f85d Fix a bogus MSVC warning about unreachable code, take 2 2018-06-04 18:17:55 +02:00
Victor Zverovich
81d5663825 Fix more bogus MSVC warnings about unreachable code (#748) 2018-06-04 06:10:52 +02:00
Victor Zverovich
68f0ac8271 Fix a bogus MSVC warning about unreachable code 2018-06-03 08:03:56 +02:00
Victor Zverovich
b60a5c5d49 Improve floating-point formatting 2018-05-28 20:16:30 -07:00
Victor Zverovich
8dc2360b11 Fix a comment 2018-05-28 17:21:39 -07:00
Victor Zverovich
4e4b8570e5 Implement simple version of Grisu 2018-05-28 11:25:07 -07:00
Victor Zverovich
4027557958 Fix tests on 64-bit MSVC 2018-05-27 11:38:53 -07:00
Victor Zverovich
5c32aa411c Workaround a bug in MSVC 2018-05-27 11:18:27 -07:00
Victor Zverovich
468c243ca8 Add a function to get cached power of 10 2018-05-27 10:57:26 -07:00
Victor Zverovich
2f257b7291 Implement normalization and simplify power table 2018-05-27 08:04:30 -07:00
Victor Zverovich
6a5bb6e268 Move Android.mk to support and update 2018-05-27 06:20:54 -07:00
Victor Zverovich
e282d963fe Bump version 2018-05-26 09:46:59 -07:00
Victor Zverovich
e2cd521b8f Fix incorrect call to on_align in '{:}=' (#750) 2018-05-26 09:23:09 -07:00
Victor Zverovich
fba352a92a Don't use UDL templates on Intel C++ compiler (#742) 2018-05-26 08:07:45 -07:00
Victor Zverovich
6dcc526d5b Update release script 2018-05-26 07:02:49 -07:00
Victor Zverovich
5386f1df20 Update version 2018-05-21 21:00:04 -07:00
Victor Zverovich
ba6640b257 Fix formatting 2018-05-21 20:50:23 -07:00
Victor Zverovich
507a50c3ad Fix changelog 2018-05-21 20:38:07 -07:00
Victor Zverovich
147807c911 Detect integer_sequence support on MSVC 2018-05-21 20:30:58 -07:00
Victor Zverovich
8b246531e6 Update changelog 2018-05-21 20:27:58 -07:00
Victor Zverovich
5ad54256c5 Fix a conflict between fmt::join and fmt/ostream.h (#744) 2018-05-21 20:21:06 -07:00
Victor Zverovich
6ebc1a967d Merge locale.h into format-inl.h 2018-05-20 17:16:34 -07:00
Victor Zverovich
6966db1dab Update docs 2018-05-20 17:10:34 -07:00
Victor Zverovich
2196025dd1 Fix a warning 2018-05-20 17:09:12 -07:00
Victor Zverovich
589f5f37b6 Update changelog 2018-05-20 16:00:39 -07:00
Victor Zverovich
edd5f1445d Fix compilation errors on gcc 4.4 2018-05-20 09:09:03 -07:00
Victor Zverovich
936aba5f90 Fix compilation errors on gcc 4.4 2018-05-20 07:42:09 -07:00
Victor Zverovich
3e3a27740e Update changelog 2018-05-19 11:46:55 -07:00
Victor Zverovich
b76bb79613 Improve naming consistency 2018-05-19 10:32:53 -07:00
Victor Zverovich
fbd5153487 Update changelog 2018-05-19 10:31:49 -07:00
Victor Zverovich
69823bf852 Improve naming consistency 2018-05-19 08:59:37 -07:00
Victor Zverovich
d940fa679c Disable unsafe implicit conversion to std::string (#729) 2018-05-19 07:14:27 -07:00
Victor Zverovich
d2bf93fe22 Update changelog 2018-05-19 07:13:06 -07:00
Michael Winterberg
550ef1d29d MSVC improvements and data truncation cleanup.
MSVC is timid about evaluating constexpr functions unless it has to, so the "TYPES" variables end up in read-write memory even though the optimizer removes the initializer. Making TYPES constexpr causes MSVC to try harder to initialize these variables at compile time, which also ends up completely removing the (named) variable from the final compiled binary.
Fixed a data truncation warning being reported in ostream-test.
2018-05-17 18:46:31 -07:00
Victor Zverovich
728e4f5a8d Fix docs 2018-05-16 08:26:55 -07:00
Victor Zverovich
8c2557710d Update docs and changelog 2018-05-16 07:58:53 -07:00
sv1990
a68fd44ecc Add ranges.h to FMT_HEADERS in CMakeLists.txt (#738) 2018-05-14 06:16:30 -06:00
Remotion
e3f7f3a2e9 Add support for ranges, containers and tuple-like types in fmt/ranges.h 2018-05-13 13:28:11 -07:00
Victor Zverovich
984232db15 Remove duplicate ChangeLog entries 2018-05-13 13:14:28 -07:00
Victor Zverovich
78677e3fcf Update ChangeLog and docs 2018-05-13 12:42:55 -07:00
Victor Zverovich
ad23270ec7 Document to_wstring 2018-05-13 09:11:29 -07:00
Victor Zverovich
3c0f8c2601 Update ChangeLog 2018-05-13 08:53:16 -07:00
Victor Zverovich
989378930a Detect inline namespaces on gcc 2018-05-13 08:53:04 -07:00
Victor Zverovich
dfb6546932 Fix docs 2018-05-13 08:04:39 -07:00
Victor Zverovich
3aa2911579 Update ChangeLog.rst 2018-05-13 08:02:06 -07:00
Victor Zverovich
d3f6c841c1 Update ChangeLog.rst 2018-05-13 07:22:41 -07:00
Victor Zverovich
c1441ae4c4 Update ChangeLog.rst 2018-05-12 16:02:20 -07:00
Victor Zverovich
dece85b31f Fix docs, take 2 2018-05-12 13:57:56 -07:00
Victor Zverovich
6a1df3bd05 Fix docs 2018-05-12 12:57:16 -07:00
Victor Zverovich
838400d29b Add inline namespace fmt::v5 2018-05-12 11:02:15 -07:00
Victor Zverovich
b64b24ebc5 Update ChangeLog.rst 2018-05-12 09:42:59 -07:00
Victor Zverovich
fc9087114f Update ChangeLog.rst 2018-05-12 09:10:11 -07:00
Victor Zverovich
46c374a8a9 Fix compilation with new gcc and -std=c++11 (#734) 2018-05-09 20:58:05 -07:00
Victor Zverovich
f0ae725721 Clarify the use of allocators 2018-05-09 06:43:54 -07:00
Victor Zverovich
d72d046254 Update paths in fmt.pro 2018-05-09 06:21:00 -07:00
Dan McGregor
edbbf7ce6c Fix FreeBSD 12
FreeBSD 12 changed the type of freelocale to the type defined by
POSIX. Check the FreeBSD version when building for FreeBSD.
2018-05-09 06:10:37 -07:00
Elias Kosunen
a4e4f74530 Fix a -Wundef when FMT_GCC_VERSION < 600 2018-05-09 06:09:25 -07:00
Victor Zverovich
7d3de49715 Implement double to fp conversion 2018-05-06 13:37:49 -07:00
Victor Zverovich
a4c7d99f70 Add bit_cast 2018-05-06 11:52:51 -07:00
Elias Kosunen
0adccaefb6 Fix a -Wundef of _LIBCPP_VERSION 2018-05-05 07:43:22 -07:00
Daniela Engert
2570f1afdc Provide more overloads for the wide string flavour
Signed-off-by: Daniela Engert <dani@ngrt.de>
2018-05-05 07:31:44 -07:00
Michael Winterberg
ca31ca13f1 Fixed arg_formatter_base::write_pointer to not mutate the format specs.
This fixes cases where arg_formatters are reused, like with arg_join.
2018-05-01 07:12:27 -07:00
Daniela Engert
6cd666100f remove trailing spaces.
Signed-off-by: Daniela Engert <dani@ngrt.de>
2018-05-01 07:10:05 -07:00
Victor Zverovich
fe19c266ce Move format_string to fmt namespace for ADL 2018-04-29 08:35:20 -07:00
Victor Zverovich
2768af2388 Add cached powers of 10 2018-04-29 06:33:05 -07:00
Victor Zverovich
dd296e1de0 Add a script to compute powers of 10 2018-04-28 14:32:05 -07:00
DanielaE
0efc8a1808 Fix compiler warning about narrowing
Signed-off-by: Daniela Engert <dani@ngrt.de>
2018-04-27 06:41:43 -07:00
Victor Zverovich
df1ba52b64 Update example 2018-04-22 17:04:28 -07:00
Victor Zverovich
221b08fd8f Merge branch 'master' of github.com:fmtlib/fmt 2018-04-22 09:16:34 -07:00
Victor Zverovich
fa9066fe3e context_base::begin -> out 2018-04-22 09:16:32 -07:00
Elias Kosunen
90ff31b38e Fix a -Wundef warning on clang
Resolves #715
2018-04-22 09:13:55 -07:00
Victor Zverovich
b1f68c43b5 Merge branch 'master' of github.com:fmtlib/fmt 2018-04-21 19:21:41 -07:00
Victor Zverovich
cd90097ca4 Implement handmade FP 2018-04-21 17:26:24 -07:00
Victor Zverovich
822eccc3b8 Sync API with standards proposal 2018-04-21 14:29:24 -07:00
Daniela Engert
2ae41242a5 allow time formatting with wchar_t contexts
change total specialization of 'struct formatter<std::tm>' into partial specialization 'template <typename Char> struct formatter<std::tm, Char>', backed by matching 'strftime'-like overloads
2018-04-18 18:55:49 -07:00
Victor Zverovich
a1579b0ff8 Update key 2018-04-16 18:22:03 -07:00
Victor Zverovich
ded921f0a2 Fix documentation build, take 2 2018-04-15 10:34:04 -07:00
Victor Zverovich
3284751f43 Fix documentation build 2018-04-15 09:49:37 -07:00
Victor Zverovich
bb738c4c26 Remove section on Write API since it's being superceeded by compile-time Format API 2018-04-15 09:13:44 -07:00
Victor Zverovich
d180c25c8f Update godbolt link 2018-04-15 06:19:38 -07:00
Victor Zverovich
1ed842a3b4 Update godbolt link 2018-04-14 12:41:08 -07:00
Victor Zverovich
e80aba1c2b Remove format_float stub 2018-04-14 12:40:53 -07:00
Victor Zverovich
7b8cb3135a Make context_base::args() public 2018-04-14 12:40:26 -07:00
Christian Parpart
48ae0506de fixes MSVC compiler warning bloat (Visual Studio 2017, latest updates) 2018-04-11 06:53:27 -07:00
Victor Zverovich
096c4051b2 Simplify char_traits 2018-04-08 13:38:12 -07:00
Victor Zverovich
7610c5362a Remove unused macro 2018-04-08 11:54:22 -07:00
Victor Zverovich
111fa5814b Update README.rst 2018-04-08 09:03:37 -07:00
Victor Zverovich
52fcef1e57 Update docs 2018-04-08 07:33:07 -07:00
Victor Zverovich
7d28674d3a make_args -> make_format_args 2018-04-08 07:21:26 -07:00
Victor Zverovich
9382b76f2a context_t -> format_context_t 2018-04-08 07:09:34 -07:00
Victor Zverovich
fd0b07a75a (w)context -> (w)format_context 2018-04-08 07:03:44 -07:00
Victor Zverovich
26aa34f319 basic_context -> basic_format_context 2018-04-08 06:45:21 -07:00
Victor Zverovich
44cc034651 Relax string_view requirements 2018-04-07 16:18:01 -07:00
Victor Zverovich
0829cab8f2 Remove from_checked 2018-04-07 15:21:48 -07:00
Victor Zverovich
cb7bbc6224 Improve checked iterator support 2018-04-07 15:11:34 -07:00
Victor Zverovich
5079f924d6 Fix a narrowing warning 2018-04-07 14:42:09 -07:00
Victor Zverovich
5859e58ba1 Fix msvc warnings 2018-04-04 21:11:31 -07:00
Victor Zverovich
1e747f603f Fix msvc warnings 2018-04-04 20:57:02 -07:00
Victor Zverovich
9d4efd7aa2 Iterator Wars VI: Return of the checked iterator 2018-04-04 20:15:02 -07:00
Victor Zverovich
9764f55891 Update docs 2018-04-04 07:53:19 -07:00
Victor Zverovich
4ef97b9bb2 Add a missing comma 2018-04-04 07:43:51 -07:00
Victor Zverovich
23759b2688 basic_arg -> basic_format_arg, arg_store -> format_arg_store 2018-04-04 07:38:21 -07:00
Victor Zverovich
4975297eb0 Simplify counting iterators 2018-03-31 07:47:30 -10:00
Victor Zverovich
e8e006f4e7 Fix compile checks for mixing narrow and wide strings (#690) 2018-03-30 09:29:47 -10:00
Victor Zverovich
c5ebecf7c6 Document format_to_n 2018-03-30 08:31:41 -10:00
Victor Zverovich
3cf0526316 Return output iterator to the end from format_to_n 2018-03-30 08:20:12 -10:00
Victor Zverovich
174087bfdb Implement format_to_n 2018-03-29 15:13:10 -10:00
Victor Zverovich
050f3f1f0e Remove parts of obsolete write API 2018-03-29 07:36:37 -10:00
Sebastian König
e90b1da367 Fix linker errors using fmt as shared library in MSVC 2018-03-28 07:14:56 -10:00
Victor Zverovich
8e10d404db Fix compile tests 2018-03-27 07:39:03 -10:00
Germán Méndez Bravo
7a41d61d79 Add make_printf_args
Fixes #687
2018-03-27 07:15:51 -10:00
Victor Zverovich
4fea018b2d Fix string_view detection 2018-03-26 07:00:41 -10:00
Victor Zverovich
6957d28cfb Detect string_view on libc++ (#686) 2018-03-26 06:50:22 -10:00
Victor Zverovich
0ea70defbe Update readme 2018-03-21 09:25:28 -07:00
Victor Zverovich
9ce5e30c06 Update readme 2018-03-21 09:15:28 -07:00
Victor Zverovich
8c29459eda Fix handling of empty string_view (#689) 2018-03-21 09:01:51 -07:00
Victor Zverovich
a24005d5fd Fix a narrowing warning 2018-03-21 08:29:06 -07:00
Victor Zverovich
3651b7fca6 Fix a narrowing warning 2018-03-21 07:59:42 -07:00
Victor Zverovich
b64486dae9 Add format.cc 2018-03-21 07:51:56 -07:00
Victor Zverovich
3da71d51e0 Move source files to the src directory 2018-03-21 07:50:59 -07:00
Victor Zverovich
7971ed3db3 Update readme 2018-03-21 06:48:36 -07:00
Victor Zverovich
f61ca2ec4f Update readme 2018-03-21 06:46:41 -07:00
Victor Zverovich
84e520b79c Update readme 2018-03-21 06:16:13 -07:00
Victor Zverovich
e8aa0f3315 Update docs 2018-03-21 06:12:10 -07:00
Victor Zverovich
17258e9c63 Update docs 2018-03-19 19:47:14 -07:00
Victor Zverovich
6d339e32a0 Improve comment 2018-03-16 16:26:31 -04:00
Victor Zverovich
c3d05245fe Fix a shadowing warning 2018-03-16 16:26:11 -04:00
Victor Zverovich
b58c8ddeb4 Update docs 2018-03-16 16:04:12 -04:00
Victor Zverovich
505b3ae66f Workaround GCC bug 67371 (#682) 2018-03-16 12:02:19 -04:00
Victor Zverovich
70dffc639a Remove unnecessary check 2018-03-15 09:58:26 -04:00
Victor Zverovich
df828f88da Don't define FMT_GCC_VERSION on clang 2018-03-15 09:55:31 -04:00
Victor Zverovich
42f70c8b4f Avoid narrowing casts 2018-03-15 09:45:31 -04:00
Elias Kosunen
10b939b096 Remove unneeded usage of anonymous struct on clang 2018-03-15 09:28:50 -04:00
Elias Kosunen
3adfaae20c Remove extra semicolon in format_args constructor 2018-03-15 09:28:50 -04:00
Jonathan Müller
4006678577 Fix warnings under MSVC (#679)
Closes #678.
2018-03-14 20:17:15 +01:00
johnthagen
9c5f54a723 Add format example for padded hex byte
Fixes #2
2018-03-13 23:05:48 -04:00
Victor Zverovich
7bab90e52d Remove extra comma 2018-03-13 22:45:14 -04:00
Victor Zverovich
2e21e7d1f1 Fix util-test 2018-03-13 22:20:06 -04:00
Vasili Galka
acb469ae2e Fixed UTF8/16 converters to support empty string input
Previously an exception was thrown since Win32 WideCharToMultiByte API
returns error on zero-length input.
2018-03-13 21:33:21 -04:00
Victor Zverovich
c37c4c437e Fix find-package-test 2018-03-13 14:13:39 -04:00
Mario Werner
6d21fc43b9 add alias targets with fmt namespace
For the consumer it should not matter if fmt has been added to the
project as subdirectory or via find_package. With the alias targets
the library can be always imported via fmt::fmt.
2018-03-13 13:51:48 -04:00
Victor Zverovich
e02aacc634 Add CMake namespace (#511) 2018-03-13 13:03:18 -04:00
Park DongHa
aee4512cc5 Gradle (#649)
* Gradle

Gradle support to make ease of import in Android Java projects.

* Gradle

Gradle support for Android projects.
For command line build, `gradle assembe` will trigger build phase

 - Config for Android .so file generation
 - Commented build.gradle
 - Automatic file copy after build
 - Dummy AndroidManifest file

* Build with Gradle

 - Build job for Travis CI
 - Moved gradle file to support/

* Gradle Path

 - Absolute path for Gradle binary

* File check after Gradle build

 - Additional script for build success
 - Check the Gradle's `assemble.doLast` task
2018-03-12 15:40:25 -04:00
Victor Zverovich
7db0e94b9e Fix handling of numeric alignment with no width (#675) 2018-03-11 21:04:42 -04:00
Victor Zverovich
9facc119a6 Update docs 2018-03-10 09:44:37 -08:00
Victor Zverovich
a1d187113b Merge branch 'master' of github.com:fmtlib/fmt 2018-03-10 06:46:51 -08:00
Victor Zverovich
daf650c49a Disallow formatting of multibyte strings into a wide buffer (#606) 2018-03-10 06:46:41 -08:00
Victor Zverovich
8fd7e30f37 Update README.rst 2018-03-09 15:44:46 -08:00
Victor Zverovich
ca93be130a Use fmt(s) as an alias for FMT_STRING(s) 2018-03-09 15:40:40 -08:00
Victor Zverovich
80e57c7a3d Update to new naming conventions 2018-03-07 07:36:13 -08:00
Victor Zverovich
ae3cc844e7 Check format string at compile time in print 2018-03-07 05:41:45 -08:00
Victor Zverovich
585512fc7c Remove unnecessary instantiations 2018-03-04 15:14:02 -08:00
Victor Zverovich
7755cdc199 Make symbols readable 2018-03-04 15:00:22 -08:00
Victor Zverovich
f867d08239 Update docs 2018-03-04 12:09:34 -08:00
Victor Zverovich
a103b9bc46 Workaround missed optimization in gcc (#668) 2018-03-04 11:45:20 -08:00
Victor Zverovich
bb47109a78 Cleanup 2018-03-04 11:25:40 -08:00
Victor Zverovich
f1ede6380b Make inline_buffer_size public and update docs 2018-03-04 10:33:42 -08:00
Victor Zverovich
995b63adfe Update copyright 2018-03-04 10:11:44 -08:00
Victor Zverovich
4023291759 Update docs 2018-03-04 09:55:17 -08:00
Victor Zverovich
86a9bc8291 Cleanup 2018-03-04 09:16:51 -08:00
Victor Zverovich
b7632e9641 Make format_to return iterator and update docs 2018-03-04 08:13:08 -08:00
Victor Zverovich
5281ea6ad2 do_vformat_to -> vformat_to and update docs 2018-03-04 06:40:43 -08:00
Victor Zverovich
d07ba49821 Fix docs 2018-03-03 22:12:23 -08:00
Victor Zverovich
418659adbe Fix compilation errors on gcc 4.4 2018-03-03 14:04:59 -08:00
Victor Zverovich
1d2adef28d Fix compilation errors on gcc 4.4 2018-03-01 03:45:25 -08:00
Victor Zverovich
45518c3fe1 Fix compilation errors on gcc 4.4 2018-02-28 07:47:24 -08:00
Victor Zverovich
698d909706 Workaround a bug in gcc 5.1 2018-02-28 06:14:56 -08:00
Victor Zverovich
81074c7048 Fix more compilation errors on gcc 4.6 2018-02-28 05:23:25 -08:00
Victor Zverovich
1b4525384b Fix more compilation errors on gcc 4.6 2018-02-28 05:09:24 -08:00
Victor Zverovich
6090e51b65 Fix compilation errors on gcc 4.6 2018-02-28 04:49:20 -08:00
Victor Zverovich
0827ec5aa9 Fix compilation errors on gcc 4.6 2018-02-28 04:33:43 -08:00
Victor Zverovich
4d35f94133 Always use fallback string_view to pass format string (#664) 2018-02-24 18:19:30 +00:00
Victor Zverovich
34cf54c2fc Update README.rst 2018-02-24 09:37:17 +00:00
Victor Zverovich
0565d65461 Fix gcc 7.2 issue 2018-02-24 09:29:15 +00:00
Victor Zverovich
f5dc0ed342 Break long lines 2018-02-24 08:39:17 +00:00
Lars Gullik Bjønnes
ea06f021f8 test: comment out one FormatStringErrors constexpr test
GCC 7.3 complains that this is not a compile time constant.

test/format-test.cc: In member function ‘virtual void FormatTest_FormatStringErrors_Test::TestBody()’:
test/format-test.cc:1919:3: error: non-constant condition for static assertion
   static_assert(test_error<__VA_ARGS__>(fmt, error), "")
   ^
test/format-test.cc:1924:3: note: in expansion of macro ‘EXPECT_ERROR’
   EXPECT_ERROR("{0:s", "unknown format specifier", Date);
   ^~~~~~~~~~~~
2018-02-24 08:20:20 +00:00
Lars Gullik Bjønnes
5b49177352 test: Initialize some local variables
GCC 7.3 complains about uninitialized varaibles in constexpr context.
2018-02-24 08:20:20 +00:00
Lars Gullik Bjønnes
f45f70af09 Use trailing return type instead of deduction
C++11 does not support deduction of return type.
2018-02-24 08:20:20 +00:00
Lars Gullik Bjønnes
db86e8d5d3 Remove a couple of unused argument names 2018-02-24 08:20:20 +00:00
Lars Gullik Bjønnes
55f5c9f21b Use FMT_NULL instead of 0 is a few more places.
Found with GCC and -Wzero-as-null-pointer-constant
2018-02-24 08:20:20 +00:00
johnthagen
e92ba1071d Fix Python str.format link to point to Python 3 docs 2018-02-20 17:40:49 +00:00
Victor Zverovich
a7ae5666a0 Enable join on msvc 2018-02-19 21:03:51 +00:00
Victor Zverovich
24d249b0b4 Fix formatting of objects convertible to string_view 2018-02-19 20:25:56 +00:00
hubslave
e508e30800 Don't define FMT_LOCALE on OpenBSD
OpenBSD doesn't have strtod_l() (at least under the default
headers), so the class Locale that the macro gates won't compile.
2018-02-19 19:24:33 +00:00
Victor Zverovich
0ee4273b04 Put is_enum check first not to instantiate convert_to_int unnecessarily 2018-02-18 05:47:29 +00:00
Victor Zverovich
8ca3ab2c4c Revert problematic pragma 2018-02-18 05:38:32 +00:00
Victor Zverovich
18ac98700e Fix formatting of objects convertible to std::string 2018-02-17 12:57:18 +00:00
Victor Zverovich
ce4a65ffea Add pointer support to basic_writer 2018-02-17 09:38:46 +00:00
Victor Zverovich
91721caa42 Add detection of wostream operator<< (#650) 2018-02-17 09:03:43 +00:00
Victor Zverovich
1efc15c177 Fix MSVC build 2018-02-16 18:13:54 +00:00
Victor Zverovich
8ed264fcd4 Rename type enum constants to prevent collision with poorly written C libs (#644) 2018-02-16 17:20:33 +00:00
Victor Zverovich
4ba3f7db82 Update docs 2018-02-15 18:52:44 -08:00
Andrew Gunnerson
7d2723d57c posix.cc: Fix compilation with -fno-exceptions
Signed-off-by: Andrew Gunnerson <andrewgunnerson@gmail.com>
2018-02-15 18:39:36 -08:00
Alex Alabuzhev
24d66c5d65 compilation fix & warnings 2018-02-15 18:37:45 -08:00
Victor Zverovich
229887bd40 Make constexpr remove_prefix gcc version check tighter (#648) 2018-02-14 05:46:41 -08:00
Victor Zverovich
f3f19e762f Update docs 2018-02-11 13:43:16 -08:00
Victor Zverovich
e9fa42acb8 Fix docs and build issues on gcc-4.6 2018-02-11 09:43:54 -08:00
Victor Zverovich
affb35cfb9 Replace using with typedef for compatibility with gcc-4.6 2018-02-11 09:23:47 -08:00
Victor Zverovich
9710c058aa Update documentation building script 2018-02-11 09:23:17 -08:00
Victor Zverovich
1a4e892765 Move output_range to format.h 2018-02-11 08:36:44 -08:00
Victor Zverovich
522de7b55d Replace using with typedef for compatibility with gcc-4.6 2018-02-11 08:32:02 -08:00
Victor Zverovich
0b508fd29d Fix c++0x detection 2018-02-11 07:32:22 -08:00
Victor Zverovich
1849735f12 Fallback to c++11 if c++14 not available 2018-02-11 07:25:53 -08:00
Victor Zverovich
3239c51814 Get rid of generic lambdas 2018-02-11 07:05:14 -08:00
Victor Zverovich
78166ccd36 Get rid of generic lambdas 2018-02-11 06:50:56 -08:00
Victor Zverovich
d8ef8a9e9b Cleanup 2018-02-11 06:24:22 -08:00
Victor Zverovich
822222181b Update README.rst 2018-02-10 07:45:32 -08:00
Victor Zverovich
b00053247c Merge the std branch 2018-02-10 07:38:27 -08:00
Giuseppe Corbelli
a502decddb Added a fmt.pro to support build using qmake (#641) 2018-02-10 07:22:02 -08:00
Victor Zverovich
61065e1a5c Fix unreachable code warning when signbit returns bool 2018-02-10 07:21:17 -08:00
Victor Zverovich
403ae0a23b Add debug postfix for libfmt (#636) 2018-02-10 07:17:40 -08:00
Victor Zverovich
5096c0fe97 Fix string_view detection 2018-02-10 07:17:29 -08:00
Victor Zverovich
5b3f9eab94 Update syntax.rst 2018-02-10 07:03:44 -08:00
Victor Zverovich
e802cf14e3 Add note about errno to the documentation 2018-02-10 07:01:59 -08:00
Victor Zverovich
c96d64652b CMakeLists: Use GNUInstallDirs to set install location 2018-02-10 07:00:14 -08:00
Victor Zverovich
dbd84697ff Update usage.rst 2018-02-10 06:54:26 -08:00
Victor Zverovich
5013c15737 Silence MSVC 2017 constant if expression warning 2018-02-10 06:52:46 -08:00
Victor Zverovich
cdfcee27fb Use allocator_traits if available 2018-02-10 06:51:13 -08:00
Victor Zverovich
66b25ef0d0 Add examples 2018-02-10 06:33:03 -08:00
Victor Zverovich
6cb68f9496 Fix warnings 2018-02-10 06:28:43 -08:00
Victor Zverovich
0b635c9dc5 Fix handling of fixed enums in clang (#580) 2018-02-10 06:17:42 -08:00
Victor Zverovich
66afd9b33a Fix compilation on gcc 6 2018-02-10 05:16:16 -08:00
Victor Zverovich
67e070fe5a Make format work with C++17 std::string_view (#571) 2018-02-07 08:14:54 -08:00
Victor Zverovich
867b330966 Remove ANDROID macro check per comment in #458 2018-02-07 07:44:15 -08:00
Victor Zverovich
64599973e9 Enable stream exceptions (#581) 2018-02-07 07:36:15 -08:00
Victor Zverovich
35f8f03670 Use less version 2.6.1 and sudo to fix npm install issues on travis 2018-02-07 07:17:34 -08:00
Victor Zverovich
92a250fdb6 Suppress Clang's warning on zero as a null pointer 2018-02-07 07:16:00 -08:00
Victor Zverovich
2f13d41e30 Add to_wstring 2018-02-07 07:08:14 -08:00
Victor Zverovich
1e19ae8348 Workaround a bug in MSVC 2018-02-07 06:31:42 -08:00
Victor Zverovich
3810d7e4d4 Workaround a bug in MSVC 2018-02-04 09:29:50 -08:00
Victor Zverovich
5c7474e1fb Relax constexpr requirements 2018-02-04 08:58:21 -08:00
Victor Zverovich
1f57243b49 Relax constexpr requirements 2018-02-04 08:52:43 -08:00
Victor Zverovich
dc5403612e Conditionally compile constexpr 2018-02-04 08:21:31 -08:00
Victor Zverovich
5d8ba816de Fix a segfault in test on glibc 2.26 #551 2018-02-02 19:34:08 -08:00
Victor Zverovich
a9f810c188 Update README.rst 2018-02-02 19:17:19 -08:00
Victor Zverovich
2582f41e12 Fix ifdefs 2018-02-02 19:16:13 -08:00
Victor Zverovich
1a7d0ba2d0 Adding OpenSpace to the list of projects 2018-02-02 19:10:25 -08:00
Victor Zverovich
8921f613de Update build script 2018-02-02 18:46:39 -08:00
Victor Zverovich
f62e225e82 Automatically update version in release script (#431) 2018-02-02 18:45:05 -08:00
Victor Zverovich
94806747df remove 'FMT_CPPFORMAT' CMake option 2018-02-02 18:42:22 -08:00
Victor Zverovich
bfce29ffef Improve conversion 2018-02-02 18:40:36 -08:00
Victor Zverovich
8cf30aa2be Fix segfault on complex pointer formatting (#642) 2018-02-01 21:49:03 -08:00
Victor Zverovich
f164e4c72f Remove old bcc-related comments 2018-02-01 16:49:47 -08:00
Victor Zverovich
c57029c1f0 Add Drake & Lyft Envoy to the list of projects 2018-02-01 16:46:41 -08:00
Victor Zverovich
8fa9acb8e5 Workaround broken __builtin_clz in clang with MS codegen (#519) 2018-02-01 16:43:16 -08:00
Victor Zverovich
3dae25828f Describe cmake use of header-only target 2018-02-01 16:42:53 -08:00
Victor Zverovich
1c7b751d70 Fix handling of implicit conversion to integral types larger than int 2018-02-01 16:42:15 -08:00
Victor Zverovich
08dff3774c Allow compiling and using as DLL in windows #502 2018-01-28 20:50:43 -08:00
Victor Zverovich
c753a2af39 Don't include the world with WIN32_LEAN_AND_MEAN (#503) 2018-01-28 20:26:25 -08:00
Victor Zverovich
a5185ec8d4 add SOURCELINK_SUFFIX for compatibility with Sphinx 1.5 2018-01-28 20:20:39 -08:00
Victor Zverovich
768061c85e Fix FormatBuf implementation (#491) 2018-01-28 20:08:51 -08:00
Victor Zverovich
0c136381e3 Move back_insert_range to format.h 2018-01-27 18:56:50 -08:00
Victor Zverovich
5060568f72 %.f should have zero precision, not default precision 2018-01-27 17:56:19 -08:00
Victor Zverovich
a09f748894 Add Kodi (xbmc) to the list of projects using fmt 2018-01-27 17:47:41 -08:00
Victor Zverovich
f9fa7c405f Add FMT_API and FMT_OVERRIDE where needed 2018-01-27 17:15:14 -08:00
Victor Zverovich
a980d3b46b Add fmt::join to format ranges (#466) 2018-01-27 16:04:45 -08:00
Victor Zverovich
87eab90ea8 Fix missing intrinsic when included from C++/CLI (#457) 2018-01-27 09:25:15 -08:00
Victor Zverovich
75005bbcd5 Don't export the -std=c++11 flag from the fmt target 2018-01-27 09:18:20 -08:00
Victor Zverovich
19f990a9c0 Use https to fetch dependencies from github 2018-01-27 09:15:28 -08:00
Victor Zverovich
bca9de9e68 Return iterator from format_to 2018-01-27 07:03:26 -08:00
Giuseppe Corbelli
0555cea5fc Added a fmt.pro to support build using qmake (#641) 2018-01-26 17:12:48 -08:00
Victor Zverovich
a93270fd60 Replace a bunch of craft with type_traits, take 2 2018-01-22 18:56:53 -08:00
Victor Zverovich
21429c8646 Revert "Replace a bunch of craft with type_traits"
This reverts commit e79588d6c1.
2018-01-21 18:53:38 -08:00
Victor Zverovich
0473c48f88 Add std::basic_string allocator support (#441) 2018-01-21 18:21:16 -08:00
Victor Zverovich
72d9fffd78 Fix test compilation for FreeBSD (#433) 2018-01-21 18:18:05 -08:00
Victor Zverovich
e79588d6c1 Replace a bunch of craft with type_traits 2018-01-21 18:11:57 -08:00
Victor Zverovich
3a6c7d0cbd Fix signbit detection (#423) 2018-01-21 16:41:55 -08:00
Victor Zverovich
5e4c34b25a Add version macro FMT_VERSION (#411) 2018-01-21 16:36:22 -08:00
Victor Zverovich
bd8a7e7ea1 More iteratification 2018-01-21 14:30:38 -08:00
peterbell10
f78c3e41be Fix unreachable code warning when signbit returns bool 2018-01-21 06:11:29 -08:00
Victor Zverovich
0a402056bc Add CONTRIBUTING.rst 2018-01-20 19:52:19 -08:00
Victor Zverovich
e35d41fff5 Add extern templates for format_float (#413) 2018-01-20 19:17:59 -08:00
Victor Zverovich
d8c25a175a Use nullptr if available 2018-01-20 19:11:19 -08:00
Victor Zverovich
e95e4659d9 Add syntax.rst to build 2018-01-20 17:55:43 -08:00
Victor Zverovich
e51119508c argument index -> argument id 2018-01-20 17:55:28 -08:00
Victor Zverovich
229ee34eea Fix compiler warnings 2018-01-20 17:54:06 -08:00
Victor Zverovich
7fe0f3dabc Update ChangeLog 2018-01-20 17:39:15 -08:00
Victor Zverovich
38b603a42f Update README.rst 2018-01-20 17:12:43 -08:00
Victor Zverovich
a1e7e4a768 Fix compilation with -fno-exceptions (#402, #405) 2018-01-20 17:10:14 -08:00
codicodi
3f24a38840 Thread-safe time formatting (#396) 2018-01-20 11:35:23 -08:00
Victor Zverovich
f853d94a15 Remove unnecessary fmt/ prefix (#397) 2018-01-20 10:28:10 -08:00
Victor Zverovich
9649919d01 Document use of format_arg for user-defined type #393 2018-01-20 10:07:29 -08:00
Victor Zverovich
c8efe145b4 Add api.rst to build 2018-01-20 09:52:29 -08:00
Victor Zverovich
da80005f11 Fix compilation on Cygwin (#388) 2018-01-20 09:52:03 -08:00
Victor Zverovich
8ed163533c Fix a typo 2018-01-20 09:43:56 -08:00
Victor Zverovich
1760c31b52 Workaround Doxygen mess 2018-01-20 08:53:03 -08:00
Victor Zverovich
72606f2391 Add missing types to counting_iterator 2018-01-20 08:20:18 -08:00
Victor Zverovich
c15710032e Add debug postfix for libfmt (#636) 2018-01-20 06:47:12 -08:00
Victor Zverovich
6822466aa3 Handle nested braces in join (#638) 2018-01-20 06:26:22 -08:00
Victor Zverovich
64b349aee2 More iterator support & fmt::count 2018-01-17 22:04:24 -08:00
Victor Zverovich
e3b69efbe1 Suppress msvc warnings in gmock 2018-01-17 05:46:14 -08:00
Victor Zverovich
322736d3bb Add support for arbitrary output iterators 2018-01-15 12:46:44 -08:00
Victor Zverovich
1029119497 Cleanup 2018-01-15 11:37:39 -08:00
Victor Zverovich
c1d137ed5f Add support for nonconiguous iterators 2018-01-15 11:30:53 -08:00
Victor Zverovich
f6fd38bb3a More iterator support 2018-01-15 08:48:37 -08:00
Victor Zverovich
c2fecb9b2a Clean API 2018-01-14 14:15:59 -08:00
Victor Zverovich
9a53a706fc Add support for back_insert_iterator 2018-01-14 13:12:26 -08:00
Victor Zverovich
91ee9c9acd Return iterator from the format method 2018-01-14 11:00:27 -08:00
Victor Zverovich
67928eae28 Don't inherit context from parse_context 2018-01-14 09:27:40 -08:00
Victor Zverovich
217e7c76f1 Pass ranges by value 2018-01-14 08:13:48 -08:00
Victor Zverovich
22994c62f7 Decouple arg_formatter_base from buffer 2018-01-13 15:34:48 -08:00
Victor Zverovich
00f1450d9a Update tesmplate parameter names 2018-01-13 14:57:43 -08:00
Victor Zverovich
3a2e89e134 Reduce dependency on buffer 2018-01-13 12:57:27 -08:00
Victor Zverovich
c719d94473 Fix experimental/string_view detection 2018-01-13 07:57:33 -08:00
Victor Zverovich
cea3c20747 Give a better error message for function pointers (#633) 2018-01-13 07:02:45 -08:00
Victor Zverovich
232ceabbc3 Workaround an internal compiler error in MSVC 2018-01-13 06:43:03 -08:00
Victor Zverovich
c095445394 Replace buffer with range 2018-01-10 22:41:23 -08:00
Victor Zverovich
c3d6c5fc4c Replace buffer with range 2017-12-30 07:42:56 -08:00
Tim Blechmann
0f98773164 add transition helper to format.h
the transition from v3 to v4 introduced an API change that format.h does
not provide printf functionality. to easi the transition we introduce a
define `FMT_FORMAT_PROVIDE_PRINTF` that will pull in printf.h from format.h
2017-12-27 21:48:55 -08:00
Victor Zverovich
d165d9c483 Decouple locale and buffer 2017-12-26 17:22:07 -08:00
Victor Zverovich
3663414053 Parameterize basic_writer on buffer type 2017-12-26 09:00:22 -08:00
Victor Zverovich
6f2769d0b4 Revert "Added support for format string containing '\0' in _format udl (#619) (#620)"
This reverts commit 3aaa25fa70 for
reasons discussed in #622.
2017-12-23 08:00:51 -08:00
Victor Zverovich
5f1c73db7d Shorten a comment in locale.h 2017-12-23 08:00:38 -08:00
Victor Zverovich
319346025d Update version 2017-12-20 08:38:07 -08:00
Victor Zverovich
51a16f8c58 Update ChangeLog.rst 2017-12-20 08:33:31 -08:00
Victor Zverovich
a00874603d Merge release branch 2017-12-20 08:30:58 -08:00
Victor Zverovich
941663d038 Merge ostream.cc into ostream.h 2017-12-17 09:33:56 -08:00
Victor Zverovich
955062da2e Merge printf.cc into printf.h 2017-12-17 08:36:19 -08:00
Virgilio Alexandre Fornazin
5705bf1c71 Added support for pre-c++17 experimental string_view (#607)
Added support for pre-c++17 experimental string_view
2017-12-16 09:03:11 -08:00
Victor Zverovich
cabce31f45 Update syntax.rst 2017-12-16 08:58:54 -08:00
Victor Zverovich
ccaae0c019 Refer to jeaiii project 2017-12-10 16:09:35 -08:00
Victor Zverovich
e37151021e Add a integer formatter based on jeaiii 2017-12-10 16:05:51 -08:00
Victor Zverovich
b3495f2e4b Update README.rst 2017-12-10 06:54:51 -08:00
Victor Zverovich
61f296e30c Move FMT_HAS_BUILTIN to format.h 2017-12-09 08:56:44 -08:00
Victor Zverovich
ce801c9095 Remove dependency on <vector> and <array> 2017-12-09 08:48:30 -08:00
Victor Zverovich
41fc29907a Merge branch 'std' of github.com:fmtlib/fmt into std 2017-12-09 08:16:34 -08:00
Victor Zverovich
971fb584c3 Allow mixing named and automatic arguments 2017-12-09 08:15:13 -08:00
Abdó Roig-Maranges
af0f21da0f add missing inline in header-only mode (#626) 2017-12-09 07:50:53 -08:00
Victor Zverovich
7cea163809 numeric -> arithmetic 2017-12-09 06:19:15 -08:00
Victor Zverovich
5328907f7f Get rid of <limits> dependency 2017-12-06 09:18:17 -08:00
Victor Zverovich
faaafc7e12 Remove <utility> dependency and replace typedefs with using 2017-12-06 09:13:23 -08:00
Victor Zverovich
94edb1a71c Add a lightweight header for the core API 2017-12-06 07:42:42 -08:00
Artem Golubikhin
3aaa25fa70 Added support for format string containing '\0' in _format udl (#619) (#620)
Added support for strings containing '\0' in udl (#619)
2017-12-06 06:21:34 -08:00
Victor Zverovich
84bd2f1962 Merge include/fmt/CMakeLists.txt into the main CMake file 2017-12-03 09:59:55 -08:00
Victor Zverovich
7f351dec27 Decouple <locale> for better compile times 2017-12-03 09:51:59 -08:00
Victor Zverovich
81bd9e8ea3 args -> format_args 2017-12-03 08:00:22 -08:00
Victor Zverovich
10e70a06c9 Improve handling of custom arguments 2017-12-02 09:44:48 -08:00
Victor Zverovich
e0243000de arg_index -> arg_id 2017-11-26 10:05:49 -08:00
Victor Zverovich
ac5f95208c Automatically add package to release 2017-11-25 08:23:13 -08:00
Abdo Roig-Maranges
0e914372fb Avoid conflict with the macro CHAR_WIDTH
It looks like CHAR_WIDTH is a macro in glibc. See
https://sourceware.org/ml/libc-alpha/2016-09/msg00225.html
2017-11-25 07:25:06 -08:00
Victor Zverovich
f03a35a679 Check string specs at compile time 2017-11-24 09:54:28 -08:00
Victor Zverovich
e9da574147 Check char specs at compile time 2017-11-24 07:54:22 -08:00
Victor Zverovich
b25a029284 Check pointer type specs are compile time 2017-11-23 10:12:23 -08:00
Victor Zverovich
c8a9d902dd Check floating-point type specifiers 2017-11-23 09:14:37 -08:00
Victor Zverovich
6570dc3122 Disallow formatting of multibyte strings into a wide buffer (#606) 2017-11-23 07:23:07 -08:00
Victor Zverovich
3851994ab0 Fix yet another internal compiler error in MSVC 2017-11-19 09:06:49 -08:00
Victor Zverovich
44e186512b Refactor parse context and fix warnings 2017-11-19 08:49:58 -08:00
Victor Zverovich
e7e270f511 Test error on invalid type spec and remove unused alias 2017-11-19 08:25:34 -08:00
Victor Zverovich
692b82d32c UdlArg -> udl_arg 2017-11-19 08:02:07 -08:00
Victor Zverovich
c523dd584f Use error handler to report errors 2017-11-19 07:36:01 -08:00
Victor Zverovich
5a32e64b05 More tests 2017-11-19 07:03:12 -08:00
Victor Zverovich
093e2a4780 Improve error handling 2017-11-18 09:16:35 -08:00
Victor Zverovich
dc104cbaaa Workaround internal compiler errors in MSVC 2017-11-18 09:05:05 -08:00
Victor Zverovich
39411504a5 More tests 2017-11-18 08:16:59 -08:00
Victor Zverovich
e3eb5ea074 Add parse_context::error_handler() 2017-11-18 06:58:14 -08:00
Victor Zverovich
734e722da4 Fix warnings 2017-11-18 06:56:29 -08:00
Victor Zverovich
62af25dca8 Workaround yet another MSVC internal error 2017-11-18 06:31:47 -08:00
Victor Zverovich
594bd8feba More tests 2017-11-16 06:55:49 -08:00
Victor Zverovich
f2b52bba05 More tests 2017-11-15 07:06:03 -08:00
Victor Zverovich
dfdb1adea5 More tests 2017-11-12 10:03:39 -08:00
Victor Zverovich
7967c2f874 Disable test that triggers an MSVC bug 2017-11-12 09:47:15 -08:00
Victor Zverovich
18a0b94b0e Fix overflow check 2017-11-12 09:25:28 -08:00
Victor Zverovich
686ff942af Fix compile-time parsing and add more tests 2017-11-11 11:40:56 -08:00
Victor Zverovich
5b95b5d77c Test compile-time errors 2017-11-11 10:28:05 -08:00
Victor Zverovich
246bdafc74 Add FMT_STRING macro for compile-time strings 2017-11-11 07:39:12 -08:00
Victor Zverovich
e805543341 Remove FMT_USE_VARIADIC_TEMPLATES 2017-11-11 07:02:58 -08:00
Victor Zverovich
dba1ccc4d7 Update readme 2017-11-10 07:38:51 -08:00
Victor Zverovich
e613b3c7b1 Update readme 2017-11-10 07:24:16 -08:00
Victor Zverovich
9fda7a36fd Check integral type specs at compile time 2017-11-08 07:58:09 -08:00
Victor Zverovich
92847a0d11 Add integral type handler 2017-11-08 05:56:52 -08:00
Victor Zverovich
a03842b0d5 More compile-time checks 2017-11-05 13:26:19 -08:00
Victor Zverovich
1c855a4762 Integrate constexpr format specs parsing 2017-11-05 09:28:50 -08:00
Victor Zverovich
780b44bf82 Add compile-time format string check 2017-11-04 09:02:47 -07:00
Victor Zverovich
8ca6e76dbc Detect user-defined literal templates 2017-11-04 08:23:24 -07:00
Victor Zverovich
a7e986166a Workaround another MSVC madness 2017-10-29 08:19:55 -07:00
Victor Zverovich
db9ffa1405 Make parse_format_string constexpr 2017-10-29 07:32:14 -07:00
Victor Zverovich
e926ae78ac Add parse_format_string 2017-10-29 07:00:47 -07:00
Victor Zverovich
57e266ab1d Rename handlers 2017-10-27 06:44:00 -07:00
Victor Zverovich
d29c7c3aca Workaround a bug in MSVC 2017-10-25 07:37:50 -07:00
Victor Zverovich
aadb38a5e6 Make specs_checker constexpr 2017-10-24 07:46:30 -07:00
Victor Zverovich
dd0b72e1ee Remove refactoring artefacts 2017-10-22 14:44:52 -07:00
Victor Zverovich
e52b10e33f Merge branch 'vitaut-patch-1' of github.com:fmtlib/fmt into std 2017-10-22 10:35:37 -07:00
Victor Zverovich
529d88ce95 Make dynamic_format_specs construction constexpr 2017-10-22 10:19:09 -07:00
Victor Zverovich
d2f2a8b0ca constexpr support of dynamic width and precision 2017-10-22 09:32:46 -07:00
Victor Zverovich
6b3840b73c Make format_specs construction constexpr 2017-10-22 08:18:26 -07:00
Victor Zverovich
a38bd9ca24 Fix formatting and naming 2017-10-22 07:19:45 -07:00
Victor Zverovich
91014f0171 Naming conventions 2017-10-22 06:43:41 -07:00
Victor Zverovich
932ab2bfca Report error from parse_nonnegative_int via handler 2017-10-21 08:37:52 -07:00
Victor Zverovich
0ebdf41efa Fix compile-test 2017-10-21 08:17:00 -07:00
Victor Zverovich
170f5c671f Move headers to include/fmt 2017-10-21 07:38:49 -07:00
Victor Zverovich
3d11eac784 Workaround another MSVC constexpr bug 2017-10-21 07:13:20 -07:00
Victor Zverovich
c69e308690 Update README.rst 2017-10-20 18:00:31 -07:00
Victor Zverovich
25aac0bee5 Fix travis build on macOS 2017-10-20 06:47:17 -07:00
Victor Zverovich
b83241ff4d Make format spec parsing constexpr 2017-10-19 07:36:46 -07:00
Victor Zverovich
bd5188c811 Remove MinGW because it's not on appveyor image 2017-10-19 06:46:25 -07:00
Victor Zverovich
62616b88a6 Workaround a bug in MSVC's constexpr handling 2017-10-19 06:06:13 -07:00
Victor Zverovich
b8f85f671f Use Visual Studio 2017 image on appveyor 2017-10-18 08:38:16 -07:00
Victor Zverovich
7174de0d79 Fix contexpr-ness of pointer_from 2017-10-18 06:36:08 -07:00
Victor Zverovich
3785afc5a3 Pass errors to handler instead of throwing (#566) 2017-10-18 06:28:18 -07:00
Victor Zverovich
1b5ccf6c13 Make parse_arg_id constexpr 2017-10-15 16:54:47 -07:00
Victor Zverovich
17f93fe084 Make basic_string_view ctors constexpr 2017-09-29 12:26:57 -07:00
Victor Zverovich
d5e918b61f Detect C++14 compiler support 2017-09-28 08:57:54 -07:00
Victor Zverovich
be5b4552d9 Make null_terminating_iterator more iteratory 2017-09-27 22:40:58 -07:00
Victor Zverovich
643fb0662e Check for argument indexing switch 2017-09-27 21:18:37 -07:00
Victor Zverovich
d45544d14e Fix width handling in dynamic formatting 2017-09-27 19:04:15 -07:00
Victor Zverovich
8cbf544733 Add parse context 2017-09-17 09:05:01 -07:00
Victor Zverovich
ec4f5175f1 Replace Range with ParseContext in parse() 2017-09-16 17:07:03 -07:00
Victor Zverovich
83dd2ab919 Simplify dynamic_specs_handler 2017-09-16 15:30:13 -07:00
Victor Zverovich
5a8ae0bb05 Fix a warning 2017-09-13 08:36:06 -07:00
Victor Zverovich
39bc319b35 Update test results 2017-09-10 07:35:32 -07:00
Victor Zverovich
534bff7d31 Fix handling of max packed arguments 2017-09-09 07:38:52 -07:00
Victor Zverovich
0cda806dcc Fix compile tests 2017-09-08 11:25:49 -07:00
Victor Zverovich
a3191a9903 Get rid of FMT_MAKE_WSTR_VALUE macro 2017-09-08 08:42:01 -07:00
Victor Zverovich
fced79b0ee Get rid of old compat macros 2017-09-08 08:26:05 -07:00
Victor Zverovich
be887d9269 Replace internal::get with std::declval 2017-09-08 08:09:28 -07:00
Victor Zverovich
53cf073561 Get rid of FMT_MAKE_VALUE macro 2017-09-08 07:43:04 -07:00
Victor Zverovich
2972de4ba3 Char -> char_type 2017-09-06 07:29:48 -07:00
Victor Zverovich
9ee7c2163c Type -> type 2017-09-06 07:12:07 -07:00
Victor Zverovich
1a09194ae6 Cleanup type handling 2017-09-06 07:00:21 -07:00
Victor Zverovich
c18a4041f9 Remove conditional and to_iterator 2017-09-04 13:56:14 -07:00
Victor Zverovich
1cade7ef4d Remove FMT_USE_RVALUE_REFERENCES 2017-09-04 13:52:29 -07:00
Victor Zverovich
7413239f49 Remove unnecessary qualification 2017-09-04 13:12:52 -07:00
Victor Zverovich
af00e4f9c9 Remove printf_arg_formatter from format.h and cleanup 2017-09-04 12:28:53 -07:00
Victor Zverovich
44a26e5e21 CharPtr -> pointer_type and move to writer 2017-09-04 11:58:14 -07:00
Victor Zverovich
0fbd846561 Replace fmt::internal::make_unsigned with std::make_unsigned 2017-09-04 11:41:15 -07:00
Victor Zverovich
8a2bc0ab1b Add nullptr support 2017-09-04 11:10:08 -07:00
Victor Zverovich
80505995d0 Allow delayed type checking 2017-09-04 09:33:22 -07:00
Victor Zverovich
b0867f3fa0 AlignSpec -> align_spec and fix a warning 2017-08-27 09:56:45 -07:00
Victor Zverovich
f194a418f9 Replace fmt::is_same with std::is_same 2017-08-27 09:16:50 -07:00
Victor Zverovich
47c84d7974 Move part of write API (spec factories) to a separate header 2017-08-27 09:08:44 -07:00
Victor Zverovich
20168147dd Add ptr, a helper function for pointer formatting 2017-08-27 08:41:28 -07:00
Victor Zverovich
77c892c88e Fix more warnings 2017-08-27 08:16:46 -07:00
Victor Zverovich
be7d72ba0d Fix expansion-to-defined warning 2017-08-27 08:00:15 -07:00
Victor Zverovich
d4c504ae1c Fix a warning 2017-08-27 06:38:23 -07:00
Victor Zverovich
27ad6cee82 Use standard enable_if 2017-08-26 10:41:58 -07:00
Victor Zverovich
64681739fd Fix a warning 2017-08-26 09:32:37 -07:00
Victor Zverovich
388061674a Remove FMT_HAS_GXX_CXX11 2017-08-26 09:23:00 -07:00
Victor Zverovich
a7320bdce9 Fix a warning 2017-08-26 09:19:03 -07:00
Victor Zverovich
016acebb56 Remove legacy code 2017-08-26 09:09:43 -07:00
Victor Zverovich
07f8ffc44f Suppress shadowing warnings 2017-08-26 08:50:09 -07:00
Victor Zverovich
466386d5cd Suppress a warning in gmock 2017-08-26 08:50:09 -07:00
Victor Zverovich
70ef82a8e3 Workaround a bug in MSVC 2017-08-20 09:47:21 -07:00
Victor Zverovich
5e0562ab51 Separate parsing and formatting 2017-08-13 13:09:02 -07:00
Victor Zverovich
1102d46508 Make format spec parsing context-independent 2017-07-30 08:58:24 -07:00
Victor Zverovich
45911770c5 Separate parsing and formatting in extension API 2017-07-29 07:50:16 -07:00
Victor Zverovich
7bd776e7db Explain why null_terminating_iterator is used 2017-07-26 08:48:59 -07:00
Victor Zverovich
873c8451ed Remove system_header pragma 2017-07-26 08:42:57 -07:00
Victor Zverovich
9f7957c073 Separate argument parsing and formatting 2017-07-26 08:37:46 -07:00
Victor Zverovich
da439f2838 Suppress warning about missing noreturn attribute (#549)
Suppress warning about missing noreturn attribute

Adding `[[noreturn]]` to `report_unknown_type` suppresses the Clang/GCC `-Wmissing-noreturn` warning:

Clang outputs:

    .../fmt/fmt/format.cc:294:74: warning:
          function 'report_unknown_type' could be declared with
          attribute 'noreturn' [-Wmissing-noreturn]
      ...code, const char *type) {
                                 ^

GCC outputs:

    .../fmt/fmt/format.cc:294:74: warning: function might be candidate for
        attribute 'noreturn' [-Wsuggest-attribute=noreturn]
      ...code, const char *type) {
                                 ^

Cherry-picked d16c4d.
2017-07-23 20:21:11 -07:00
Victor Zverovich
eefdb379f9 Fix an unused argument warning 2017-07-23 20:15:52 -07:00
Victor Zverovich
2f4f49fd60 Switch from cstring_view to string_view 2017-07-22 08:24:37 -07:00
Victor Zverovich
a8d6f309c8 Minor optimizations 2017-07-17 06:52:56 -07:00
Victor Zverovich
d16582a038 Move printf-related code to printf.cc 2017-07-15 09:46:18 -04:00
Victor Zverovich
361911dd18 Use preinstalled version of cmake on travis 2017-07-13 19:06:20 -04:00
Victor Zverovich
9ea183aaba Fix MSVC build 2017-07-13 19:00:21 -04:00
Victor Zverovich
8f4b918c5b Check argument index 2017-07-12 13:24:51 -04:00
Victor Zverovich
4193485b43 Remove test files 2017-07-12 13:15:06 -04:00
Victor Zverovich
07123e8ff3 Use Ubuntu Trusty on Travis for a new CMake 2017-07-12 13:13:36 -04:00
Victor Zverovich
586d63636a Implement more efficient handling of large number of format arguments 2017-07-12 00:26:54 -04:00
Victor Zverovich
12252152ac CStringRef -> cstring_view 2017-03-26 15:13:10 -07:00
Victor Zverovich
5aa8d6ea21 Return locale by value 2017-03-25 08:57:23 -07:00
Victor Zverovich
32ec13f149 Switch to C++ locale 2017-03-25 08:20:06 -07:00
Victor Zverovich
b4f4b7e21a Clean the buffer API (#477) 2017-03-12 09:48:21 -07:00
Victor Zverovich
f423e46835 Replace clear() with resize(0) and data_ -> store_ 2017-03-11 08:30:15 -08:00
Victor Zverovich
23b8c24da4 Add noexcept 2017-03-11 07:38:16 -08:00
Victor Zverovich
7175bd8ae6 Fix error on MinGW 2017-03-09 06:09:43 -08:00
Victor Zverovich
7258d1b8f3 Fix tests 2017-03-08 08:08:08 -08:00
Victor Zverovich
3610f34c70 Fix windows build 2017-03-04 07:10:54 -08:00
Victor Zverovich
572491ad1f Document which header defines formatting functions 2017-02-24 07:04:44 -08:00
Victor Zverovich
c333dca065 Follow standard naming conventions 2017-02-21 06:56:26 -08:00
Victor Zverovich
6a2ff287b2 Follow standard naming conventions 2017-02-19 08:05:41 -08:00
Victor Zverovich
eedfd07f8b internal::MemoryBuffer -> basic_memory_buffer 2017-02-18 09:13:12 -08:00
Victor Zverovich
4ec8860783 ArgFormatter -> arg_formatter 2017-02-18 07:46:32 -08:00
Victor Zverovich
50e716737d StringRef -> string_view, LongLong -> long_long 2017-02-18 07:34:52 -08:00
Victor Zverovich
e022c21ddc Fix windows build 2017-02-18 06:29:33 -08:00
Victor Zverovich
87b691d80c Merge StringWriter into StringBuffer 2017-02-17 06:23:16 -08:00
Victor Zverovich
c2f021692f Merge ArrayWriter into FixedBuffer 2017-02-17 06:09:26 -08:00
Victor Zverovich
fefaf07b6f Pass buffer instead of writer to format_value 2017-02-14 19:39:34 -05:00
Victor Zverovich
6e568f3a08 buffer -> basic_buffer 2017-02-14 12:08:37 -05:00
Victor Zverovich
bb1c82ef7d Fix build 2017-02-05 08:04:13 -08:00
Victor Zverovich
a13b96ed88 Simplify API 2017-02-05 06:54:03 -08:00
Victor Zverovich
624c58682d Simplify API 2017-02-05 06:41:39 -08:00
Victor Zverovich
7ae8bd7073 basic_format_arg -> basic_arg, Buffer -> buffer 2017-02-05 06:09:06 -08:00
Victor Zverovich
bf0f107564 Parameterize format_specs on character type 2017-01-28 13:17:47 +00:00
Victor Zverovich
296e9cada2 FrmatSpec -> format_spec 2017-01-28 12:51:35 +00:00
Victor Zverovich
b5fb8dd18b stream -> buffer 2017-01-28 12:44:36 +00:00
Victor Zverovich
984a102921 Remove IntFormatSpec and StrFormatSpec 2017-01-28 04:26:48 -08:00
Victor Zverovich
4863730eca Remove pad 2017-01-22 19:11:47 -08:00
Victor Zverovich
aaa0fc396b Improve compatibility with old compilers and fix test 2017-01-22 12:16:16 -08:00
Victor Zverovich
aea5d3ab00 Improve compatibility with older gcc and update tests 2017-01-22 11:50:52 -08:00
Victor Zverovich
8485027710 Use named argument emulation instead of nested functions 2017-01-22 11:28:55 -08:00
Victor Zverovich
ec15ef7b7b Replace operator<< with write function 2017-01-22 10:00:34 -08:00
Victor Zverovich
b77c8190ca FPUtil -> fputil 2016-12-30 13:12:27 -08:00
Victor Zverovich
8428621ddc BasicWriter -> basic_writer 2016-12-30 12:26:12 -08:00
Victor Zverovich
939aff2936 Remove unnecessary template arg from basic_format_args 2016-12-30 10:19:38 -08:00
Victor Zverovich
f69786a715 Remove Not 2016-12-30 09:29:41 -08:00
Victor Zverovich
b2a0d8914a Merge value and MakeValue 2016-12-30 09:25:01 -08:00
Victor Zverovich
acd1811c50 Value -> value 2016-12-30 08:05:26 -08:00
Victor Zverovich
42a319074c Parameterize Value on context 2016-12-29 18:07:05 -08:00
Victor Zverovich
a4d6cb32d1 Clean up basic_format_arg 2016-12-29 17:17:18 -08:00
Victor Zverovich
d705d51671 Parameterize basic_format_arg on context (#442) 2016-12-29 15:25:22 -08:00
Victor Zverovich
422236af7c Don't erase writer type 2016-12-28 07:55:33 -08:00
Victor Zverovich
abb6996f36 MakeArg -> make_arg 2016-12-27 07:55:44 -08:00
Victor Zverovich
ee1651ce07 Handle empty format_arg state 2016-12-27 07:43:25 -08:00
Victor Zverovich
3bbc5799b6 Fix MinGW build 2016-12-26 12:20:49 -08:00
Victor Zverovich
63fcfc5798 Fix build on older gcc 2016-12-26 10:55:30 -08:00
Victor Zverovich
d86e51e9c1 Don't inherit basic_format_arg from internal::Value 2016-12-24 07:46:50 -08:00
Victor Zverovich
f05888692c Fix handling of unpacked args (#437) 2016-12-23 08:24:48 -08:00
Victor Zverovich
1183621867 Add support for exotic character types 2016-12-15 08:36:18 -08:00
Victor Zverovich
763ca9780f Parameterize Value on character type 2016-12-15 08:26:10 -08:00
Victor Zverovich
6cba8fe9ba Move stuff out of internal::Value 2016-12-15 07:51:40 -08:00
Victor Zverovich
e1ee5bf0ba Replace StringValue with StringRef 2016-12-11 21:13:54 -08:00
Victor Zverovich
0854f8c3bf Parameterize formatting argument on char type. 2016-12-11 15:43:11 -08:00
Victor Zverovich
9cf6c8fdc6 Get rid of fmt::internal::Arg 2016-11-26 10:21:31 -08:00
Victor Zverovich
5f022ae081 Remove FMT_DISPATCH 2016-11-20 10:14:23 -08:00
Victor Zverovich
41d4bcf0cc Ingore Xcode files 2016-11-20 10:13:16 -08:00
Victor Zverovich
284297019f Merge BasicArgFormatter and ArgFormatter 2016-11-20 09:36:27 -08:00
Victor Zverovich
d4084ac5b1 Get rid of ArgVisitor 2016-11-20 09:11:13 -08:00
Victor Zverovich
d58cc8a4a8 Merge BasicPrintfArgFormatter and PrintfArgFormatter 2016-11-20 07:42:38 -08:00
Victor Zverovich
e2dfd39c75 Update arg visitors 2016-11-19 09:29:09 -08:00
Victor Zverovich
751ff64bdb Update ArgConverter to the new visitor API 2016-11-19 08:40:24 -08:00
Victor Zverovich
c9dc41ab3f Replace ArgVisitor::visit with a free visit function 2016-11-19 07:59:54 -08:00
Victor Zverovich
caa60b9c99 Update comment 2016-11-19 07:41:28 -08:00
Victor Zverovich
95a53e1f62 Refactor argument visitor API (#422) 2016-11-19 07:39:07 -08:00
Victor Zverovich
6d24116763 Improve visitor API 2016-11-13 09:42:17 -08:00
Victor Zverovich
a1dd524b6f format_arg -> do_format_arg 2016-11-07 18:22:21 -08:00
Victor Zverovich
55a1ac5035 Fix test 2016-11-07 08:55:40 -08:00
Victor Zverovich
85793a18cd Simplify API 2016-11-06 19:27:14 -08:00
Victor Zverovich
9998f66f8c Replace formatter with context 2016-11-06 18:59:17 -08:00
Victor Zverovich
2bba420337 Pass writer directly to format_value (#400) 2016-10-26 17:54:11 -07:00
Victor Zverovich
b656a1c133 Make value the second argument to format_value 2016-10-25 06:19:19 -07:00
Victor Zverovich
edf98792a5 Pass writer to format_value 2016-10-25 05:55:40 -07:00
Victor Zverovich
64ca334a2d CharType -> Char 2016-10-22 09:15:28 -07:00
Victor Zverovich
be613204ab Char -> char_type 2016-10-22 08:19:19 -07:00
Victor Zverovich
f85d5f4dac BasicFormatter -> basic_formatter 2016-10-22 08:04:20 -07:00
Victor Zverovich
18dfa257d0 Pass correct formatters to make_format_args 2016-10-21 06:46:21 -07:00
Victor Zverovich
dafbec7553 Fix type safety when using custom formatters (#394) 2016-10-07 08:37:06 -07:00
Victor Zverovich
506435bf71 Fix formatting 2016-10-07 03:41:23 -07:00
Victor Zverovich
f287994084 Fix formatting 2016-10-07 03:22:14 -07:00
Victor Zverovich
48fe97835b Add format_arg::operator bool 2016-10-02 09:36:40 -07:00
Victor Zverovich
119a63ab72 internal::Arg -> format_arg 2016-10-02 09:29:11 -07:00
Victor Zverovich
65a8c2c343 format_arg -> format_value 2016-10-02 08:49:10 -07:00
Victor Zverovich
13b04044e5 Add format_args::size_type 2016-10-02 08:26:32 -07:00
Victor Zverovich
8a77e7927e Enable C++11 in tests. 2016-10-01 07:18:55 -07:00
Victor Zverovich
1e8553d679 Enable C++11 in tests. 2016-10-01 07:02:58 -07:00
Victor Zverovich
06bab3edb0 Workaround mingw bug https://sourceforge.net/p/mingw/bugs/1531/ 2016-09-30 07:20:57 -07:00
Victor Zverovich
6fd6ecc10d Enable C++11 for no-windows-h-test 2016-09-28 07:45:28 -07:00
Victor Zverovich
c4212f9ec2 format -> vformat 2016-09-28 07:09:26 -07:00
Victor Zverovich
21c6700b83 Don't build std branch with -std=c++0=98 2016-09-26 07:35:27 -07:00
Victor Zverovich
209a1d58bf Get rid of macros 2016-08-27 09:06:21 -07:00
Victor Zverovich
9a07973261 Test types 2016-08-27 08:55:01 -07:00
Victor Zverovich
ea28a63706 Get rid of FMT_VARIADIC_CTOR 2016-08-27 08:23:44 -07:00
Victor Zverovich
0d8aca8de3 Get rid of FMT_VARIADIC_VOID 2016-08-27 08:16:49 -07:00
Victor Zverovich
4ece95a754 Make make_format_args public 2016-08-27 07:57:48 -07:00
Victor Zverovich
0028ce57b6 Get rid of FMT_VARIADIC 2016-08-26 17:23:13 -07:00
Victor Zverovich
ece7ae5f49 Make format_arg_store convertible to format_args 2016-08-26 15:09:40 -07:00
Victor Zverovich
621447fece Make initialization C++11-compatible 2016-08-26 14:41:18 -07:00
Victor Zverovich
a0190e4bbd Add a missing include 2016-08-26 10:26:33 -07:00
Victor Zverovich
b903f5c123 format -> vformat 2016-08-26 09:10:23 -07:00
Victor Zverovich
43c0095aa3 Refactor type mapping 2016-08-26 08:50:09 -07:00
Victor Zverovich
4873685c7e ArgArray -> format_arg_store 2016-08-26 06:44:41 -07:00
Victor Zverovich
fc73e10620 ArgList -> format_args 2016-08-25 08:50:07 -07:00
Victor Zverovich
92605eb4f7 Remove FMT_USE_VARIADIC_TEMPLATES 2016-08-25 08:44:53 -07:00
Victor Zverovich
9bb213e920 FormatError -> format_error 2016-08-25 08:38:07 -07:00
78 changed files with 11099 additions and 8953 deletions

View File

@@ -1,3 +0,0 @@
<!---
Please make sure you've followed the guidelines outlined in the CONTRIBUTING.rst file.
--->

14
.gitignore vendored
View File

@@ -1,5 +1,17 @@
.vscode/
*.iml
.idea/
.externalNativeBuild/
.gradle/
gradle/
gradlew*
local.properties
build/
bin/
/_CPack_Packages
/CMakeScripts
/doc/doxyxml
/doc/html
virtualenv
@@ -8,6 +20,7 @@ virtualenv
*~
*.a
*.so*
*.xcodeproj
*.zip
cmake_install.cmake
CPack*.cmake
@@ -15,5 +28,6 @@ fmt-*.cmake
CTestTestfile.cmake
CMakeCache.txt
CMakeFiles
FMT.build
Makefile
run-msbuild.bat

View File

@@ -1,27 +1,129 @@
language: cpp
dist: trusty
sudo: required # the doc target uses sudo to install dependencies
sudo: false
os: linux
git:
depth: 1
os:
- linux
- osx
env:
global:
- secure: |-
Gsnp9ERFnXt+diCfc7Vb72g+7HDn1MCHvw4zfUDdoBh9bxxFlLQRlzZZfwWhzni57lflrt
0QHXafu+oBVOJuNv6WauV3+ZyuWIQRmNGjZFNLvZsXHK/dyad2vGQBPvEkb+8l/aCyTpbr
6pxmyzLHSn1ZR7OX5rfPvwM3tOyZ3H0=
matrix:
- BUILD=Doc
- BUILD=Debug STANDARD=0x
- BUILD=Release STANDARD=98
- BUILD=Release STANDARD=0x
a1eovNn4uol9won7ghr67eD3/59oeESN+G9bWE+ecI1V6yRseG9whniGhIpC/YfMW/Qz5I
5sxSmFjaw9bxCISNwUIrL1O5x2AmRYTnFcXk4dFsUvlZg+WeF/aKyBYCNRM8C2ndbBmtAO
o1F2EwFbiso0EmtzhAPs19ujiVxkLn4=
matrix:
exclude:
- os: osx
env: BUILD=Doc
include:
# Documentation
- env: BUILD=Doc
sudo: required
# g++ 6 on Linux with C++14
- env: COMPILER=g++-6 BUILD=Debug STANDARD=14
compiler: gcc
addons:
apt:
update: true
sources:
- ubuntu-toolchain-r-test
packages:
- g++-6
- env: COMPILER=g++-6 BUILD=Release STANDARD=14
compiler: gcc
addons:
apt:
update: true
sources:
- ubuntu-toolchain-r-test
packages:
- g++-6
# Apple clang on OS X with C++14
- env: BUILD=Debug STANDARD=14
compiler: clang
os: osx
- env: BUILD=Release STANDARD=14
compiler: clang
os: osx
# clang 6.0 on Linux with C++14
- env: COMPILER=clang++-6.0 BUILD=Debug STANDARD=14
compiler: clang
addons:
apt:
update: true
packages:
- clang-6.0
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty
- llvm-toolchain-trusty-6.0
# clang 4.0 on Linux with C++14
- env: COMPILER=clang++-4.0 BUILD=Debug STANDARD=11
compiler: clang
addons:
apt:
update: true
packages:
- clang-4.0
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty
- llvm-toolchain-trusty-4.0
# g++ 4.8 on Linux with C++11
- env: COMPILER=g++-4.8 BUILD=Debug STANDARD=11
compiler: gcc
# g++ 4.4 on Linux with C++11
- env: COMPILER=g++-4.4 BUILD=Debug STANDARD=11
compiler: gcc
addons:
apt:
update: true
packages:
- g++-4.4
sources:
- ubuntu-toolchain-r-test
# Android
- language: android
android:
addons:
apt:
update: true
components:
- tools
- platform-tools
- android-21
- sys-img-armeabi-v7a-android-21
env:
- ANDROID=true
before_install:
- git submodule update --init --recursive
- sudo apt-get install wget unzip tree
install:
# Accept SDK Licenses + Install NDK
- yes | sdkmanager --update > /dev/null 2>&1
- sdkmanager ndk-bundle > /dev/null 2>&1
# Download Gradle 4.3.1
- wget https://services.gradle.org/distributions/gradle-4.3.1-bin.zip
- mkdir -p gradle
- unzip -q -d ./gradle gradle-4.3.1-bin.zip
- export GRADLE=${TRAVIS_BUILD_DIR}/gradle/gradle-4.3.1/bin/gradle
before_script:
- bash $GRADLE --version
- cd ./support
script:
- bash $GRADLE clean assemble
after_success:
- cd ${TRAVIS_BUILD_DIR}
- tree ./libs
allow_failures:
# Errors
- env: COMPILER=g++-4.4 BUILD=Debug STANDARD=11
compiler: gcc
before_script:
- if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then export CXX=${COMPILER}; fi
- if [[ "${BUILD}" != "Doc" ]]; then ${CXX} --version; fi
script:
- support/travis-build.py

View File

@@ -1,14 +1,6 @@
message(STATUS "CMake version: ${CMAKE_VERSION}")
cmake_minimum_required(VERSION 2.8.12)
if (POLICY CMP0048) # Version variables
cmake_policy(SET CMP0048 OLD)
endif ()
if (POLICY CMP0063) # Visibility
cmake_policy(SET CMP0063 OLD)
endif (POLICY CMP0063)
cmake_minimum_required(VERSION 3.1.0)
# Determine if fmt is built as a subproject (using add_subdirectory)
# or if it is the master project.
@@ -36,19 +28,19 @@ if (NOT CMAKE_BUILD_TYPE)
endif ()
option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF)
option(FMT_WERROR "Halt the compilation with an error on compiler warnings." OFF)
# Options that control generation of various targets.
option(FMT_DOC "Generate the doc target." ${MASTER_PROJECT})
option(FMT_INSTALL "Generate the install target." ${MASTER_PROJECT})
option(FMT_TEST "Generate the test target." ${MASTER_PROJECT})
option(FMT_USE_CPP11 "Enable the addition of C++11 compiler flags." ON)
project(FMT)
# Starting with cmake 3.0 VERSION is part of the project command.
file(READ fmt/format.h format_h)
if (NOT format_h MATCHES "FMT_VERSION ([0-9]+)([0-9][0-9])([0-9][0-9])")
message(FATAL_ERROR "Cannot get FMT_VERSION from format.h.")
# Get version from core.h
file(READ include/fmt/core.h core_h)
if (NOT core_h MATCHES "FMT_VERSION ([0-9]+)([0-9][0-9])([0-9][0-9])")
message(FATAL_ERROR "Cannot get FMT_VERSION from core.h.")
endif ()
# Use math to skip leading zeros if any.
math(EXPR CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
@@ -65,10 +57,63 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${CMAKE_CURRENT_SOURCE_DIR}/support/cmake")
include(cxx11)
include(cxx14)
include(CheckCXXCompilerFlag)
if (CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wshadow -pedantic)
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(PEDANTIC_COMPILE_FLAGS -pedantic-errors -Wall -Wextra -pedantic
-Wold-style-cast -Wfloat-equal -Wlogical-op -Wundef
-Wredundant-decls -Wshadow -Wwrite-strings -Wpointer-arith
-Wcast-qual -Wformat=2 -Wmissing-include-dirs
-Wcast-align -Wnon-virtual-dtor
-Wctor-dtor-privacy -Wdisabled-optimization
-Winvalid-pch -Wmissing-declarations -Woverloaded-virtual
-Wno-ctor-dtor-privacy -Wno-dangling-else -Wno-float-equal
-Wno-format-nonliteral -Wno-sign-conversion -Wno-shadow)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnoexcept)
endif ()
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wdouble-promotion
-Wtrampolines -Wzero-as-null-pointer-constant -Wuseless-cast
-Wvector-operation-performance -Wsized-deallocation)
endif ()
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wshift-overflow=2
-Wnull-dereference -Wduplicated-cond)
endif ()
set(WERROR_FLAG -Werror)
endif ()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(PEDANTIC_COMPILE_FLAGS -Weverything -Wpedantic
-Wno-weak-vtables -Wno-padded -Wno-gnu-statement-expression
-Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-reserved-id-macro
-Wno-global-constructors -Wno-disabled-macro-expansion
-Wno-switch-enum -Wno-documentation-unknown-command
-Wno-gnu-string-literal-operator-template -Wno-unused-member-function
-Wno-format-nonliteral -Wno-missing-noreturn -Wno-undefined-func-template
-Wno-shadow -Wno-sign-conversion -Wno-used-but-marked-unused
-Wno-covered-switch-default -Wno-missing-variable-declarations
-Wno-double-promotion)
set(WERROR_FLAG -Werror)
check_cxx_compiler_flag(-Wno-zero-as-null-pointer-constant HAS_NULLPTR_WARNING)
if (HAS_NULLPTR_WARNING)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wno-zero-as-null-pointer-constant)
endif ()
check_cxx_compiler_flag(-Wno-gnu-string-literal-operator-template HAS_GNU_UDL_WARNING)
if (HAS_GNU_UDL_WARNING)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wno-gnu-string-literal-operator-template)
endif ()
endif ()
if (MSVC)
set(PEDANTIC_COMPILE_FLAGS /W3)
set(WERROR_FLAG /WX)
endif ()
if (MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
@@ -94,7 +139,106 @@ else ()
check_symbol_exists(open fcntl.h HAVE_OPEN)
endif ()
add_subdirectory(fmt)
function(add_headers VAR)
set(headers ${${VAR}})
foreach (header ${ARGN})
set(headers ${headers} include/fmt/${header})
endforeach()
set(${VAR} ${headers} PARENT_SCOPE)
endfunction()
# Define the fmt library, its includes and the needed defines.
add_headers(FMT_HEADERS core.h format.h format-inl.h ostream.h printf.h time.h
ranges.h)
set(FMT_SOURCES src/format.cc)
if (HAVE_OPEN)
add_headers(FMT_HEADERS posix.h)
set(FMT_SOURCES ${FMT_SOURCES} src/posix.cc)
endif ()
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst)
add_library(fmt::fmt ALIAS fmt)
if (FMT_WERROR)
target_compile_options(fmt PRIVATE ${WERROR_FLAG})
endif ()
if (FMT_PEDANTIC)
target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
target_include_directories(fmt PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
set_target_properties(fmt PROPERTIES
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
DEBUG_POSTFIX d)
if (BUILD_SHARED_LIBS)
if (UNIX AND NOT APPLE)
# Fix rpmlint warning:
# unused-direct-shlib-dependency /usr/lib/libformat.so.1.1.0 /lib/libm.so.6.
target_link_libraries(fmt -Wl,--as-needed)
endif ()
target_compile_definitions(fmt PRIVATE FMT_EXPORT INTERFACE FMT_SHARED)
endif ()
add_library(fmt-header-only INTERFACE)
add_library(fmt::fmt-header-only ALIAS fmt-header-only)
target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)
target_include_directories(fmt-header-only INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
# Install targets.
if (FMT_INSTALL)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
set(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING
"Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.")
set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake)
set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake)
set(targets_export_name fmt-targets)
set (INSTALL_TARGETS fmt)
if (TARGET fmt-header-only)
set(INSTALL_TARGETS ${INSTALL_TARGETS} fmt-header-only)
endif ()
set(FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING
"Installation directory for libraries, relative to ${CMAKE_INSTALL_PREFIX}.")
set(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR}/fmt CACHE STRING
"Installation directory for include files, relative to ${CMAKE_INSTALL_PREFIX}.")
# Generate the version, config and target files into the build directory.
write_basic_package_version_file(
${version_config}
VERSION ${FMT_VERSION}
COMPATIBILITY AnyNewerVersion)
configure_package_config_file(
${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in
${project_config}
INSTALL_DESTINATION ${FMT_CMAKE_DIR})
# Use a namespace because CMake provides better diagnostics for namespaced
# imported targets.
export(TARGETS ${INSTALL_TARGETS} NAMESPACE fmt::
FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake)
# Install version, config and target files.
install(
FILES ${project_config} ${version_config}
DESTINATION ${FMT_CMAKE_DIR})
install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR}
NAMESPACE fmt::)
# Install the library and headers.
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
DESTINATION ${FMT_LIB_DIR})
install(FILES ${FMT_HEADERS} DESTINATION ${FMT_INC_DIR})
endif ()
if (FMT_DOC)
add_subdirectory(doc)

View File

@@ -6,6 +6,7 @@ All C++ code must adhere to `Google C++ Style Guide
exceptions:
* Exceptions are permitted
* snake_case should be used instead of UpperCamelCase for function names
* snake_case should be used instead of UpperCamelCase for function and type
names
Thanks for contributing!

View File

@@ -1,34 +1,514 @@
5.1.0 - 2018-07-05
------------------
* Added experimental support for RGB color output enabled with
the ``FMT_EXTENDED_COLORS`` macro:
.. code:: c++
#define FMT_EXTENDED_COLORS
#define FMT_HEADER_ONLY // or compile fmt with FMT_EXTENDED_COLORS defined
#include <fmt/format.h>
fmt::print(fmt::color::steel_blue, "Some beautiful text");
The old API (the ``print_colored`` and ``vprint_colored`` functions and the
``color`` enum) is now deprecated.
(`#762 <https://github.com/fmtlib/fmt/issues/762>`_
`#767 <https://github.com/fmtlib/fmt/pull/767>`_).
Thanks `@Remotion (Remo) <https://github.com/Remotion>`_.
* Added quotes to strings in ranges and tuples
(`#766 <https://github.com/fmtlib/fmt/pull/766>`_).
Thanks `@Remotion (Remo) <https://github.com/Remotion>`_.
* Made ``format_to`` work with ``basic_memory_buffer``
(`#776 <https://github.com/fmtlib/fmt/issues/776>`_).
* Added ``vformat_to_n`` and ``wchar_t`` overload of ``format_to_n``
(`#764 <https://github.com/fmtlib/fmt/issues/764>`_,
`#769 <https://github.com/fmtlib/fmt/issues/769>`_).
* Made ``is_range`` and ``is_tuple_like`` part of public (experimental) API
to allow specialization for user-defined types
(`#751 <https://github.com/fmtlib/fmt/issues/751>`_,
`#759 <https://github.com/fmtlib/fmt/pull/759>`_).
Thanks `@drrlvn (Dror Levin) <https://github.com/drrlvn>`_.
* Added more compilers to continuous integration and increased ``FMT_PEDANTIC``
warning levels
(`#736 <https://github.com/fmtlib/fmt/pull/736>`_).
Thanks `@eliaskosunen (Elias Kosunen) <https://github.com/eliaskosunen>`_.
* Fixed compilation with MSVC 2013.
* Fixed handling of user-defined types in ``format_to``
(`#793 <https://github.com/fmtlib/fmt/issues/793>`_).
* Forced linking of inline ``vformat`` functions into the library
(`#795 <https://github.com/fmtlib/fmt/issues/795>`_).
* Fixed incorrect call to on_align in ``'{:}='``
(`#750 <https://github.com/fmtlib/fmt/issues/750>`_).
* Fixed floating-point formatting to a non-back_insert_iterator with sign &
numeric alignment specified
(`#756 <https://github.com/fmtlib/fmt/issues/756>`_).
* Fixed formatting to an array with ``format_to_n``
(`#778 <https://github.com/fmtlib/fmt/issues/778>`_).
* Fixed formatting of more than 15 named arguments
(`#754 <https://github.com/fmtlib/fmt/issues/754>`_).
* Fixed handling of compile-time strings when including ``fmt/ostream.h``.
(`#768 <https://github.com/fmtlib/fmt/issues/768>`_).
* Fixed various compiler warnings and errors
(`#742 <https://github.com/fmtlib/fmt/issues/742>`_,
`#748 <https://github.com/fmtlib/fmt/issues/748>`_,
`#752 <https://github.com/fmtlib/fmt/issues/752>`_,
`#770 <https://github.com/fmtlib/fmt/issues/770>`_,
`#775 <https://github.com/fmtlib/fmt/pull/775>`_,
`#779 <https://github.com/fmtlib/fmt/issues/779>`_,
`#780 <https://github.com/fmtlib/fmt/pull/780>`_,
`#790 <https://github.com/fmtlib/fmt/pull/790>`_,
`#792 <https://github.com/fmtlib/fmt/pull/792>`_,
`#800 <https://github.com/fmtlib/fmt/pull/800>`_).
Thanks `@Remotion (Remo) <https://github.com/Remotion>`_,
`@gabime (Gabi Melman) <https://github.com/gabime>`_,
`@foonathan (Jonathan Müller) <https://github.com/foonathan>`_,
`@Dark-Passenger (Dhruv Paranjape) <https://github.com/Dark-Passenger>`_, and
`@0x8000-0000 (Sign Bit) <https://github.com/0x8000-0000>`_.
5.0.0 - 2018-05-21
------------------
* Added a requirement for partial C++11 support, most importantly variadic
templates and type traits, and dropped ``FMT_VARIADIC_*`` emulation macros.
Variadic templates are available since GCC 4.4, Clang 2.9 and MSVC 18.0 (2013).
For older compilers use {fmt} `version 4.x
<https://github.com/fmtlib/fmt/releases/tag/4.1.0>`_ which continues to be
maintained and works with C++98 compilers.
* Renamed symbols to follow standard C++ naming conventions and proposed a subset
of the library for standardization in `P0645R2 Text Formatting
<https://wg21.link/P0645>`_.
* Implemented ``constexpr`` parsing of format strings and `compile-time format
string checks
<http://fmtlib.net/dev/api.html#compile-time-format-string-checks>`_. For
example
.. code:: c++
#include <fmt/format.h>
std::string s = format(fmt("{:d}"), "foo");
gives a compile-time error because ``d`` is an invalid specifier for strings
(`godbolt <https://godbolt.org/g/rnCy9Q>`__)::
...
<source>:4:19: note: in instantiation of function template specialization 'fmt::v5::format<S, char [4]>' requested here
std::string s = format(fmt("{:d}"), "foo");
^
format.h:1337:13: note: non-constexpr function 'on_error' cannot be used in a constant expression
handler.on_error("invalid type specifier");
Compile-time checks require relaxed ``constexpr`` (C++14 feature) support. If
the latter is not available, checks will be performed at runtime.
* Separated format string parsing and formatting in the extension API to enable
compile-time format string processing. For example
.. code:: c++
struct Answer {};
namespace fmt {
template <>
struct formatter<Answer> {
constexpr auto parse(parse_context& ctx) {
auto it = ctx.begin();
spec = *it;
if (spec != 'd' && spec != 's')
throw format_error("invalid specifier");
return ++it;
}
template <typename FormatContext>
auto format(Answer, FormatContext& ctx) {
return spec == 's' ?
format_to(ctx.begin(), "{}", "fourty-two") :
format_to(ctx.begin(), "{}", 42);
}
char spec = 0;
};
}
std::string s = format(fmt("{:x}"), Answer());
gives a compile-time error due to invalid format specifier (`godbolt
<https://godbolt.org/g/2jQ1Dv>`__)::
...
<source>:12:45: error: expression '<throw-expression>' is not a constant expression
throw format_error("invalid specifier");
* Added `iterator support
<http://fmtlib.net/dev/api.html#output-iterator-support>`_:
.. code:: c++
#include <vector>
#include <fmt/format.h>
std::vector<char> out;
fmt::format_to(std::back_inserter(out), "{}", 42);
* Added the `format_to_n
<http://fmtlib.net/dev/api.html#_CPPv2N3fmt11format_to_nE8OutputItNSt6size_tE11string_viewDpRK4Args>`_
function that restricts the output to the specified number of characters
(`#298 <https://github.com/fmtlib/fmt/issues/298>`_):
.. code:: c++
char out[4];
fmt::format_to_n(out, sizeof(out), "{}", 12345);
// out == "1234" (without terminating '\0')
* Added the `formatted_size
<http://fmtlib.net/dev/api.html#_CPPv2N3fmt14formatted_sizeE11string_viewDpRK4Args>`_
function for computing the output size:
.. code:: c++
#include <fmt/format.h>
auto size = fmt::formatted_size("{}", 12345); // size == 5
* Improved compile times by reducing dependencies on standard headers and
providing a lightweight `core API <http://fmtlib.net/dev/api.html#core-api>`_:
.. code:: c++
#include <fmt/core.h>
fmt::print("The answer is {}.", 42);
See `Compile time and code bloat
<https://github.com/fmtlib/fmt#compile-time-and-code-bloat>`_.
* Added the `make_format_args
<http://fmtlib.net/dev/api.html#_CPPv2N3fmt16make_format_argsEDpRK4Args>`_
function for capturing formatting arguments:
.. code:: c++
// Prints formatted error message.
void vreport_error(const char *format, fmt::format_args args) {
fmt::print("Error: ");
fmt::vprint(format, args);
}
template <typename... Args>
void report_error(const char *format, const Args & ... args) {
vreport_error(format, fmt::make_format_args(args...));
}
* Added the ``make_printf_args`` function for capturing ``printf`` arguments
(`#687 <https://github.com/fmtlib/fmt/issues/687>`_,
`#694 <https://github.com/fmtlib/fmt/pull/694>`_).
Thanks `@Kronuz (Germán Méndez Bravo) <https://github.com/Kronuz>`_.
* Added prefix ``v`` to non-variadic functions taking ``format_args`` to
distinguish them from variadic ones:
.. code:: c++
std::string vformat(string_view format_str, format_args args);
template <typename... Args>
std::string format(string_view format_str, const Args & ... args);
* Added experimental support for formatting ranges, containers and tuple-like
types in ``fmt/ranges.h`` (`#735 <https://github.com/fmtlib/fmt/pull/735>`_):
.. code:: c++
#include <fmt/ranges.h>
std::vector<int> v = {1, 2, 3};
fmt::print("{}", v); // prints {1, 2, 3}
Thanks `@Remotion (Remo) <https://github.com/Remotion>`_.
* Implemented ``wchar_t`` date and time formatting
(`#712 <https://github.com/fmtlib/fmt/pull/712>`_):
.. code:: c++
#include <fmt/time.h>
std::time_t t = std::time(nullptr);
auto s = fmt::format(L"The date is {:%Y-%m-%d}.", *std::localtime(&t));
Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_.
* Provided more wide string overloads
(`#724 <https://github.com/fmtlib/fmt/pull/724>`_).
Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_.
* Switched from a custom null-terminated string view class to ``string_view``
in the format API and provided ``fmt::string_view`` which implements a subset
of ``std::string_view`` API for pre-C++17 systems.
* Added support for ``std::experimental::string_view``
(`#607 <https://github.com/fmtlib/fmt/pull/607>`_):
.. code:: c++
#include <fmt/core.h>
#include <experimental/string_view>
fmt::print("{}", std::experimental::string_view("foo"));
Thanks `@virgiliofornazin (Virgilio Alexandre Fornazin)
<https://github.com/virgiliofornazin>`__.
* Allowed mixing named and automatic arguments:
.. code:: c++
fmt::format("{} {two}", 1, fmt::arg("two", 2));
* Removed the write API in favor of the `format API
<http://fmtlib.net/dev/api.html#format-api>`_ with compile-time handling of
format strings.
* Disallowed formatting of multibyte strings into a wide character target
(`#606 <https://github.com/fmtlib/fmt/pull/606>`_).
* Improved documentation
(`#515 <https://github.com/fmtlib/fmt/pull/515>`_,
`#614 <https://github.com/fmtlib/fmt/issues/614>`_,
`#617 <https://github.com/fmtlib/fmt/pull/617>`_,
`#661 <https://github.com/fmtlib/fmt/pull/661>`_,
`#680 <https://github.com/fmtlib/fmt/pull/680>`_).
Thanks `@ibell (Ian Bell) <https://github.com/ibell>`_,
`@mihaitodor (Mihai Todor) <https://github.com/mihaitodor>`_, and
`@johnthagen <https://github.com/johnthagen>`_.
* Implemented more efficient handling of large number of format arguments.
* Introduced an inline namespace for symbol versioning.
* Added debug postfix ``d`` to the ``fmt`` library name
(`#636 <https://github.com/fmtlib/fmt/issues/636>`_).
* Removed unnecessary ``fmt/`` prefix in includes
(`#397 <https://github.com/fmtlib/fmt/pull/397>`_).
Thanks `@chronoxor (Ivan Shynkarenka) <https://github.com/chronoxor>`_.
* Moved ``fmt/*.h`` to ``include/fmt/*.h`` to prevent irrelevant files and
directories appearing on the include search paths when fmt is used as a
subproject and moved source files to the ``src`` directory.
* Added qmake project file ``support/fmt.pro``
(`#641 <https://github.com/fmtlib/fmt/pull/641>`_).
Thanks `@cowo78 (Giuseppe Corbelli) <https://github.com/cowo78>`_.
* Added Gradle build file ``support/build.gradle``
(`#649 <https://github.com/fmtlib/fmt/pull/649>`_).
Thanks `@luncliff (Park DongHa) <https://github.com/luncliff>`_.
* Removed ``FMT_CPPFORMAT`` CMake option.
* Fixed a name conflict with the macro ``CHAR_WIDTH`` in glibc
(`#616 <https://github.com/fmtlib/fmt/pull/616>`_).
Thanks `@aroig (Abdó Roig-Maranges) <https://github.com/aroig>`_.
* Fixed handling of nested braces in ``fmt::join``
(`#638 <https://github.com/fmtlib/fmt/issues/638>`_).
* Added ``SOURCELINK_SUFFIX`` for compatibility with Sphinx 1.5
(`#497 <https://github.com/fmtlib/fmt/pull/497>`_).
Thanks `@ginggs (Graham Inggs) <https://github.com/ginggs>`_.
* Added a missing ``inline`` in the header-only mode
(`#626 <https://github.com/fmtlib/fmt/pull/626>`_).
Thanks `@aroig (Abdó Roig-Maranges) <https://github.com/aroig>`_.
* Fixed various compiler warnings
(`#640 <https://github.com/fmtlib/fmt/pull/640>`_,
`#656 <https://github.com/fmtlib/fmt/pull/656>`_,
`#679 <https://github.com/fmtlib/fmt/pull/679>`_,
`#681 <https://github.com/fmtlib/fmt/pull/681>`_,
`#705 <https://github.com/fmtlib/fmt/pull/705>`__,
`#715 <https://github.com/fmtlib/fmt/issues/715>`_,
`#717 <https://github.com/fmtlib/fmt/pull/717>`_,
`#720 <https://github.com/fmtlib/fmt/pull/720>`_,
`#723 <https://github.com/fmtlib/fmt/pull/723>`_,
`#726 <https://github.com/fmtlib/fmt/pull/726>`_,
`#730 <https://github.com/fmtlib/fmt/pull/730>`_,
`#739 <https://github.com/fmtlib/fmt/pull/739>`_).
Thanks `@peterbell10 <https://github.com/peterbell10>`_,
`@LarsGullik <https://github.com/LarsGullik>`_,
`@foonathan (Jonathan Müller) <https://github.com/foonathan>`_,
`@eliaskosunen (Elias Kosunen) <https://github.com/eliaskosunen>`_,
`@christianparpart (Christian Parpart) <https://github.com/christianparpart>`_,
`@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_,
and `@mwinterb <https://github.com/mwinterb>`_.
* Worked around an MSVC bug and fixed several warnings
(`#653 <https://github.com/fmtlib/fmt/pull/653>`_).
Thanks `@alabuzhev (Alex Alabuzhev) <https://github.com/alabuzhev>`_.
* Worked around GCC bug 67371
(`#682 <https://github.com/fmtlib/fmt/issues/682>`_).
* Fixed compilation with ``-fno-exceptions``
(`#655 <https://github.com/fmtlib/fmt/pull/655>`_).
Thanks `@chenxiaolong (Andrew Gunnerson) <https://github.com/chenxiaolong>`_.
* Made ``constexpr remove_prefix`` gcc version check tighter
(`#648 <https://github.com/fmtlib/fmt/issues/648>`_).
* Renamed internal type enum constants to prevent collision with poorly written
C libraries (`#644 <https://github.com/fmtlib/fmt/issues/644>`_).
* Added detection of ``wostream operator<<``
(`#650 <https://github.com/fmtlib/fmt/issues/650>`_).
* Fixed compilation on OpenBSD
(`#660 <https://github.com/fmtlib/fmt/pull/660>`_).
Thanks `@hubslave <https://github.com/hubslave>`_.
* Fixed compilation on FreeBSD 12
(`#732 <https://github.com/fmtlib/fmt/pull/732>`_).
Thanks `@dankm <https://github.com/dankm>`_.
* Fixed compilation when there is a mismatch between ``-std`` options between
the library and user code
(`#664 <https://github.com/fmtlib/fmt/issues/664>`_).
* Fixed compilation with GCC 7 and ``-std=c++11``
(`#734 <https://github.com/fmtlib/fmt/issues/734>`_).
* Improved generated binary code on GCC 7 and older
(`#668 <https://github.com/fmtlib/fmt/issues/668>`_).
* Fixed handling of numeric alignment with no width
(`#675 <https://github.com/fmtlib/fmt/issues/675>`_).
* Fixed handling of empty strings in UTF8/16 converters
(`#676 <https://github.com/fmtlib/fmt/pull/676>`_).
Thanks `@vgalka-sl (Vasili Galka) <https://github.com/vgalka-sl>`_.
* Fixed formatting of an empty ``string_view``
(`#689 <https://github.com/fmtlib/fmt/issues/689>`_).
* Fixed detection of ``string_view`` on libc++
(`#686 <https://github.com/fmtlib/fmt/issues/686>`_).
* Fixed DLL issues (`#696 <https://github.com/fmtlib/fmt/pull/696>`_).
Thanks `@sebkoenig <https://github.com/sebkoenig>`_.
* Fixed compile checks for mixing narrow and wide strings
(`#690 <https://github.com/fmtlib/fmt/issues/690>`_).
* Disabled unsafe implicit conversion to ``std::string``
(`#729 <https://github.com/fmtlib/fmt/issues/729>`_).
* Fixed handling of reused format specs (as in ``fmt::join``) for pointers
(`#725 <https://github.com/fmtlib/fmt/pull/725>`_).
Thanks `@mwinterb <https://github.com/mwinterb>`_.
* Fixed installation of ``fmt/ranges.h``
(`#738 <https://github.com/fmtlib/fmt/pull/738>`_).
Thanks `@sv1990 <https://github.com/sv1990>`_.
4.1.0 - 2017-12-20
------------------
* Added ``fmt::to_wstring()`` in addition to ``fmt::to_string()`` (`#559 <https://github.com/fmtlib/fmt/pull/559>`_). Thanks `@alabuzhev (Alex Alabuzhev) <https://github.com/alabuzhev>`_.
* Added ``fmt::to_wstring()`` in addition to ``fmt::to_string()``
(`#559 <https://github.com/fmtlib/fmt/pull/559>`_).
Thanks `@alabuzhev (Alex Alabuzhev) <https://github.com/alabuzhev>`_.
* Added support for C++17 ``std::string_view`` (`#571 <https://github.com/fmtlib/fmt/pull/571>`_ and `#578 <https://github.com/fmtlib/fmt/pull/578>`_). Thanks `@thelostt (Mário Feroldi) <https://github.com/thelostt>`_ and `@mwinterb <https://github.com/mwinterb>`_.
* Added support for C++17 ``std::string_view``
(`#571 <https://github.com/fmtlib/fmt/pull/571>`_ and
`#578 <https://github.com/fmtlib/fmt/pull/578>`_).
Thanks `@thelostt (Mário Feroldi) <https://github.com/thelostt>`_ and
`@mwinterb <https://github.com/mwinterb>`_.
* Enabled stream exceptions to catch errors (`#581 <https://github.com/fmtlib/fmt/issues/581>`_). Thanks `@crusader-mike <https://github.com/crusader-mike>`_.
* Enabled stream exceptions to catch errors
(`#581 <https://github.com/fmtlib/fmt/issues/581>`_).
Thanks `@crusader-mike <https://github.com/crusader-mike>`_.
* Allowed formatting of class hierarchies with ``fmt::format_arg()`` (`#547 <https://github.com/fmtlib/fmt/pull/547>`_). Thanks `@rollbear (Björn Fahller) <https://github.com/rollbear>`_.
* Allowed formatting of class hierarchies with ``fmt::format_arg()``
(`#547 <https://github.com/fmtlib/fmt/pull/547>`_).
Thanks `@rollbear (Björn Fahller) <https://github.com/rollbear>`_.
* Removed limitations on character types
(`#563 <https://github.com/fmtlib/fmt/pull/563>`_).
Thanks `@Yelnats321 (Elnar Dakeshov) <https://github.com/Yelnats321>`_.
* Conditionally enabled use of ``std::allocator_traits`` (`#583 <https://github.com/fmtlib/fmt/pull/583>`_). Thanks `@mwinterb <https://github.com/mwinterb>`_.
* Conditionally enabled use of ``std::allocator_traits``
(`#583 <https://github.com/fmtlib/fmt/pull/583>`_).
Thanks `@mwinterb <https://github.com/mwinterb>`_.
* Added support for ``const`` variadic member function emulation with ``FMT_VARIADIC_CONST`` (`#591 <https://github.com/fmtlib/fmt/pull/591>`_). Thanks `@ludekvodicka (Ludek Vodicka) <https://github.com/ludekvodicka>`_.
* Added support for ``const`` variadic member function emulation with
``FMT_VARIADIC_CONST`` (`#591 <https://github.com/fmtlib/fmt/pull/591>`_).
Thanks `@ludekvodicka (Ludek Vodicka) <https://github.com/ludekvodicka>`_.
* Various bugfixes: bad overflow check, unsupported implicit type conversion when determining formatting function, test segfaults (`#551 <https://github.com/fmtlib/fmt/issues/551>`_), ill-formed macros (`#542 <https://github.com/fmtlib/fmt/pull/542>`_) and ambiguous overloads (`#580 <https://github.com/fmtlib/fmt/issues/580>`_). Thanks `@xylosper (Byoung-young Lee) <https://github.com/xylosper>`_.
* Various bugfixes: bad overflow check, unsupported implicit type conversion
when determining formatting function, test segfaults
(`#551 <https://github.com/fmtlib/fmt/issues/551>`_), ill-formed macros
(`#542 <https://github.com/fmtlib/fmt/pull/542>`_) and ambiguous overloads
(`#580 <https://github.com/fmtlib/fmt/issues/580>`_).
Thanks `@xylosper (Byoung-young Lee) <https://github.com/xylosper>`_.
* Prevented warnings on MSVC (`#605 <https://github.com/fmtlib/fmt/pull/605>`_, `#602 <https://github.com/fmtlib/fmt/pull/602>`_, and `#545 <https://github.com/fmtlib/fmt/pull/545>`_), clang (`#582 <https://github.com/fmtlib/fmt/pull/582>`_), GCC (`#573 <https://github.com/fmtlib/fmt/issues/573>`_), various conversion warnings (`#609 <https://github.com/fmtlib/fmt/pull/609>`_, `#567 <https://github.com/fmtlib/fmt/pull/567>`_, `#553 <https://github.com/fmtlib/fmt/pull/553>`_ and `#553 <https://github.com/fmtlib/fmt/pull/553>`_), and added ``override`` and ``[[noreturn]]`` (`#549 <https://github.com/fmtlib/fmt/pull/549>`_ and `#555 <https://github.com/fmtlib/fmt/issues/555>`_). Thanks `@alabuzhev (Alex Alabuzhev) <https://github.com/alabuzhev>`_, `@virgiliofornazin (Virgilio Alexandre Fornazin) <https://gihtub.com/virgiliofornazin>`_, `@alexanderbock (Alexander Bock) <https://github.com/alexanderbock>`_, `@yumetodo <https://github.com/yumetodo>`_, `@VaderY (Császár Mátyás) <https://github.com/VaderY>`_, `@jpcima (JP Cimalando) <https://github.com/jpcima>`_, `@thelostt (Mário Feroldi) <https://github.com/thelostt>`_, and `@Manu343726 (Manu Sánchez) <https://github.com/Manu343726>`_.
* Prevented warnings on MSVC (`#605 <https://github.com/fmtlib/fmt/pull/605>`_,
`#602 <https://github.com/fmtlib/fmt/pull/602>`_, and
`#545 <https://github.com/fmtlib/fmt/pull/545>`_),
clang (`#582 <https://github.com/fmtlib/fmt/pull/582>`_),
GCC (`#573 <https://github.com/fmtlib/fmt/issues/573>`_),
various conversion warnings (`#609 <https://github.com/fmtlib/fmt/pull/609>`_,
`#567 <https://github.com/fmtlib/fmt/pull/567>`_,
`#553 <https://github.com/fmtlib/fmt/pull/553>`_ and
`#553 <https://github.com/fmtlib/fmt/pull/553>`_), and added ``override`` and
``[[noreturn]]`` (`#549 <https://github.com/fmtlib/fmt/pull/549>`_ and
`#555 <https://github.com/fmtlib/fmt/issues/555>`_).
Thanks `@alabuzhev (Alex Alabuzhev) <https://github.com/alabuzhev>`_,
`@virgiliofornazin (Virgilio Alexandre Fornazin)
<https://gihtub.com/virgiliofornazin>`_,
`@alexanderbock (Alexander Bock) <https://github.com/alexanderbock>`_,
`@yumetodo <https://github.com/yumetodo>`_,
`@VaderY (Császár Mátyás) <https://github.com/VaderY>`_,
`@jpcima (JP Cimalando) <https://github.com/jpcima>`_,
`@thelostt (Mário Feroldi) <https://github.com/thelostt>`_, and
`@Manu343726 (Manu Sánchez) <https://github.com/Manu343726>`_.
* Improved CMake: Used GNUInstallDirs to set installation location (`#610 <https://github.com/fmtlib/fmt/pull/610>`_) and fixed warnings (`#536 <https://github.com/fmtlib/fmt/pull/536>`_ and `#556 <https://github.com/fmtlib/fmt/pull/556>`_). Thanks `@mikecrowe (Mike Crowe) <https://github.com/mikecrowe>`_, `@evgen231 <https://github.com/evgen231>`_ and `@henryiii (Henry Schreiner) <https://github.com/henryiii>`_.
* Improved CMake: Used ``GNUInstallDirs`` to set installation location
(`#610 <https://github.com/fmtlib/fmt/pull/610>`_) and fixed warnings
(`#536 <https://github.com/fmtlib/fmt/pull/536>`_ and
`#556 <https://github.com/fmtlib/fmt/pull/556>`_).
Thanks `@mikecrowe (Mike Crowe) <https://github.com/mikecrowe>`_,
`@evgen231 <https://github.com/evgen231>`_ and
`@henryiii (Henry Schreiner) <https://github.com/henryiii>`_.
4.0.0 - 2017-06-27
------------------
* Removed old compatibility headers ``cppformat/*.h`` and CMake options (`#527 <https://github.com/fmtlib/fmt/pull/527>`_). Thanks `@maddinat0r (Alex Martin) <https://github.com/maddinat0r>`_.
* Removed old compatibility headers ``cppformat/*.h`` and CMake options
(`#527 <https://github.com/fmtlib/fmt/pull/527>`_).
Thanks `@maddinat0r (Alex Martin) <https://github.com/maddinat0r>`_.
* Added ``string.h`` containing ``fmt::to_string()`` as alternative to ``std::to_string()`` as well as other string writer functionality (`#326 <https://github.com/fmtlib/fmt/issues/326>`_ and `#441 <https://github.com/fmtlib/fmt/pull/441>`_):
* Added ``string.h`` containing ``fmt::to_string()`` as alternative to
``std::to_string()`` as well as other string writer functionality
(`#326 <https://github.com/fmtlib/fmt/issues/326>`_ and
`#441 <https://github.com/fmtlib/fmt/pull/441>`_):
.. code:: c++
@@ -36,9 +516,17 @@
std::string answer = fmt::to_string(42);
Thanks to `@glebov-andrey (Andrey Glebov) <https://github.com/glebov-andrey>`_.
Thanks to `@glebov-andrey (Andrey Glebov)
<https://github.com/glebov-andrey>`_.
* Moved ``fmt::printf()`` to new ``printf.h`` header and allowed ``%s`` as generic specifier (`#453 <https://github.com/fmtlib/fmt/pull/453>`_), made ``%.f`` more conformant to regular ``printf()`` (`#490 <https://github.com/fmtlib/fmt/pull/490>`_), added custom writer support (`#476 <https://github.com/fmtlib/fmt/issues/476>`_) and implemented missing custom argument formatting (`#339 <https://github.com/fmtlib/fmt/pull/339>`_ and `#340 <https://github.com/fmtlib/fmt/pull/340>`_):
* Moved ``fmt::printf()`` to new ``printf.h`` header and allowed ``%s`` as
generic specifier (`#453 <https://github.com/fmtlib/fmt/pull/453>`_),
made ``%.f`` more conformant to regular ``printf()``
(`#490 <https://github.com/fmtlib/fmt/pull/490>`_), added custom writer
support (`#476 <https://github.com/fmtlib/fmt/issues/476>`_) and implemented
missing custom argument formatting
(`#339 <https://github.com/fmtlib/fmt/pull/339>`_ and
`#340 <https://github.com/fmtlib/fmt/pull/340>`_):
.. code:: c++
@@ -47,11 +535,21 @@
// %s format specifier can be used with any argument type.
fmt::printf("%s", 42);
Thanks `@mojoBrendan <https://github.com/mojoBrendan>`_, `@manylegged (Arthur Danskin) <https://github.com/manylegged>`_ and `@spacemoose (Glen Stark) <https://github.com/spacemoose>`_. See also `#360 <https://github.com/fmtlib/fmt/issues/360>`_, `#335 <https://github.com/fmtlib/fmt/issues/335>`_ and `#331 <https://github.com/fmtlib/fmt/issues/331>`_.
Thanks `@mojoBrendan <https://github.com/mojoBrendan>`_,
`@manylegged (Arthur Danskin) <https://github.com/manylegged>`_ and
`@spacemoose (Glen Stark) <https://github.com/spacemoose>`_.
See also `#360 <https://github.com/fmtlib/fmt/issues/360>`_,
`#335 <https://github.com/fmtlib/fmt/issues/335>`_ and
`#331 <https://github.com/fmtlib/fmt/issues/331>`_.
* Added ``container.h`` containing a ``BasicContainerWriter`` to write to containers like ``std::vector`` (`#450 <https://github.com/fmtlib/fmt/pull/450>`_). Thanks `@polyvertex (Jean-Charles Lefebvre) <https://github.com/polyvertex>`_.
* Added ``container.h`` containing a ``BasicContainerWriter``
to write to containers like ``std::vector``
(`#450 <https://github.com/fmtlib/fmt/pull/450>`_).
Thanks `@polyvertex (Jean-Charles Lefebvre) <https://github.com/polyvertex>`_.
* Added ``fmt::join()`` function that takes a range and formats its elements separated by a given string (`#466 <https://github.com/fmtlib/fmt/pull/466>`_):
* Added ``fmt::join()`` function that takes a range and formats
its elements separated by a given string
(`#466 <https://github.com/fmtlib/fmt/pull/466>`_):
.. code:: c++
@@ -63,75 +561,174 @@
Thanks `@olivier80 <https://github.com/olivier80>`_.
* Added support for custom formatting specifications to simplify customization of built-in formatting (`#444 <https://github.com/fmtlib/fmt/pull/444>`_). Thanks `@polyvertex (Jean-Charles Lefebvre) <https://github.com/polyvertex>`_. See also `#439 <https://github.com/fmtlib/fmt/issues/439>`_.
* Added support for custom formatting specifications to simplify customization
of built-in formatting (`#444 <https://github.com/fmtlib/fmt/pull/444>`_).
Thanks `@polyvertex (Jean-Charles Lefebvre) <https://github.com/polyvertex>`_.
See also `#439 <https://github.com/fmtlib/fmt/issues/439>`_.
* Added ``fmt::format_system_error()`` for error code formatting (`#323 <https://github.com/fmtlib/fmt/issues/323>`_ and `#526 <https://github.com/fmtlib/fmt/pull/526>`_). Thanks `@maddinat0r (Alex Martin) <https://github.com/maddinat0r>`_.
* Added ``fmt::format_system_error()`` for error code formatting
(`#323 <https://github.com/fmtlib/fmt/issues/323>`_ and
`#526 <https://github.com/fmtlib/fmt/pull/526>`_).
Thanks `@maddinat0r (Alex Martin) <https://github.com/maddinat0r>`_.
* Added thread-safe ``fmt::localtime()`` and ``fmt::gmtime()`` as replacement for the standard version to ``time.h`` (`#396 <https://github.com/fmtlib/fmt/pull/396>`_). Thanks `@codicodi <https://github.com/codicodi>`_.
* Added thread-safe ``fmt::localtime()`` and ``fmt::gmtime()``
as replacement for the standard version to ``time.h``
(`#396 <https://github.com/fmtlib/fmt/pull/396>`_).
Thanks `@codicodi <https://github.com/codicodi>`_.
* Internal improvements to ``NamedArg`` and ``ArgLists`` (`#389 <https://github.com/fmtlib/fmt/pull/389>`_ and `#390 <https://github.com/fmtlib/fmt/pull/390>`_). Thanks `@chronoxor <https://github.com/chronoxor>`_.
* Internal improvements to ``NamedArg`` and ``ArgLists``
(`#389 <https://github.com/fmtlib/fmt/pull/389>`_ and
`#390 <https://github.com/fmtlib/fmt/pull/390>`_).
Thanks `@chronoxor <https://github.com/chronoxor>`_.
* Fixed crash due to bug in ``FormatBuf`` (`#493 <https://github.com/fmtlib/fmt/pull/493>`_). Thanks `@effzeh <https://github.com/effzeh>`_. See also `#480 <https://github.com/fmtlib/fmt/issues/480>`_ and `#491 <https://github.com/fmtlib/fmt/issues/491>`_.
* Fixed crash due to bug in ``FormatBuf``
(`#493 <https://github.com/fmtlib/fmt/pull/493>`_).
Thanks `@effzeh <https://github.com/effzeh>`_. See also
`#480 <https://github.com/fmtlib/fmt/issues/480>`_ and
`#491 <https://github.com/fmtlib/fmt/issues/491>`_.
* Fixed handling of wide strings in ``fmt::StringWriter``.
* Improved compiler error messages (`#357 <https://github.com/fmtlib/fmt/issues/357>`_).
* Improved compiler error messages
(`#357 <https://github.com/fmtlib/fmt/issues/357>`_).
* Fixed various warnings and issues with various compilers (`#494 <https://github.com/fmtlib/fmt/pull/494>`_, `#499 <https://github.com/fmtlib/fmt/pull/499>`_, `#483 <https://github.com/fmtlib/fmt/pull/483>`_, `#519 <https://github.com/fmtlib/fmt/pull/519>`_, `#485 <https://github.com/fmtlib/fmt/pull/485>`_, `#482 <https://github.com/fmtlib/fmt/pull/482>`_, `#475 <https://github.com/fmtlib/fmt/pull/475>`_, `#473 <https://github.com/fmtlib/fmt/pull/473>`_ and `#414 <https://github.com/fmtlib/fmt/pull/414>`_). Thanks `@chronoxor <https://github.com/chronoxor>`_, `@zhaohuaxishi <https://github.com/zhaohuaxishi>`_, `@pkestene (Pierre Kestener) <https://github.com/pkestene>`_, `@dschmidt (Dominik Schmidt) <https://github.com/dschmidt>`_ and `@0x414c (Alexey Gorishny) <https://github.com/0x414c>`_ .
* Fixed various warnings and issues with various compilers
(`#494 <https://github.com/fmtlib/fmt/pull/494>`_,
`#499 <https://github.com/fmtlib/fmt/pull/499>`_,
`#483 <https://github.com/fmtlib/fmt/pull/483>`_,
`#485 <https://github.com/fmtlib/fmt/pull/485>`_,
`#482 <https://github.com/fmtlib/fmt/pull/482>`_,
`#475 <https://github.com/fmtlib/fmt/pull/475>`_,
`#473 <https://github.com/fmtlib/fmt/pull/473>`_ and
`#414 <https://github.com/fmtlib/fmt/pull/414>`_).
Thanks `@chronoxor <https://github.com/chronoxor>`_,
`@zhaohuaxishi <https://github.com/zhaohuaxishi>`_,
`@pkestene (Pierre Kestener) <https://github.com/pkestene>`_,
`@dschmidt (Dominik Schmidt) <https://github.com/dschmidt>`_ and
`@0x414c (Alexey Gorishny) <https://github.com/0x414c>`_ .
* Improved CMake: targets are now namespaced (`#511 <https://github.com/fmtlib/fmt/pull/511>`_ and `#513 <https://github.com/fmtlib/fmt/pull/513>`_), supported header-only ``printf.h`` (`#354 <https://github.com/fmtlib/fmt/pull/354>`_), fixed issue with minimal supported library subset (`#418 <https://github.com/fmtlib/fmt/issues/418>`_, `#419 <https://github.com/fmtlib/fmt/pull/419>`_ and `#420 <https://github.com/fmtlib/fmt/pull/420>`_). Thanks `@bjoernthiel (Bjoern Thiel) <https://github.com/bjoernthiel>`_,
`@niosHD (Mario Werner) <https://github.com/niosHD>`_, `@LogicalKnight (Sean LK) <https://github.com/LogicalKnight>`_ and `@alabuzhev (Alex Alabuzhev) <https://github.com/alabuzhev>`_.
* Improved CMake: targets are now namespaced
(`#511 <https://github.com/fmtlib/fmt/pull/511>`_ and
`#513 <https://github.com/fmtlib/fmt/pull/513>`_), supported header-only
``printf.h`` (`#354 <https://github.com/fmtlib/fmt/pull/354>`_), fixed issue
with minimal supported library subset
(`#418 <https://github.com/fmtlib/fmt/issues/418>`_,
`#419 <https://github.com/fmtlib/fmt/pull/419>`_ and
`#420 <https://github.com/fmtlib/fmt/pull/420>`_).
Thanks `@bjoernthiel (Bjoern Thiel) <https://github.com/bjoernthiel>`_,
`@niosHD (Mario Werner) <https://github.com/niosHD>`_,
`@LogicalKnight (Sean LK) <https://github.com/LogicalKnight>`_ and
`@alabuzhev (Alex Alabuzhev) <https://github.com/alabuzhev>`_.
* Improved documentation. Thanks to `@pwm1234 (Phil) <https://github.com/pwm1234>`_ for `#393 <https://github.com/fmtlib/fmt/pull/393>`_.
* Improved documentation. Thanks to
`@pwm1234 (Phil) <https://github.com/pwm1234>`_ for
`#393 <https://github.com/fmtlib/fmt/pull/393>`_.
3.0.2 - 2017-06-14
------------------
* Added ``FMT_VERSION`` macro (`#411 <https://github.com/fmtlib/fmt/issues/411>`_).
* Added ``FMT_VERSION`` macro
(`#411 <https://github.com/fmtlib/fmt/issues/411>`_).
* Used ``FMT_NULL`` instead of literal ``0`` (`#409 <https://github.com/fmtlib/fmt/pull/409>`_). Thanks `@alabuzhev (Alex Alabuzhev) <https://github.com/alabuzhev>`_.
* Used ``FMT_NULL`` instead of literal ``0``
(`#409 <https://github.com/fmtlib/fmt/pull/409>`_).
Thanks `@alabuzhev (Alex Alabuzhev) <https://github.com/alabuzhev>`_.
* Added extern templates for ``format_float`` (`#413 <https://github.com/fmtlib/fmt/issues/413>`_).
* Added extern templates for ``format_float``
(`#413 <https://github.com/fmtlib/fmt/issues/413>`_).
* Fixed implicit conversion issue (`#507 <https://github.com/fmtlib/fmt/issues/507>`_).
* Fixed implicit conversion issue
(`#507 <https://github.com/fmtlib/fmt/issues/507>`_).
* Fixed signbit detection (`#423 <https://github.com/fmtlib/fmt/issues/423>`_).
* Fixed naming collision (`#425 <https://github.com/fmtlib/fmt/issues/425>`_).
* Fixed missing intrinsic for C++/CLI (`#457 <https://github.com/fmtlib/fmt/pull/457>`_). Thanks `@calumr (Calum Robinson) <https://github.com/calumr>`_
* Fixed missing intrinsic for C++/CLI
(`#457 <https://github.com/fmtlib/fmt/pull/457>`_).
Thanks `@calumr (Calum Robinson) <https://github.com/calumr>`_
* Fixed Android detection (`#458 <https://github.com/fmtlib/fmt/pull/458>`_). Thanks `@Gachapen (Magnus Bjerke Vik) <https://github.com/Gachapen>`_.
* Fixed Android detection (`#458 <https://github.com/fmtlib/fmt/pull/458>`_).
Thanks `@Gachapen (Magnus Bjerke Vik) <https://github.com/Gachapen>`_.
* Use lean ``windows.h`` if not in header-only mode (`#503 <https://github.com/fmtlib/fmt/pull/503>`_). Thanks `@Quentin01 (Quentin Buathier) <https://github.com/Quentin01>`_.
* Use lean ``windows.h`` if not in header-only mode
(`#503 <https://github.com/fmtlib/fmt/pull/503>`_).
Thanks `@Quentin01 (Quentin Buathier) <https://github.com/Quentin01>`_.
* Fixed issue with CMake exporting C++11 flag (`#445 <https://github.com/fmtlib/fmt/pull/455>`_). Thanks `@EricWF (Eric) <https://github.com/EricWF>`_.
* Fixed issue with CMake exporting C++11 flag
(`#445 <https://github.com/fmtlib/fmt/pull/455>`_).
Thanks `@EricWF (Eric) <https://github.com/EricWF>`_.
* Fixed issue with nvcc and MSVC compiler bug and MinGW (`#505 <https://github.com/fmtlib/fmt/issues/505>`_).
* Fixed issue with nvcc and MSVC compiler bug and MinGW
(`#505 <https://github.com/fmtlib/fmt/issues/505>`_).
* Fixed DLL issues (`#469 <https://github.com/fmtlib/fmt/pull/469>`_ and `#502 <https://github.com/fmtlib/fmt/pull/502>`_). Thanks `@richardeakin (Richard Eakin) <https://github.com/richardeakin>`_ and `@AndreasSchoenle (Andreas Schönle) <https://github.com/AndreasSchoenle>`_.
* Fixed DLL issues (`#469 <https://github.com/fmtlib/fmt/pull/469>`_ and
`#502 <https://github.com/fmtlib/fmt/pull/502>`_).
Thanks `@richardeakin (Richard Eakin) <https://github.com/richardeakin>`_ and
`@AndreasSchoenle (Andreas Schönle) <https://github.com/AndreasSchoenle>`_.
* Fixed test compilation under FreeBSD (`#433 <https://github.com/fmtlib/fmt/issues/433>`_).
* Fixed test compilation under FreeBSD
(`#433 <https://github.com/fmtlib/fmt/issues/433>`_).
* Fixed various warnings (`#403 <https://github.com/fmtlib/fmt/pull/403>`_, `#410 <https://github.com/fmtlib/fmt/pull/410>`_ and `#510 <https://github.com/fmtlib/fmt/pull/510>`_). Thanks `@Lecetem <https://github.com/Lectem>`_, `@chenhayat (Chen Hayat) <https://github.com/chenhayat>`_ and `@trozen <https://github.com/trozen>`_.
* Fixed various warnings (`#403 <https://github.com/fmtlib/fmt/pull/403>`_,
`#410 <https://github.com/fmtlib/fmt/pull/410>`_ and
`#510 <https://github.com/fmtlib/fmt/pull/510>`_).
Thanks `@Lecetem <https://github.com/Lectem>`_,
`@chenhayat (Chen Hayat) <https://github.com/chenhayat>`_ and
`@trozen <https://github.com/trozen>`_.
* Removed redundant include (`#479 <https://github.com/fmtlib/fmt/issues/479>`_).
* Worked around a broken ``__builtin_clz`` in clang with MS codegen
(`#519 <https://github.com/fmtlib/fmt/issues/519>`_).
* Removed redundant include
(`#479 <https://github.com/fmtlib/fmt/issues/479>`_).
* Fixed documentation issues.
3.0.1 - 2016-11-01
------------------
* Fixed handling of thousands seperator (`#353 <https://github.com/fmtlib/fmt/issues/353>`_)
* Fixed handling of thousands seperator
(`#353 <https://github.com/fmtlib/fmt/issues/353>`_).
* Fixed handling of ``unsigned char`` strings (`#373 <https://github.com/fmtlib/fmt/issues/373>`_)
* Fixed handling of ``unsigned char`` strings
(`#373 <https://github.com/fmtlib/fmt/issues/373>`_).
* Corrected buffer growth when formatting time (`#367 <https://github.com/fmtlib/fmt/issues/367>`_)
* Corrected buffer growth when formatting time
(`#367 <https://github.com/fmtlib/fmt/issues/367>`_).
* Removed warnings under MSVC and clang (`#318 <https://github.com/fmtlib/fmt/issues/318>`_, `#250 <https://github.com/fmtlib/fmt/issues/250>`_, also merged `#385 <https://github.com/fmtlib/fmt/pull/385>`_ and `#361 <https://github.com/fmtlib/fmt/pull/361>`_). Thanks `@jcelerier (Jean-Michaël Celerier) <https://github.com/jcelerier>`_ and `@nmoehrle (Nils Moehrle) <https://github.com/nmoehrle>`_.
* Removed warnings under MSVC and clang
(`#318 <https://github.com/fmtlib/fmt/issues/318>`_,
`#250 <https://github.com/fmtlib/fmt/issues/250>`_, also merged
`#385 <https://github.com/fmtlib/fmt/pull/385>`_ and
`#361 <https://github.com/fmtlib/fmt/pull/361>`_).
Thanks `@jcelerier (Jean-Michaël Celerier) <https://github.com/jcelerier>`_
and `@nmoehrle (Nils Moehrle) <https://github.com/nmoehrle>`_.
* Fixed compilation issues under Android (`#327 <https://github.com/fmtlib/fmt/pull/327>`_, `#345 <https://github.com/fmtlib/fmt/issues/345>`_ and `#381 <https://github.com/fmtlib/fmt/pull/381>`_), FreeBSD (`#358 <https://github.com/fmtlib/fmt/pull/358>`_), Cygwin (`#388 <https://github.com/fmtlib/fmt/issues/388>`_), MinGW (`#355 <https://github.com/fmtlib/fmt/issues/355>`_) as well as other issues (`#350 <https://github.com/fmtlib/fmt/issues/350>`_, `#366 <https://github.com/fmtlib/fmt/issues/355>`_, `#348 <https://github.com/fmtlib/fmt/pull/348>`_, `#402 <https://github.com/fmtlib/fmt/pull/402>`_, `#405 <https://github.com/fmtlib/fmt/pull/405>`_). Thanks to `@dpantele (Dmitry) <https://github.com/dpantele>`_, `@hghwng (Hugh Wang) <https://github.com/hghwng>`_, `@arvedarved (Tilman Keskinöz) <https://github.com/arvedarved>`_, `@LogicalKnight (Sean) <https://github.com/LogicalKnight>`_ and `@JanHellwig (Jan Hellwig) <https://github.com/janhellwig>`_.
* Fixed some documentation issues and extended specification (`#320 <https://github.com/fmtlib/fmt/issues/320>`_, `#333 <https://github.com/fmtlib/fmt/pull/333>`_, `#347 <https://github.com/fmtlib/fmt/issues/347>`_, `#362 <https://github.com/fmtlib/fmt/pull/362>`_). Thanks to `@smellman (Taro Matsuzawa aka. btm) <https://github.com/smellman>`_.
* Fixed compilation issues under Android
(`#327 <https://github.com/fmtlib/fmt/pull/327>`_,
`#345 <https://github.com/fmtlib/fmt/issues/345>`_ and
`#381 <https://github.com/fmtlib/fmt/pull/381>`_),
FreeBSD (`#358 <https://github.com/fmtlib/fmt/pull/358>`_),
Cygwin (`#388 <https://github.com/fmtlib/fmt/issues/388>`_),
MinGW (`#355 <https://github.com/fmtlib/fmt/issues/355>`_) as well as other
issues (`#350 <https://github.com/fmtlib/fmt/issues/350>`_,
`#366 <https://github.com/fmtlib/fmt/issues/355>`_,
`#348 <https://github.com/fmtlib/fmt/pull/348>`_,
`#402 <https://github.com/fmtlib/fmt/pull/402>`_,
`#405 <https://github.com/fmtlib/fmt/pull/405>`_).
Thanks to `@dpantele (Dmitry) <https://github.com/dpantele>`_,
`@hghwng (Hugh Wang) <https://github.com/hghwng>`_,
`@arvedarved (Tilman Keskinöz) <https://github.com/arvedarved>`_,
`@LogicalKnight (Sean) <https://github.com/LogicalKnight>`_ and
`@JanHellwig (Jan Hellwig) <https://github.com/janhellwig>`_.
* Fixed some documentation issues and extended specification
(`#320 <https://github.com/fmtlib/fmt/issues/320>`_,
`#333 <https://github.com/fmtlib/fmt/pull/333>`_,
`#347 <https://github.com/fmtlib/fmt/issues/347>`_,
`#362 <https://github.com/fmtlib/fmt/pull/362>`_).
Thanks to `@smellman (Taro Matsuzawa aka. btm)
<https://github.com/smellman>`_.
3.0.0 - 2016-05-07
------------------
@@ -249,8 +846,8 @@
`@Gachapen (Magnus Bjerke Vik) <https://github.com/Gachapen>`_ and
`@jwilk (Jakub Wilk) <https://github.com/jwilk>`_.
* Fixed compiler and sanitizer warnings (
`#244 <https://github.com/fmtlib/fmt/issues/244>`_,
* Fixed compiler and sanitizer warnings
(`#244 <https://github.com/fmtlib/fmt/issues/244>`_,
`#256 <https://github.com/fmtlib/fmt/pull/256>`_,
`#259 <https://github.com/fmtlib/fmt/pull/259>`_,
`#263 <https://github.com/fmtlib/fmt/issues/263>`_,
@@ -670,8 +1267,8 @@ Fixes
`@Jopie64 (Johan) <https://github.com/Jopie64>`_.
* Fixed portability issues (mostly causing test failures) on ARM, ppc64, ppc64le,
s390x and SunOS 5.11 i386 (
`#138 <https://github.com/fmtlib/fmt/issues/138>`_,
s390x and SunOS 5.11 i386
(`#138 <https://github.com/fmtlib/fmt/issues/138>`_,
`#179 <https://github.com/fmtlib/fmt/issues/179>`_,
`#180 <https://github.com/fmtlib/fmt/issues/180>`_,
`#202 <https://github.com/fmtlib/fmt/issues/202>`_,

View File

@@ -11,50 +11,48 @@
:alt: Join the chat at https://gitter.im/fmtlib/fmt
:target: https://gitter.im/fmtlib/fmt
**fmt** is an open-source formatting library for C++.
It can be used as a safe alternative to printf or as a fast
alternative to IOStreams.
**{fmt}** is an open-source formatting library for C++.
It can be used as a safe and fast alternative to (s)printf and IOStreams.
`Documentation <http://fmtlib.net/latest/>`_
`Documentation <http://fmtlib.net/latest/>`__
This is a development branch that implements the C++ standards proposal `P0645
Text Formatting <http://fmtlib.net/Text%20Formatting.html>`__.
Released versions are available from the `Releases page
<https://github.com/fmtlib/fmt/releases>`__.
Features
--------
* Two APIs: faster concatenation-based `write API
<http://fmtlib.net/latest/api.html#write-api>`_ and slower,
but still very fast, replacement-based `format API
<http://fmtlib.net/latest/api.html#format-api>`_ with positional arguments
for localization.
* Write API similar to the one used by IOStreams but stateless allowing
faster implementation.
* Format API with `format string syntax
<http://fmtlib.net/latest/syntax.html>`_
similar to the one used by `str.format
<https://docs.python.org/2/library/stdtypes.html#str.format>`_ in Python.
* Replacement-based `format API <http://fmtlib.net/dev/api.html>`_ with
positional arguments for localization.
* `Format string syntax <http://fmtlib.net/dev/syntax.html>`_ similar to the one
of `str.format <https://docs.python.org/2/library/stdtypes.html#str.format>`_
in Python.
* Safe `printf implementation
<http://fmtlib.net/latest/api.html#printf-formatting-functions>`_
including the POSIX extension for positional arguments.
<http://fmtlib.net/latest/api.html#printf-formatting-functions>`_ including
the POSIX extension for positional arguments.
* Support for user-defined types.
* High speed: performance of the format API is close to that of
glibc's `printf <http://en.cppreference.com/w/cpp/io/c/fprintf>`_
and better than the performance of IOStreams. See `Speed tests`_ and
* High speed: performance of the format API is close to that of glibc's `printf
<http://en.cppreference.com/w/cpp/io/c/fprintf>`_ and better than the
performance of IOStreams. See `Speed tests`_ and
`Fast integer to string conversion in C++
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
* Small code size both in terms of source code (the core library consists of a single
header file and a single source file) and compiled code.
See `Compile time and code bloat`_.
* Small code size both in terms of source code (the minimum configuration
consists of just three header 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 `unit tests
<https://github.com/fmtlib/fmt/tree/master/test>`_.
* Safety: the library is fully type safe, errors in format strings are
reported using exceptions, automatic memory management prevents buffer
overflow errors.
* 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 BSD `license
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_
* `Portability <http://fmtlib.net/latest/index.html#portability>`_ with consistent output
across platforms and support for older compilers.
* `Portability <http://fmtlib.net/latest/index.html#portability>`_ with
consistent output across platforms and support for older compilers.
* Clean warning-free codebase even on high warning levels
(-Wall -Wextra -pedantic).
(``-Wall -Wextra -pedantic``).
* Support for wide strings.
* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro.
@@ -77,14 +75,37 @@ Arguments can be accessed by position and arguments' indices can be repeated:
std::string s = fmt::format("{0}{1}{0}", "abra", "cad");
// s == "abracadabra"
fmt can be used as a safe portable replacement for ``itoa``:
Format strings can be checked at compile time:
.. code:: c++
fmt::MemoryWriter w;
w << 42; // replaces itoa(42, buffer, 10)
w << fmt::hex(42); // replaces itoa(42, buffer, 16)
// access the string using w.str() or w.c_str()
// test.cc
#include <fmt/format.h>
std::string s = format(fmt("{2}"), 42);
.. code::
$ c++ -Iinclude -std=c++14 test.cc
...
test.cc:3:17: note: in instantiation of function template specialization 'fmt::v5::format<S, int>' requested here
std::string s = format(fmt("{2}"), 42);
^
include/fmt/core.h:778:19: note: non-constexpr function 'on_error' cannot be used in a constant expression
ErrorHandler::on_error(message);
^
include/fmt/format.h:2226:16: note: in call to '&checker.context_->on_error(&"argument index out of range"[0])'
context_.on_error("argument index out of range");
^
{fmt} can be used as a safe portable replacement for ``itoa``
(`godbolt <https://godbolt.org/g/NXmpU4>`_):
.. code:: c++
fmt::memory_buffer buf;
format_to(buf, "{}", 42); // replaces itoa(42, buffer, 10)
format_to(buf, "{:x}", 42); // replaces itoa(42, buffer, 16)
// access the string using to_string(buf) or buf.data()
An object of any user-defined type for which there is an overloaded
:code:`std::ostream` insertion operator (``operator<<``) can be formatted:
@@ -106,27 +127,27 @@ An object of any user-defined type for which there is an overloaded
std::string s = fmt::format("The date is {}", Date(2012, 12, 9));
// s == "The date is 2012-12-9"
You can use the `FMT_VARIADIC
<http://fmtlib.net/latest/api.html#utilities>`_
macro to create your own functions similar to `format
You can create your own functions similar to `format
<http://fmtlib.net/latest/api.html#format>`_ and
`print <http://fmtlib.net/latest/api.html#print>`_
which take arbitrary arguments:
which take arbitrary arguments (`godbolt <https://godbolt.org/g/MHjHVf>`_):
.. code:: c++
// Prints formatted error message.
void report_error(const char *format, fmt::ArgList args) {
void vreport_error(const char *format, fmt::format_args args) {
fmt::print("Error: ");
fmt::print(format, args);
fmt::vprint(format, args);
}
template <typename... Args>
void report_error(const char *format, const Args & ... args) {
vreport_error(format, fmt::make_format_args(args...));
}
FMT_VARIADIC(void, report_error, const char *)
report_error("file not found: {}", path);
Note that you only need to define one function that takes ``fmt::ArgList``
argument. ``FMT_VARIADIC`` automatically defines necessary wrappers that
accept variable number of arguments.
Note that ``vreport_error`` is not parameterized on argument types which can
improve compile times and reduce code size compared to fully parameterized version.
Projects using this library
---------------------------
@@ -135,15 +156,11 @@ Projects using this library
* `AMPL/MP <https://github.com/ampl/mp>`_:
An open-source library for mathematical programming
* `AvioBook <https://www.aviobook.aero/en>`_: A comprehensive aircraft operations suite
* `CUAUV <http://cuauv.org/>`_: Cornell University's autonomous underwater vehicle
* `Drake <http://drake.mit.edu/>`_: A planning, control, and analysis toolbox for nonlinear dynamical systems (MIT)
* `Envoy <https://lyft.github.io/envoy/>`_: C++ L7 proxy and communication bus (Lyft)
* `FiveM <https://fivem.net/>`_: a modification framework for GTA V
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
Player vs Player Gaming Network with tweaks
@@ -155,14 +172,25 @@ Projects using this library
* `Lifeline <https://github.com/peter-clark/lifeline>`_: A 2D game
* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to generate randomized datasets
* `Drake <http://drake.mit.edu/>`_: A planning, control, and analysis toolbox
for nonlinear dynamical systems (MIT)
* `OpenSpace <http://openspaceproject.com/>`_: An open-source astrovisualization framework
* `Envoy <https://lyft.github.io/envoy/>`_: C++ L7 proxy and communication bus
(Lyft)
* `FiveM <https://fivem.net/>`_: a modification framework for GTA V
* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to
generate randomized datasets
* `OpenSpace <http://openspaceproject.com/>`_: An open-source astrovisualization
framework
* `PenUltima Online (POL) <http://www.polserver.com/>`_:
An MMO server, compatible with most Ultima Online clients
* `quasardb <https://www.quasardb.net/>`_: A distributed, high-performance, associative database
* `quasardb <https://www.quasardb.net/>`_: A distributed, high-performance,
associative database
* `readpe <https://bitbucket.org/sys_dev/readpe>`_: Read Portable Executable
@@ -308,11 +336,12 @@ further details see the `source
================= ============= ===========
Library Method Run Time, s
================= ============= ===========
EGLIBC 2.19 printf 1.30
libstdc++ 4.8.2 std::ostream 1.85
fmt 1.0 fmt::print 1.42
tinyformat 2.0.1 tfm::printf 2.25
Boost Format 1.54 boost::format 9.94
libc printf 1.35
libc++ std::ostream 3.42
fmt 534bff7 fmt::print 1.56
tinyformat 2.0.1 tfm::printf 3.73
Boost Format 1.54 boost::format 8.44
Folly Format folly::format 2.54
================= ============= ===========
As you can see ``boost::format`` is much slower than the alternative methods; this
@@ -332,38 +361,45 @@ from `format-benchmark <https://github.com/fmtlib/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 (g++-4.8.1, Ubuntu GNU/Linux 13.10,
best of three) is shown in the following tables.
executable size and compile time (Apple LLVM version 8.1.0 (clang-802.0.42),
macOS Sierra, best of three) is shown in the following tables.
**Optimized build (-O3)**
============ =============== ==================== ==================
Method Compile Time, s Executable size, KiB Stripped size, KiB
============ =============== ==================== ==================
printf 2.6 41 30
IOStreams 19.4 92 70
fmt 46.8 46 34
tinyformat 64.6 418 386
Boost Format 222.8 990 923
============ =============== ==================== ==================
============= =============== ==================== ==================
Method Compile Time, s Executable size, KiB Stripped size, KiB
============= =============== ==================== ==================
printf 2.7 29 26
printf+string 18.4 29 26
IOStreams 34.6 59 55
fmt 22.0 37 34
tinyformat 51.8 103 97
Boost Format 120.5 762 739
Folly Format 158.7 102 87
============= =============== ==================== ==================
As you can see, fmt has two times less overhead in terms of resulting
code size compared to IOStreams and comes pretty close to ``printf``.
Boost Format has by far the largest overheads.
As you can see, fmt has 60% less overhead in terms of resulting binary code
size compared to IOStreams and comes pretty close to ``printf``. Boost Format
has by far the largest overheads.
``printf+string`` is the same as ``printf`` but with extra ``<string>``
include to measure the overhead of the latter.
**Non-optimized build**
============ =============== ==================== ==================
Method Compile Time, s Executable size, KiB Stripped size, KiB
============ =============== ==================== ==================
printf 2.1 41 30
IOStreams 19.7 86 62
fmt 47.9 108 86
tinyformat 27.7 234 190
Boost Format 122.6 884 763
============ =============== ==================== ==================
============= =============== ==================== ==================
Method Compile Time, s Executable size, KiB Stripped size, KiB
============= =============== ==================== ==================
printf 2.4 33 30
printf+string 18.5 33 30
IOStreams 31.9 56 52
fmt 20.9 56 51
tinyformat 38.9 88 82
Boost Format 64.8 366 304
Folly Format 113.5 442 428
============= =============== ==================== ==================
``libc``, ``libstdc++`` and ``libfmt`` are all linked as shared
``libc``, ``lib(std)c++`` and ``libfmt`` are all linked as shared
libraries to compare formatting function overhead only. Boost Format
and tinyformat are header-only libraries so they don't provide any
linkage options.
@@ -412,10 +448,13 @@ It only applies if you distribute the documentation of fmt.
Acknowledgments
---------------
The fmt library is maintained by Victor Zverovich (`vitaut <https://github.com/vitaut>`_)
and Jonathan Müller (`foonathan <https://github.com/foonathan>`_) with contributions from many
other people. See `Contributors <https://github.com/fmtlib/fmt/graphs/contributors>`_ and `Releases <https://github.com/fmtlib/fmt/releases>`_ for some of the names. Let us know if your contribution
is not listed or mentioned incorrectly and we'll make it right.
The fmt library is maintained by Victor Zverovich (`vitaut
<https://github.com/vitaut>`_) and Jonathan Müller (`foonathan
<https://github.com/foonathan>`_) with contributions from many other people.
See `Contributors <https://github.com/fmtlib/fmt/graphs/contributors>`_ and
`Releases <https://github.com/fmtlib/fmt/releases>`_ for some of the names.
Let us know if your contribution is not listed or mentioned incorrectly and
we'll make it right.
The benchmark section of this readme file and the performance tests are taken
from the excellent `tinyformat <https://github.com/c42f/tinyformat>`_ library

View File

@@ -6,7 +6,7 @@ endif ()
add_custom_target(doc
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build.py ${FMT_VERSION}
SOURCES build.py conf.py _templates/layout.html)
SOURCES api.rst syntax.rst build.py conf.py _templates/layout.html)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/
DESTINATION share/doc/fmt OPTIONAL)

View File

@@ -4,52 +4,272 @@
API Reference
*************
All functions and classes provided by the fmt library reside
in namespace ``fmt`` and macros have prefix ``FMT_``. For brevity the
namespace is usually omitted in examples.
The {fmt} library API consists of the following parts:
Format API
==========
* :ref:`fmt/core.h <core-api>`: the core API providing argument handling
facilities and a lightweight subset of formatting functions
* :ref:`fmt/format.h <format-api>`: the full format API providing compile-time
format string checks, output iterator and user-defined type support
* :ref:`fmt/time.h <time-api>`: date and time formatting
* :ref:`fmt/ostream.h <ostream-api>`: ``std::ostream`` support
* :ref:`fmt/printf.h <printf-api>`: ``printf`` formatting
The following functions defined in ``fmt/format.h`` use :ref:`format string
syntax <syntax>` similar to the one used by Python's `str.format
<http://docs.python.org/3/library/stdtypes.html#str.format>`_ function.
All functions and types provided by the library reside in namespace ``fmt`` and
macros have prefix ``FMT_`` or ``fmt``.
.. _core-api:
Core API
========
``fmt/core.h`` defines the core API which provides argument handling facilities
and a lightweight subset of formatting functions.
The following functions use :ref:`format string syntax <syntax>`
imilar to that of Python's `str.format
<http://docs.python.org/3/library/stdtypes.html#str.format>`_.
They take *format_str* and *args* as arguments.
*format_str* is a format string that contains literal text and replacement
fields surrounded by braces ``{}``. The fields are replaced with formatted
arguments in the resulting string.
*args* is an argument list representing arbitrary arguments.
The `performance of the format API
<https://github.com/fmtlib/fmt/blob/master/README.rst#speed-tests>`_ is close
to that of glibc's ``printf`` and better than the performance of IOStreams.
For even better speed use the `write API`_.
*args* is an argument list representing objects to be formatted.
.. _format:
.. doxygenfunction:: format(CStringRef, ArgList)
.. doxygenfunction:: operator""_format(const char *, std::size_t)
.. doxygenfunction:: format(string_view, const Args&...)
.. doxygenfunction:: vformat(string_view, format_args)
.. _print:
.. doxygenfunction:: print(CStringRef, ArgList)
.. doxygenfunction:: print(string_view, const Args&...)
.. doxygenfunction:: vprint(string_view, format_args)
.. doxygenfunction:: print(std::FILE *, CStringRef, ArgList)
.. doxygenfunction:: print(std::FILE *, string_view, const Args&...)
.. doxygenfunction:: vprint(std::FILE *, string_view, format_args)
.. doxygenclass:: fmt::BasicFormatter
.. doxygenfunction:: print(std::FILE *, wstring_view, const Args&...)
.. doxygenfunction:: vprint(std::FILE *, wstring_view, wformat_args)
Named arguments
---------------
.. doxygenfunction:: fmt::arg(string_view, const T&)
Argument lists
--------------
.. doxygenfunction:: fmt::make_format_args(const Args&...)
.. doxygenclass:: fmt::format_arg_store
:members:
.. doxygenclass:: fmt::basic_format_args
:members:
.. doxygenstruct:: fmt::format_args
.. doxygenclass:: fmt::basic_format_arg
:members:
Compatibility
-------------
.. doxygenclass:: fmt::basic_string_view
:members:
.. doxygentypedef:: fmt::string_view
.. doxygentypedef:: fmt::wstring_view
.. _format-api:
Format API
==========
``fmt/format.h`` defines the full format API providing compile-time format
string checks, output iterator and user-defined type support.
Compile-time format string checks
---------------------------------
.. doxygendefine:: fmt
Formatting user-defined types
-----------------------------
To make a user-defined type formattable, specialize the ``formatter<T>`` struct
template and implement ``parse`` and ``format`` methods::
#include <fmt/format.h>
struct point { double x, y; };
namespace fmt {
template <>
struct formatter<point> {
template <typename ParseContext>
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const point &p, FormatContext &ctx) {
return format_to(ctx.begin(), "({:.1f}, {:.1f})", p.x, p.y);
}
};
}
Then you can pass objects of type ``point`` to any formatting function::
point p = {1, 2};
std::string s = fmt::format("{}", p);
// s == "(1.0, 2.0)"
In the example above the ``formatter<point>::parse`` function ignores the
contents of the format string referred to by ``ctx.begin()`` so the object will
always be formatted in the same way. See ``formatter<tm>::parse`` in
:file:`fmt/time.h` for an advanced example of how to parse the format string and
customize the formatted output.
This section shows how to define a custom format function for a user-defined
type. The next section describes how to get ``fmt`` to use a conventional stream
output ``operator<<`` when one is defined for a user-defined type.
Output iterator support
-----------------------
.. doxygenfunction:: fmt::format_to(OutputIt, string_view, const Args&...)
.. doxygenfunction:: fmt::format_to_n(OutputIt, size_t, string_view, const Args&...)
.. doxygenstruct:: fmt::format_to_n_result
:members:
Literal-based API
-----------------
The following user-defined literals are defined in ``fmt/format.h``.
.. doxygenfunction:: operator""_format(const char *, std::size_t)
.. doxygenfunction:: operator""_a(const char *, std::size_t)
Utilities
---------
.. doxygenfunction:: fmt::formatted_size(string_view, const Args&...)
.. doxygenfunction:: fmt::to_string(const T&)
.. doxygenfunction:: fmt::to_wstring(const T&)
.. doxygenclass:: fmt::basic_memory_buffer
:protected-members:
:members:
System errors
-------------
fmt does not use ``errno`` to communicate errors to the user, but it may call
system functions which set ``errno``. Users should not make any assumptions about
the value of ``errno`` being preserved by library functions.
.. doxygenclass:: fmt::system_error
:members:
.. doxygenfunction:: fmt::format_system_error
.. doxygenclass:: fmt::windows_error
:members:
.. _formatstrings:
Custom allocators
-----------------
The {fmt} library supports custom dynamic memory allocators.
A custom allocator class can be specified as a template argument to
:class:`fmt::basic_memory_buffer`::
using custom_memory_buffer =
fmt::basic_memory_buffer<char, fmt::inline_buffer_size, custom_allocator>;
It is also possible to write a formatting function that uses a custom
allocator::
using custom_string =
std::basic_string<char, std::char_traits<char>, custom_allocator>;
custom_string vformat(custom_allocator alloc, fmt::string_view format_str,
fmt::format_args args) {
custom_memory_buffer buf(alloc);
fmt::vformat_to(buf, format_str, args);
return custom_string(buf.data(), buf.size(), alloc);
}
template <typename ...Args>
inline custom_string format(custom_allocator alloc,
fmt::string_view format_str,
const Args & ... args) {
return vformat(alloc, format_str, fmt::make_format_args(args...));
}
The allocator will be used for the output container only. If you are using named
arguments, the container that stores pointers to them will be allocated using
the default allocator. Also floating-point formatting falls back on ``sprintf``
which may do allocations.
Custom formatting of built-in types
-----------------------------------
It is possible to change the way arguments are formatted by providing a
custom argument formatter class::
using arg_formatter =
fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>>;
// A custom argument formatter that formats negative integers as unsigned
// with the ``x`` format specifier.
class custom_arg_formatter : public arg_formatter {
public:
custom_arg_formatter(fmt::format_context &ctx, fmt::format_specs &spec)
: arg_formatter(ctx, spec) {}
using arg_formatter::operator();
void operator()(int value) {
if (spec().type() == 'x')
(*this)(static_cast<unsigned>(value)); // convert to unsigned and format
else
arg_formatter::operator()(value);
}
};
std::string custom_vformat(fmt::string_view format_str, fmt::format_args args) {
fmt::memory_buffer buffer;
// Pass custom argument formatter as a template arg to vformat_to.
fmt::vformat_to<custom_arg_formatter>(buffer, format_str, args);
return fmt::to_string(buffer);
}
template <typename ...Args>
inline std::string custom_format(
fmt::string_view format_str, const Args &... args) {
return custom_vformat(format_str, fmt::make_format_args(args...));
}
std::string s = custom_format("{:x}", -42); // s == "ffffffd6"
.. doxygenclass:: fmt::arg_formatter
:members:
.. _time-api:
Date and time formatting
------------------------
========================
The library supports `strftime
<http://en.cppreference.com/w/cpp/chrono/c/strftime>`_-like date and time
formatting::
#include "fmt/time.h"
#include <fmt/time.h>
std::time_t t = std::time(nullptr);
// Prints "The date is 2016-04-29." (with the current date)
@@ -58,134 +278,35 @@ formatting::
The format string syntax is described in the documentation of
`strftime <http://en.cppreference.com/w/cpp/chrono/c/strftime>`_.
Formatting user-defined types
-----------------------------
A custom ``format_arg`` function may be implemented and used to format any
user-defined type. That is how date and time formatting described in the
previous section is implemented in :file:`fmt/time.h`. The following example
shows how to implement custom formatting for a user-defined structure.
::
struct MyStruct { double a, b; };
void format_arg(fmt::BasicFormatter<char> &f,
const char *&format_str, const MyStruct &s) {
f.writer().write("[MyStruct: a={:.1f}, b={:.2f}]", s.a, s.b);
}
MyStruct m = { 1, 2 };
std::string s = fmt::format("m={}", n);
// s == "m=[MyStruct: a=1.0, b=2.00]"
Note in the example above the ``format_arg`` function ignores the contents of
``format_str`` so the type will always be formatted as specified. See
``format_arg`` in :file:`fmt/time.h` for an advanced example of how to use
the ``format_str`` argument to customize the formatted output.
This technique can also be used for formatting class hierarchies::
namespace local {
struct Parent {
Parent(int p) : p(p) {}
virtual void write(fmt::Writer &w) const {
w.write("Parent : p={}", p);
}
int p;
};
struct Child : Parent {
Child(int c, int p) : Parent(p), c(c) {}
virtual void write(fmt::Writer &w) const {
w.write("Child c={} : ", c);
Parent::write(w);
}
int c;
};
void format_arg(fmt::BasicFormatter<char> &f,
const char *&format_str, const Parent &p) {
p.write(f.writer());
}
}
Local::Child c(1,2);
Local::Parent &p = c;
fmt::print("via ref to base: {}\n", p);
fmt::print("direct to child: {}\n", c);
This section shows how to define a custom format function for a user-defined
type. The next section describes how to get ``fmt`` to use a conventional stream
output ``operator<<`` when one is defined for a user-defined type.
.. _ostream-api:
``std::ostream`` support
------------------------
========================
The header ``fmt/ostream.h`` provides ``std::ostream`` support including
formatting of user-defined types that have overloaded ``operator<<``::
``fmt/ostream.h`` provides ``std::ostream`` support including formatting of
user-defined types that have overloaded ``operator<<``::
#include "fmt/ostream.h"
#include <fmt/ostream.h>
class Date {
class date {
int year_, month_, day_;
public:
Date(int year, int month, int day): year_(year), month_(month), day_(day) {}
date(int year, int month, int day): year_(year), month_(month), day_(day) {}
friend std::ostream &operator<<(std::ostream &os, const Date &d) {
friend std::ostream &operator<<(std::ostream &os, const date &d) {
return os << d.year_ << '-' << d.month_ << '-' << d.day_;
}
};
std::string s = fmt::format("The date is {}", Date(2012, 12, 9));
std::string s = fmt::format("The date is {}", date(2012, 12, 9));
// s == "The date is 2012-12-9"
.. doxygenfunction:: print(std::ostream&, CStringRef, ArgList)
.. doxygenfunction:: print(std::ostream&, string_view, const Args&...)
Argument formatters
-------------------
.. _printf-api:
It is possible to change the way arguments are formatted by providing a
custom argument formatter class::
// A custom argument formatter that formats negative integers as unsigned
// with the ``x`` format specifier.
class CustomArgFormatter :
public fmt::BasicArgFormatter<CustomArgFormatter, char> {
public:
CustomArgFormatter(fmt::BasicFormatter<char, CustomArgFormatter> &f,
fmt::FormatSpec &s, const char *fmt)
: fmt::BasicArgFormatter<CustomArgFormatter, char>(f, s, fmt) {}
void visit_int(int value) {
if (spec().type() == 'x')
visit_uint(value); // convert to unsigned and format
else
fmt::BasicArgFormatter<CustomArgFormatter, char>::visit_int(value);
}
};
std::string custom_format(const char *format_str, fmt::ArgList args) {
fmt::MemoryWriter writer;
// Pass custom argument formatter as a template arg to BasicFormatter.
fmt::BasicFormatter<char, CustomArgFormatter> formatter(args, writer);
formatter.format(format_str);
return writer.str();
}
FMT_VARIADIC(std::string, custom_format, const char *)
std::string s = custom_format("{:x}", -42); // s == "ffffffd6"
.. doxygenclass:: fmt::ArgVisitor
:members:
.. doxygenclass:: fmt::BasicArgFormatter
:members:
.. doxygenclass:: fmt::ArgFormatter
:members:
Printf formatting
-----------------
``printf`` formatting
=====================
The header ``fmt/printf.h`` provides ``printf``-like formatting functionality.
The following functions use `printf format string syntax
@@ -194,118 +315,10 @@ the POSIX extension for positional arguments. Unlike their standard
counterparts, the ``fmt`` functions are type-safe and throw an exception if an
argument type doesn't match its format specification.
.. doxygenfunction:: printf(CStringRef, ArgList)
.. doxygenfunction:: printf(string_view, const Args&...)
.. doxygenfunction:: fprintf(std::FILE *, CStringRef, ArgList)
.. doxygenfunction:: fprintf(std::FILE *, string_view, const Args&...)
.. doxygenfunction:: fprintf(std::ostream&, CStringRef, ArgList)
.. doxygenfunction:: fprintf(std::ostream&, string_view, const Args&...)
.. doxygenfunction:: sprintf(CStringRef, ArgList)
.. doxygenclass:: fmt::PrintfFormatter
:members:
.. doxygenclass:: fmt::BasicPrintfArgFormatter
:members:
.. doxygenclass:: fmt::PrintfArgFormatter
:members:
Write API
=========
The write API provides classes for writing formatted data into character
streams. It is usually faster than the `format API`_ but, as IOStreams,
may result in larger compiled code size. The main writer class is
`~fmt::BasicMemoryWriter` which stores its output in a memory buffer and
provides direct access to it. It is possible to create custom writers that
store output elsewhere by subclassing `~fmt::BasicWriter`.
.. doxygenclass:: fmt::BasicWriter
:members:
.. doxygenclass:: fmt::BasicMemoryWriter
:members:
.. doxygenclass:: fmt::BasicArrayWriter
:members:
.. doxygenclass:: fmt::BasicStringWriter
:members:
.. doxygenclass:: fmt::BasicContainerWriter
:members:
.. doxygenfunction:: bin(int)
.. doxygenfunction:: oct(int)
.. doxygenfunction:: hex(int)
.. doxygenfunction:: hexu(int)
.. doxygenfunction:: pad(int, unsigned, Char)
Utilities
=========
.. doxygenfunction:: fmt::arg(StringRef, const T&)
.. doxygenfunction:: operator""_a(const char *, std::size_t)
.. doxygendefine:: FMT_CAPTURE
.. doxygendefine:: FMT_VARIADIC
.. doxygenclass:: fmt::ArgList
:members:
.. doxygenfunction:: fmt::to_string(const T&)
.. doxygenfunction:: fmt::to_wstring(const T&)
.. doxygenclass:: fmt::BasicStringRef
:members:
.. doxygenclass:: fmt::BasicCStringRef
:members:
.. doxygenclass:: fmt::Buffer
:protected-members:
:members:
System errors
=============
.. doxygenclass:: fmt::SystemError
:members:
.. doxygenfunction:: fmt::format_system_error
.. doxygenclass:: fmt::WindowsError
:members:
.. _formatstrings:
Custom allocators
=================
The fmt library supports custom dynamic memory allocators.
A custom allocator class can be specified as a template argument to
:class:`fmt::BasicMemoryWriter`::
typedef fmt::BasicMemoryWriter<char, CustomAllocator> CustomMemoryWriter;
It is also possible to write a formatting function that uses a custom
allocator::
typedef std::basic_string<char, std::char_traits<char>, CustomAllocator>
CustomString;
CustomString format(CustomAllocator alloc, fmt::CStringRef format_str,
fmt::ArgList args) {
CustomMemoryWriter writer(alloc);
writer.write(format_str, args);
return CustomString(writer.data(), writer.size(), alloc);
}
FMT_VARIADIC(CustomString, format, CustomAllocator, fmt::CStringRef)
.. doxygenfunction:: sprintf(string_view, const Args&...)

View File

@@ -6,7 +6,7 @@ import errno, os, shutil, sys, tempfile
from subprocess import check_call, check_output, CalledProcessError, Popen, PIPE
from distutils.version import LooseVersion
versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0']
versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0', '5.1.0']
def pip_install(package, commit=None, **kwargs):
"Install package using pip."
@@ -56,14 +56,14 @@ def create_build_env(dirname='virtualenv'):
pip_install('sphinx-doc/sphinx', '12b83372ac9316e8cbe86e7fed889296a4cc29ee',
min_version='1.4.1.dev20160531')
pip_install('michaeljones/breathe',
'6b1c5bb7a1866f15fc328b8716258354b10c1daa',
'129222318f7c8f865d2631e7da7b033567e7f56a',
min_version='4.2.0')
def build_docs(version='dev', **kwargs):
doc_dir = kwargs.get('doc_dir', os.path.dirname(os.path.realpath(__file__)))
work_dir = kwargs.get('work_dir', '.')
include_dir = kwargs.get('include_dir',
os.path.join(os.path.dirname(doc_dir), 'fmt'))
include_dir = kwargs.get(
'include_dir', os.path.join(os.path.dirname(doc_dir), 'include', 'fmt'))
# Build docs.
cmd = ['doxygen', '-']
p = Popen(cmd, stdin=PIPE)
@@ -74,8 +74,8 @@ def build_docs(version='dev', **kwargs):
GENERATE_MAN = NO
GENERATE_RTF = NO
CASE_SENSE_NAMES = NO
INPUT = {0}/container.h {0}/format.h {0}/ostream.h \
{0}/printf.h {0}/string.h
INPUT = {0}/core.h {0}/format.h {0}/ostream.h \
{0}/printf.h {0}/time.h
QUIET = YES
JAVADOC_AUTOBRIEF = YES
AUTOLINK_SUPPORT = NO
@@ -89,7 +89,9 @@ def build_docs(version='dev', **kwargs):
FMT_USE_VARIADIC_TEMPLATES=1 \
FMT_USE_RVALUE_REFERENCES=1 \
FMT_USE_USER_DEFINED_LITERALS=1 \
FMT_API=
FMT_API= \
"FMT_BEGIN_NAMESPACE=namespace fmt {{" \
"FMT_END_NAMESPACE=}}"
EXCLUDE_SYMBOLS = fmt::internal::* StringValue write_str
'''.format(include_dir, doxyxml_dir).encode('UTF-8'))
if p.returncode != 0:

View File

@@ -47,7 +47,7 @@ source_suffix = '.rst'
# General information about the project.
project = u'fmt'
copyright = u'2012-2015, Victor Zverovich'
copyright = u'2012-present, Victor Zverovich'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the

View File

@@ -2,8 +2,7 @@ Overview
========
**fmt** (formerly cppformat) is an open-source formatting library.
It can be used as a safe alternative to printf or as a fast
alternative to C++ IOStreams.
It can be used as a fast and safe alternative to printf and IOStreams.
.. raw:: html
@@ -16,7 +15,7 @@ alternative to C++ IOStreams.
</div>
</div>
.. _format-api:
.. _format-api-intro:
Format API
----------
@@ -25,21 +24,21 @@ The replacement-based Format API provides a safe alternative to ``printf``,
``sprintf`` and friends with comparable or `better performance
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
The `format string syntax <syntax.html>`_ is similar to the one used by
`str.format <http://docs.python.org/2/library/stdtypes.html#str.format>`_
`str.format <http://docs.python.org/3/library/stdtypes.html#str.format>`_
in Python:
.. code:: c++
fmt::format("The answer is {}", 42);
fmt::format("The answer is {}.", 42);
The ``fmt::format`` function returns a string "The answer is 42". You can use
``fmt::MemoryWriter`` to avoid constructing ``std::string``:
The ``fmt::format`` function returns a string "The answer is 42.". You can use
``fmt::memory_buffer`` to avoid constructing ``std::string``:
.. code:: c++
fmt::MemoryWriter w;
w.write("Look, a {} string", 'C');
w.c_str(); // returns a C string (const char*)
fmt::memory_buffer out;
format_to(out, "For a moment, {} happened.", "nothing");
out.data(); // returns a pointer to the formatted data
The ``fmt::print`` function performs formatting and writes the result to a file:
@@ -54,11 +53,6 @@ The file argument can be omitted in which case the function prints to
fmt::print("Don't {}\n", "panic");
If your compiler supports C++11, then the formatting functions are implemented
with variadic templates. Otherwise variadic functions are emulated by generating
a set of lightweight wrappers. This ensures compatibility with older compilers
while providing a natural API.
The Format API also supports positional arguments useful for localization:
.. code:: c++
@@ -93,39 +87,31 @@ literal operators, they must be made visible with the directive
``using namespace fmt::literals;``. Note that this brings in only ``_a`` and
``_format`` but nothing else from the ``fmt`` namespace.
.. _write-api:
Write API
---------
The concatenation-based Write API (experimental) provides a `fast
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_
stateless alternative to IOStreams:
.. code:: c++
fmt::MemoryWriter out;
out << "The answer in hexadecimal is " << hex(42);
.. _safety:
Safety
------
The library is fully type safe, automatic memory management prevents buffer
overflow, errors in format strings are reported using exceptions. For example,
the code
overflow, errors in format strings are reported using exceptions or at compile
tim. For example, the code
.. code:: c++
fmt::format("The answer is {:d}", "forty-two");
throws a ``FormatError`` exception with description
"unknown format code 'd' for string", because the argument
``"forty-two"`` is a string while the format code ``d``
only applies to integers.
throws a ``format_error`` exception with description "unknown format code 'd' for
string", because the argument ``"forty-two"`` is a string while the format code
``d`` only applies to integers, while
Where possible, errors are caught at compile time. For example, the code
.. code:: c++
format(fmt("The answer is {:d}"), "forty-two");
reports a compile-time error for the same reason on compilers that support
relaxed ``constexpr``.
The following code
.. code:: c++
@@ -143,44 +129,56 @@ its numeric value being written to the stream (i.e. 1070 instead of letter 'ю'
which is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is
needed.
Note that fmt does not use the value of the ``errno`` global to communicate
errors to the user, but it may call system functions which set ``errno``. Since
fmt does not attempt to preserve the value of ``errno``, users should not make
any assumptions about it and always set it to ``0`` before making any system
calls that convey error information via ``errno``.
Compact binary code
-------------------
The library is designed to produce compact per-call compiled code. For example
(`godbolt <https://godbolt.org/g/TZU4KF>`_),
.. code:: c++
#include <fmt/core.h>
int main() {
fmt::print("The answer is {}.", 42);
}
compiles to just
.. code:: asm
main: # @main
sub rsp, 24
mov qword ptr [rsp], 42
mov rcx, rsp
mov edi, offset .L.str
mov esi, 17
mov edx, 2
call fmt::v5::vprint(fmt::v5::basic_string_view<char>, fmt::v5::format_args)
xor eax, eax
add rsp, 24
ret
.L.str:
.asciz "The answer is {}."
.. _portability:
Portability
-----------
The library is highly portable. Here is an incomplete list of operating systems
and compilers where it has been tested and known to work:
The library is highly portable and relies only on a small set of C++11 features:
* 64-bit (amd64) GNU/Linux with GCC 4.4.3,
`4.6.3 <https://travis-ci.org/fmtlib/fmt>`_, 4.7.2, 4.8.1, and Intel C++
Compiler (ICC) 14.0.2
* variadic templates
* type traits
* rvalue references
* decltype
* trailing return types
* deleted functions
* 32-bit (i386) GNU/Linux with GCC 4.4.3, 4.6.3
* Mac OS X with GCC 4.2.1 and Clang 4.2, 5.1.0
* 64-bit Windows with Visual C++ 2010, 2013 and
`2015 <https://ci.appveyor.com/project/vitaut/fmt>`_
* 32-bit Windows with Visual C++ 2010
Although the library uses C++11 features when available, it also works with
older compilers and standard library implementations. The only thing to keep in
mind for C++98 portability:
* Variadic templates: minimum GCC 4.4, Clang 2.9 or VS2013. This feature allows
the Format API to accept an unlimited number of arguments. With older
compilers the maximum is 15.
* User-defined literals: minimum GCC 4.7, Clang 3.1 or VS2015. The suffixes
``_format`` and ``_a`` are functionally equivalent to the functions
``fmt::format`` and ``fmt::arg``.
These are available since GCC 4.4, Clang 2.9 and MSVC 18.0 (2013). For older
compilers use fmt `version 4.x
<https://github.com/fmtlib/fmt/releases/tag/4.1.0>`_ which continues to be
maintained and only requires C++98.
The output of all formatting functions is consistent across platforms. In
particular, formatting a floating-point infinity always gives ``inf`` while the
@@ -198,7 +196,7 @@ Ease of Use
-----------
fmt has a small self-contained code base with the core library consisting of
a single header file and a single source file and no external dependencies.
just three header files and no external dependencies.
A permissive BSD `license <https://github.com/fmtlib/fmt#license>`_ allows
using the library both in open-source and commercial projects.

View File

@@ -4,8 +4,9 @@
Format String Syntax
********************
Formatting functions such as :ref:`fmt::format() <format>` and :ref:`fmt::print() <print>`
use the same format string syntax described in this section.
Formatting functions such as :ref:`fmt::format() <format>` and
:ref:`fmt::print() <print>` use the same format string syntax described in this
section.
Format strings contain "replacement fields" surrounded by curly braces ``{}``.
Anything that is not contained in braces is considered literal text, which is
@@ -35,6 +36,8 @@ If the numerical arg_ids in a format string are 0, 1, 2, ... in sequence,
they can all be omitted (not just some) and the numbers 0, 1, 2, ... will be
automatically inserted in that order.
Named arguments can be referred to by their names or indices.
Some simple format string examples::
"First, thou shalt count to {0}" // References the first argument
@@ -51,8 +54,8 @@ described in the next section.
A *format_spec* field can also include nested replacement fields in certain
positions within it. These nested replacement fields can contain only an
argument id; format specifications are not allowed. This allows the
formatting of a value to be dynamically specified.
argument id; format specifications are not allowed. This allows the formatting
of a value to be dynamically specified.
See the :ref:`formatexamples` section for some examples.
@@ -360,7 +363,12 @@ Replacing ``%x`` and ``%o`` and converting the value to different bases::
// Result: "int: 42; hex: 2a; oct: 52; bin: 101010"
// with 0x or 0 or 0b as prefix:
format("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42);
// Result: "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"
// Result: "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"
Padded hex byte with prefix and always prints both hex characters::
format("{:#04x}", 0);
// Result: "0x00"
.. ifconfig:: False

View File

@@ -61,19 +61,22 @@ __ http://en.wikipedia.org/wiki/Library_%28computing%29#Shared_libraries
Header-only usage with CMake
============================
In order to add ``fmtlib`` into an existing ``CMakeLists.txt`` file, you can add the ``fmt`` library directory into your main project, which will enable the ``fmt`` library::
You can add the ``fmt`` library directory into your project and include it in
your ``CMakeLists.txt`` file::
add_subdirectory(fmt)
If you have a project called ``foo`` that you would like to link against the fmt library in a header-only fashion, you can enable with with::
target_link_libraries(foo PRIVATE fmt::fmt-header-only)
And then to ensure that the ``fmt`` library does not always get built, you can modify the call to ``add_subdirectory`` to read ::
or
::
add_subdirectory(fmt EXCLUDE_FROM_ALL)
This will ensure that the ``fmt`` library is exluded from calls to ``make``, ``make all``, or ``cmake --build .``.
to exclude it from ``make``, ``make all``, or ``cmake --build .``.
Settting up your target to use a header-only version of ``fmt`` is equaly easy::
target_link_libraries(<your-target> PRIVATE fmt-header-only)
Building the documentation
==========================

View File

@@ -1,94 +0,0 @@
# Define the fmt library, its includes and the needed defines.
# *.cc are added to FMT_HEADERS for the header-only configuration.
set(FMT_HEADERS container.h format.h format.cc ostream.h ostream.cc printf.h
printf.cc string.h time.h)
if (HAVE_OPEN)
set(FMT_HEADERS ${FMT_HEADERS} posix.h)
set(FMT_SOURCES ${FMT_SOURCES} posix.cc)
endif ()
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} ../README.rst ../ChangeLog.rst)
add_library(fmt::fmt ALIAS fmt)
# Starting with cmake 3.1 the CXX_STANDARD property can be used instead.
# Note: Don't make -std=c++11 public or interface, since it breaks projects
# that use C++14.
target_compile_options(fmt PRIVATE ${CPP11_FLAG})
if (FMT_PEDANTIC)
target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
target_include_directories(fmt PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>)
set_target_properties(fmt PROPERTIES
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR})
if (BUILD_SHARED_LIBS)
if (UNIX AND NOT APPLE)
# Fix rpmlint warning:
# unused-direct-shlib-dependency /usr/lib/libformat.so.1.1.0 /lib/libm.so.6.
target_link_libraries(fmt -Wl,--as-needed)
endif ()
target_compile_definitions(fmt PRIVATE FMT_EXPORT INTERFACE FMT_SHARED)
endif ()
#------------------------------------------------------------------------------
# additionally define a header only library when cmake is new enough
if (CMAKE_VERSION VERSION_GREATER 3.1.0 OR CMAKE_VERSION VERSION_EQUAL 3.1.0)
add_library(fmt-header-only INTERFACE)
add_library(fmt::fmt-header-only ALIAS fmt-header-only)
target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)
target_include_directories(fmt-header-only INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>)
endif ()
# Install targets.
if (FMT_INSTALL)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
set(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING
"Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.")
set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake)
set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake)
set(targets_export_name fmt-targets)
set (INSTALL_TARGETS fmt)
if (TARGET fmt-header-only)
set(INSTALL_TARGETS ${INSTALL_TARGETS} fmt-header-only)
endif ()
set(FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING
"Installation directory for libraries, relative to ${CMAKE_INSTALL_PREFIX}.")
set(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR}/fmt CACHE STRING
"Installation directory for include files, relative to ${CMAKE_INSTALL_PREFIX}.")
# Generate the version, config and target files into the build directory.
write_basic_package_version_file(
${version_config}
VERSION ${FMT_VERSION}
COMPATIBILITY AnyNewerVersion)
configure_package_config_file(
${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in
${project_config}
INSTALL_DESTINATION ${FMT_CMAKE_DIR})
export(TARGETS ${INSTALL_TARGETS} NAMESPACE fmt::
FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake)
# Install version, config and target files.
install(
FILES ${project_config} ${version_config}
DESTINATION ${FMT_CMAKE_DIR})
install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR}
NAMESPACE fmt::)
# Install the library and headers.
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
DESTINATION ${FMT_LIB_DIR})
install(FILES ${FMT_HEADERS} DESTINATION ${FMT_INC_DIR})
endif ()

View File

@@ -1,82 +0,0 @@
/*
Formatting library for C++ - standard container utilities
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#ifndef FMT_CONTAINER_H_
#define FMT_CONTAINER_H_
#include "format.h"
namespace fmt {
namespace internal {
/**
\rst
A "buffer" that appends data to a standard container (e.g. typically a
``std::vector`` or ``std::basic_string``).
\endrst
*/
template <typename Container>
class ContainerBuffer : public Buffer<typename Container::value_type> {
private:
Container& container_;
protected:
virtual void grow(std::size_t size) FMT_OVERRIDE {
container_.resize(size);
this->ptr_ = &container_[0];
this->capacity_ = size;
}
public:
explicit ContainerBuffer(Container& container) : container_(container) {
this->size_ = container_.size();
if (this->size_ > 0) {
this->ptr_ = &container_[0];
this->capacity_ = this->size_;
}
}
};
} // namespace internal
/**
\rst
This class template provides operations for formatting and appending data
to a standard *container* like ``std::vector`` or ``std::basic_string``.
**Example**::
void vecformat(std::vector<char>& dest, fmt::BasicCStringRef<char> format,
fmt::ArgList args) {
fmt::BasicContainerWriter<std::vector<char> > appender(dest);
appender.write(format, args);
}
FMT_VARIADIC(void, vecformat, std::vector<char>&,
fmt::BasicCStringRef<char>);
\endrst
*/
template <class Container>
class BasicContainerWriter
: public BasicWriter<typename Container::value_type> {
private:
internal::ContainerBuffer<Container> buffer_;
public:
/**
\rst
Constructs a :class:`fmt::BasicContainerWriter` object.
\endrst
*/
explicit BasicContainerWriter(Container& dest)
: BasicWriter<typename Container::value_type>(buffer_), buffer_(dest) {}
};
} // namespace fmt
#endif // FMT_CONTAINER_H_

View File

@@ -1,495 +0,0 @@
/*
Formatting library for C++
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "format.h"
#include <string.h>
#include <cctype>
#include <cerrno>
#include <climits>
#include <cmath>
#include <cstdarg>
#include <cstddef> // for std::ptrdiff_t
#if defined(_WIN32) && defined(__MINGW32__)
# include <cstring>
#endif
#if FMT_USE_WINDOWS_H
# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)
# define WIN32_LEAN_AND_MEAN
# endif
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
# include <windows.h>
# else
# define NOMINMAX
# include <windows.h>
# undef NOMINMAX
# endif
#endif
#if FMT_EXCEPTIONS
# define FMT_TRY try
# define FMT_CATCH(x) catch (x)
#else
# define FMT_TRY if (true)
# define FMT_CATCH(x) if (false)
#endif
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant
# pragma warning(disable: 4702) // unreachable code
// Disable deprecation warning for strerror. The latter is not called but
// MSVC fails to detect it.
# pragma warning(disable: 4996)
#endif
// Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available.
FMT_MAYBE_UNUSED
static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
return fmt::internal::Null<>();
}
FMT_MAYBE_UNUSED
static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
return fmt::internal::Null<>();
}
namespace fmt {
FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {}
FMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT {}
FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT {}
namespace {
#ifndef _MSC_VER
# define FMT_SNPRINTF snprintf
#else // _MSC_VER
inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
va_list args;
va_start(args, format);
int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
va_end(args);
return result;
}
# define FMT_SNPRINTF fmt_snprintf
#endif // _MSC_VER
#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
# define FMT_SWPRINTF snwprintf
#else
# define FMT_SWPRINTF swprintf
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
const char RESET_COLOR[] = "\x1b[0m";
typedef void (*FormatFunc)(Writer &, int, StringRef);
// Portable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code.
// This can be either a pointer to a string stored in buffer,
// or a pointer to some static immutable string.
// Returns one of the following values:
// 0 - success
// ERANGE - buffer is not large enough to store the error message
// other - failure
// Buffer should be at least of size 1.
int safe_strerror(
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer");
class StrError {
private:
int error_code_;
char *&buffer_;
std::size_t buffer_size_;
// A noop assignment operator to avoid bogus warnings.
void operator=(const StrError &) {}
// Handle the result of XSI-compliant version of strerror_r.
int handle(int result) {
// glibc versions before 2.13 return result in errno.
return result == -1 ? errno : result;
}
// Handle the result of GNU-specific version of strerror_r.
int handle(char *message) {
// If the buffer is full then the message is probably truncated.
if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
return ERANGE;
buffer_ = message;
return 0;
}
// Handle the case when strerror_r is not available.
int handle(internal::Null<>) {
return fallback(strerror_s(buffer_, buffer_size_, error_code_));
}
// Fallback to strerror_s when strerror_r is not available.
int fallback(int result) {
// If the buffer is full then the message is probably truncated.
return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
ERANGE : result;
}
#ifdef __c2__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
// Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(internal::Null<>) {
errno = 0;
buffer_ = strerror(error_code_);
return errno;
}
#ifdef __c2__
# pragma clang diagnostic pop
#endif
public:
StrError(int err_code, char *&buf, std::size_t buf_size)
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
int run() {
return handle(strerror_r(error_code_, buffer_, buffer_size_));
}
};
return StrError(error_code, buffer, buffer_size).run();
}
void format_error_code(Writer &out, int error_code,
StringRef message) FMT_NOEXCEPT {
// Report error code making sure that the output fits into
// INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
// bad_alloc.
out.clear();
static const char SEP[] = ": ";
static const char ERROR_STR[] = "error ";
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
typedef internal::IntTraits<int>::MainType MainType;
MainType abs_value = static_cast<MainType>(error_code);
if (internal::is_negative(error_code)) {
abs_value = 0 - abs_value;
++error_code_size;
}
error_code_size += internal::count_digits(abs_value);
if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size)
out << message << SEP;
out << ERROR_STR << error_code;
assert(out.size() <= internal::INLINE_BUFFER_SIZE);
}
void report_error(FormatFunc func, int error_code,
StringRef message) FMT_NOEXCEPT {
MemoryWriter full_message;
func(full_message, error_code, message);
// Use Writer::data instead of Writer::c_str to avoid potential memory
// allocation.
std::fwrite(full_message.data(), full_message.size(), 1, stderr);
std::fputc('\n', stderr);
}
} // namespace
FMT_FUNC void SystemError::init(
int err_code, CStringRef format_str, ArgList args) {
error_code_ = err_code;
MemoryWriter w;
format_system_error(w, err_code, format(format_str, args));
std::runtime_error &base = *this;
base = std::runtime_error(w.str());
}
template <typename T>
int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, T value) {
if (width == 0) {
return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, value) :
FMT_SNPRINTF(buffer, size, format, precision, value);
}
return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, width, value) :
FMT_SNPRINTF(buffer, size, format, width, precision, value);
}
template <typename T>
int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, T value) {
if (width == 0) {
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, value) :
FMT_SWPRINTF(buffer, size, format, precision, value);
}
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, width, value) :
FMT_SWPRINTF(buffer, size, format, width, precision, value);
}
template <typename T>
const char internal::BasicData<T>::DIGITS[] =
"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";
#define FMT_POWERS_OF_10(factor) \
factor * 10, \
factor * 100, \
factor * 1000, \
factor * 10000, \
factor * 100000, \
factor * 1000000, \
factor * 10000000, \
factor * 100000000, \
factor * 1000000000
template <typename T>
const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {
0, FMT_POWERS_OF_10(1)
};
template <typename T>
const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
0,
FMT_POWERS_OF_10(1),
FMT_POWERS_OF_10(ULongLong(1000000000)),
// Multiply several constants instead of using a single long long constant
// to avoid warnings about C++98 not supporting long long.
ULongLong(1000000000) * ULongLong(1000000000) * 10
};
FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
(void)type;
if (std::isprint(static_cast<unsigned char>(code))) {
FMT_THROW(FormatError(
format("unknown format code '{}' for {}", code, type)));
}
FMT_THROW(FormatError(
format("unknown format code '\\x{:02x}' for {}",
static_cast<unsigned>(code), type)));
}
#if FMT_USE_WINDOWS_H
FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) {
static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
if (s.size() > INT_MAX)
FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
int s_size = static_cast<int>(s.size());
int length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
if (length == 0)
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
buffer_.resize(length + 1);
length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
if (length == 0)
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
buffer_[length] = 0;
}
FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) {
if (int error_code = convert(s)) {
FMT_THROW(WindowsError(error_code,
"cannot convert string from UTF-16 to UTF-8"));
}
}
FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) {
if (s.size() > INT_MAX)
return ERROR_INVALID_PARAMETER;
int s_size = static_cast<int>(s.size());
int length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
if (length == 0)
return GetLastError();
buffer_.resize(length + 1);
length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
if (length == 0)
return GetLastError();
buffer_[length] = 0;
return 0;
}
FMT_FUNC void WindowsError::init(
int err_code, CStringRef format_str, ArgList args) {
error_code_ = err_code;
MemoryWriter w;
internal::format_windows_error(w, err_code, format(format_str, args));
std::runtime_error &base = *this;
base = std::runtime_error(w.str());
}
FMT_FUNC void internal::format_windows_error(
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
FMT_TRY {
MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
buffer.resize(INLINE_BUFFER_SIZE);
for (;;) {
wchar_t *system_message = &buffer[0];
int result = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
system_message, static_cast<uint32_t>(buffer.size()), FMT_NULL);
if (result != 0) {
UTF16ToUTF8 utf8_message;
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
out << message << ": " << utf8_message;
return;
}
break;
}
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
break; // Can't get error message, report error code instead.
buffer.resize(buffer.size() * 2);
}
} FMT_CATCH(...) {}
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
}
#endif // FMT_USE_WINDOWS_H
FMT_FUNC void format_system_error(
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
FMT_TRY {
internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;
buffer.resize(internal::INLINE_BUFFER_SIZE);
for (;;) {
char *system_message = &buffer[0];
int result = safe_strerror(error_code, system_message, buffer.size());
if (result == 0) {
out << message << ": " << system_message;
return;
}
if (result != ERANGE)
break; // Can't get error message, report error code instead.
buffer.resize(buffer.size() * 2);
}
} FMT_CATCH(...) {}
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
}
template <typename Char>
void internal::FixedBuffer<Char>::grow(std::size_t) {
FMT_THROW(std::runtime_error("buffer overflow"));
}
FMT_FUNC internal::Arg internal::FormatterBase::do_get_arg(
unsigned arg_index, const char *&error) {
internal::Arg arg = args_[arg_index];
switch (arg.type) {
case internal::Arg::NONE:
error = "argument index out of range";
break;
case internal::Arg::NAMED_ARG:
arg = *static_cast<const internal::Arg*>(arg.pointer);
break;
default:
/*nothing*/;
}
return arg;
}
FMT_FUNC void report_system_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
// 'fmt::' is for bcc32.
report_error(format_system_error, error_code, message);
}
#if FMT_USE_WINDOWS_H
FMT_FUNC void report_windows_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
// 'fmt::' is for bcc32.
report_error(internal::format_windows_error, error_code, message);
}
#endif
FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) {
MemoryWriter w;
w.write(format_str, args);
std::fwrite(w.data(), 1, w.size(), f);
}
FMT_FUNC void print(CStringRef format_str, ArgList args) {
print(stdout, format_str, args);
}
FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) {
char escape[] = "\x1b[30m";
escape[3] = static_cast<char>('0' + c);
std::fputs(escape, stdout);
print(format, args);
std::fputs(RESET_COLOR, stdout);
}
#ifndef FMT_HEADER_ONLY
template struct internal::BasicData<void>;
// Explicit instantiations for char.
template void internal::FixedBuffer<char>::grow(std::size_t);
template FMT_API int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, double value);
template FMT_API int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, long double value);
// Explicit instantiations for wchar_t.
template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
template FMT_API int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, double value);
template FMT_API int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, long double value);
#endif // FMT_HEADER_ONLY
} // namespace fmt
#ifdef _MSC_VER
# pragma warning(pop)
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,35 +0,0 @@
/*
Formatting library for C++ - std::ostream support
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#include "ostream.h"
namespace fmt {
namespace internal {
FMT_FUNC void write(std::ostream &os, Writer &w) {
const char *data = w.data();
typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
UnsignedStreamSize size = w.size();
UnsignedStreamSize max_size =
internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
do {
UnsignedStreamSize n = size <= max_size ? size : max_size;
os.write(data, static_cast<std::streamsize>(n));
data += n;
size -= n;
} while (size != 0);
}
}
FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) {
MemoryWriter w;
w.write(format_str, args);
internal::write(os, w);
}
} // namespace fmt

View File

@@ -1,108 +0,0 @@
/*
Formatting library for C++ - std::ostream support
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_
#include "format.h"
#include <ostream>
namespace fmt {
namespace internal {
template <class Char>
class FormatBuf : public std::basic_streambuf<Char> {
private:
typedef typename std::basic_streambuf<Char>::int_type int_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
Buffer<Char> &buffer_;
public:
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer) {}
protected:
// The put-area is actually always empty. This makes the implementation
// simpler and has the advantage that the streambuf and the buffer are always
// in sync and sputc never writes into uninitialized memory. The obvious
// disadvantage is that each call to sputc always results in a (virtual) call
// to overflow. There is no disadvantage here for sputn since this always
// results in a call to xsputn.
int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
if (!traits_type::eq_int_type(ch, traits_type::eof()))
buffer_.push_back(static_cast<Char>(ch));
return ch;
}
std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE {
buffer_.append(s, s + count);
return count;
}
};
Yes &convert(std::ostream &);
struct DummyStream : std::ostream {
DummyStream(); // Suppress a bogus warning in MSVC.
// Hide all operator<< overloads from std::ostream.
template <typename T>
typename EnableIf<sizeof(T) == 0>::type operator<<(const T &);
};
No &operator<<(std::ostream &, int);
template <typename T>
struct ConvertToIntImpl<T, true> {
// Convert to int only if T doesn't have an overloaded operator<<.
enum {
value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
};
};
// Write the content of w to os.
FMT_API void write(std::ostream &os, Writer &w);
} // namespace internal
// Formats a value.
template <typename Char, typename ArgFormatter_, typename T>
void format_arg(BasicFormatter<Char, ArgFormatter_> &f,
const Char *&format_str, const T &value) {
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;
internal::FormatBuf<Char> format_buf(buffer);
std::basic_ostream<Char> output(&format_buf);
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
output << value;
BasicStringRef<Char> str(&buffer[0], buffer.size());
typedef internal::MakeArg< BasicFormatter<Char> > MakeArg;
format_str = f.format(format_str, MakeArg(str));
}
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
print(cerr, "Don't {}!", "panic");
\endrst
*/
FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
} // namespace fmt
#ifdef FMT_HEADER_ONLY
# include "ostream.cc"
#endif
#endif // FMT_OSTREAM_H_

View File

@@ -1,32 +0,0 @@
/*
Formatting library for C++
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#include "format.h"
#include "printf.h"
namespace fmt {
template <typename Char>
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args);
FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args) {
MemoryWriter w;
printf(w, format, args);
std::size_t size = w.size();
return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
}
#ifndef FMT_HEADER_ONLY
template void PrintfFormatter<char>::format(CStringRef format);
template void PrintfFormatter<wchar_t>::format(WCStringRef format);
#endif // FMT_HEADER_ONLY
} // namespace fmt

View File

@@ -1,603 +0,0 @@
/*
Formatting library for C++
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#ifndef FMT_PRINTF_H_
#define FMT_PRINTF_H_
#include <algorithm> // std::fill_n
#include <limits> // std::numeric_limits
#include "ostream.h"
namespace fmt {
namespace internal {
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
template <bool IsSigned>
struct IntChecker {
template <typename T>
static bool fits_in_int(T value) {
unsigned max = std::numeric_limits<int>::max();
return value <= max;
}
static bool fits_in_int(bool) { return true; }
};
template <>
struct IntChecker<true> {
template <typename T>
static bool fits_in_int(T value) {
return value >= std::numeric_limits<int>::min() &&
value <= std::numeric_limits<int>::max();
}
static bool fits_in_int(int) { return true; }
};
class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> {
public:
void report_unhandled_arg() {
FMT_THROW(FormatError("precision is not integer"));
}
template <typename T>
int visit_any_int(T value) {
if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
FMT_THROW(FormatError("number is too big"));
return static_cast<int>(value);
}
};
// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
class IsZeroInt : public ArgVisitor<IsZeroInt, bool> {
public:
template <typename T>
bool visit_any_int(T value) { return value == 0; }
};
// returns the default type for format specific "%s"
class DefaultType : public ArgVisitor<DefaultType, char> {
public:
char visit_char(int) { return 'c'; }
char visit_bool(bool) { return 's'; }
char visit_pointer(const void *) { return 'p'; }
template <typename T>
char visit_any_int(T) { return 'd'; }
template <typename T>
char visit_any_double(T) { return 'g'; }
char visit_unhandled_arg() { return 's'; }
};
template <typename T, typename U>
struct is_same {
enum { value = 0 };
};
template <typename T>
struct is_same<T, T> {
enum { value = 1 };
};
// An argument visitor that converts an integer argument to T for printf,
// if T is an integral type. If T is void, the argument is converted to
// corresponding signed or unsigned type depending on the type specifier:
// 'd' and 'i' - signed, other - unsigned)
template <typename T = void>
class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
private:
internal::Arg &arg_;
wchar_t type_;
FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
public:
ArgConverter(internal::Arg &arg, wchar_t type)
: arg_(arg), type_(type) {}
void visit_bool(bool value) {
if (type_ != 's')
visit_any_int(value);
}
void visit_char(int value) {
if (type_ != 's')
visit_any_int(value);
}
template <typename U>
void visit_any_int(U value) {
bool is_signed = type_ == 'd' || type_ == 'i';
if (type_ == 's') {
is_signed = std::numeric_limits<U>::is_signed;
}
using internal::Arg;
typedef typename internal::Conditional<
is_same<T, void>::value, U, T>::type TargetType;
if (const_check(sizeof(TargetType) <= sizeof(int))) {
// Extra casts are used to silence warnings.
if (is_signed) {
arg_.type = Arg::INT;
arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
} else {
arg_.type = Arg::UINT;
typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned;
arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
}
} else {
if (is_signed) {
arg_.type = Arg::LONG_LONG;
// glibc's printf doesn't sign extend arguments of smaller types:
// std::printf("%lld", -42); // prints "4294967254"
// but we don't have to do the same because it's a UB.
arg_.long_long_value = static_cast<LongLong>(value);
} else {
arg_.type = Arg::ULONG_LONG;
arg_.ulong_long_value =
static_cast<typename internal::MakeUnsigned<U>::Type>(value);
}
}
}
};
// Converts an integer argument to char for printf.
class CharConverter : public ArgVisitor<CharConverter, void> {
private:
internal::Arg &arg_;
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
public:
explicit CharConverter(internal::Arg &arg) : arg_(arg) {}
template <typename T>
void visit_any_int(T value) {
arg_.type = internal::Arg::CHAR;
arg_.int_value = static_cast<char>(value);
}
};
// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
class WidthHandler : public ArgVisitor<WidthHandler, unsigned> {
private:
FormatSpec &spec_;
FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
public:
explicit WidthHandler(FormatSpec &spec) : spec_(spec) {}
void report_unhandled_arg() {
FMT_THROW(FormatError("width is not integer"));
}
template <typename T>
unsigned visit_any_int(T value) {
typedef typename internal::IntTraits<T>::MainType UnsignedType;
UnsignedType width = static_cast<UnsignedType>(value);
if (internal::is_negative(value)) {
spec_.align_ = ALIGN_LEFT;
width = 0 - width;
}
unsigned int_max = std::numeric_limits<int>::max();
if (width > int_max)
FMT_THROW(FormatError("number is too big"));
return static_cast<unsigned>(width);
}
};
} // namespace internal
/**
\rst
A ``printf`` argument formatter based on the `curiously recurring template
pattern <http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_.
To use `~fmt::BasicPrintfArgFormatter` define a subclass that implements some
or all of the visit methods with the same signatures as the methods in
`~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`.
Pass the subclass as the *Impl* template parameter. When a formatting
function processes an argument, it will dispatch to a visit method
specific to the argument type. For example, if the argument type is
``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass
will be called. If the subclass doesn't contain a method with this signature,
then a corresponding method of `~fmt::BasicPrintfArgFormatter` or its
superclass will be called.
\endrst
*/
template <typename Impl, typename Char, typename Spec>
class BasicPrintfArgFormatter :
public internal::ArgFormatterBase<Impl, Char, Spec> {
private:
void write_null_pointer() {
this->spec().type_ = 0;
this->write("(nil)");
}
typedef internal::ArgFormatterBase<Impl, Char, Spec> Base;
public:
/**
\rst
Constructs an argument formatter object.
*writer* is a reference to the output writer and *spec* contains format
specifier information for standard argument types.
\endrst
*/
BasicPrintfArgFormatter(BasicWriter<Char> &w, Spec &s)
: internal::ArgFormatterBase<Impl, Char, Spec>(w, s) {}
/** Formats an argument of type ``bool``. */
void visit_bool(bool value) {
Spec &fmt_spec = this->spec();
if (fmt_spec.type_ != 's')
return this->visit_any_int(value);
fmt_spec.type_ = 0;
this->write(value);
}
/** Formats a character. */
void visit_char(int value) {
const Spec &fmt_spec = this->spec();
BasicWriter<Char> &w = this->writer();
if (fmt_spec.type_ && fmt_spec.type_ != 'c')
w.write_int(value, fmt_spec);
typedef typename BasicWriter<Char>::CharPtr CharPtr;
CharPtr out = CharPtr();
if (fmt_spec.width_ > 1) {
Char fill = ' ';
out = w.grow_buffer(fmt_spec.width_);
if (fmt_spec.align_ != ALIGN_LEFT) {
std::fill_n(out, fmt_spec.width_ - 1, fill);
out += fmt_spec.width_ - 1;
} else {
std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
}
} else {
out = w.grow_buffer(1);
}
*out = static_cast<Char>(value);
}
/** Formats a null-terminated C string. */
void visit_cstring(const char *value) {
if (value)
Base::visit_cstring(value);
else if (this->spec().type_ == 'p')
write_null_pointer();
else
this->write("(null)");
}
/** Formats a pointer. */
void visit_pointer(const void *value) {
if (value)
return Base::visit_pointer(value);
this->spec().type_ = 0;
write_null_pointer();
}
/** Formats an argument of a custom (user-defined) type. */
void visit_custom(internal::Arg::CustomValue c) {
BasicFormatter<Char> formatter(ArgList(), this->writer());
const Char format_str[] = {'}', 0};
const Char *format = format_str;
c.format(&formatter, c.value, &format);
}
};
/** The default printf argument formatter. */
template <typename Char>
class PrintfArgFormatter :
public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec> {
public:
/** Constructs an argument formatter object. */
PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
: BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec>(w, s) {}
};
/** This template formats data and writes the output to a writer. */
template <typename Char, typename ArgFormatter = PrintfArgFormatter<Char> >
class PrintfFormatter : private internal::FormatterBase {
private:
BasicWriter<Char> &writer_;
void parse_flags(FormatSpec &spec, const Char *&s);
// Returns the argument with specified index or, if arg_index is equal
// to the maximum unsigned value, the next argument.
internal::Arg get_arg(
const Char *s,
unsigned arg_index = (std::numeric_limits<unsigned>::max)());
// Parses argument index, flags and width and returns the argument index.
unsigned parse_header(const Char *&s, FormatSpec &spec);
public:
/**
\rst
Constructs a ``PrintfFormatter`` object. References to the arguments and
the writer are stored in the formatter object so make sure they have
appropriate lifetimes.
\endrst
*/
explicit PrintfFormatter(const ArgList &al, BasicWriter<Char> &w)
: FormatterBase(al), writer_(w) {}
/** Formats stored arguments and writes the output to the writer. */
void format(BasicCStringRef<Char> format_str);
};
template <typename Char, typename AF>
void PrintfFormatter<Char, AF>::parse_flags(FormatSpec &spec, const Char *&s) {
for (;;) {
switch (*s++) {
case '-':
spec.align_ = ALIGN_LEFT;
break;
case '+':
spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
break;
case '0':
spec.fill_ = '0';
break;
case ' ':
spec.flags_ |= SIGN_FLAG;
break;
case '#':
spec.flags_ |= HASH_FLAG;
break;
default:
--s;
return;
}
}
}
template <typename Char, typename AF>
internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s,
unsigned arg_index) {
(void)s;
const char *error = FMT_NULL;
internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ?
next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
if (error)
FMT_THROW(FormatError(!*s ? "invalid format string" : error));
return arg;
}
template <typename Char, typename AF>
unsigned PrintfFormatter<Char, AF>::parse_header(
const Char *&s, FormatSpec &spec) {
unsigned arg_index = std::numeric_limits<unsigned>::max();
Char c = *s;
if (c >= '0' && c <= '9') {
// Parse an argument index (if followed by '$') or a width possibly
// preceded with '0' flag(s).
unsigned value = internal::parse_nonnegative_int(s);
if (*s == '$') { // value is an argument index
++s;
arg_index = value;
} else {
if (c == '0')
spec.fill_ = '0';
if (value != 0) {
// Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now.
spec.width_ = value;
return arg_index;
}
}
}
parse_flags(spec, s);
// Parse width.
if (*s >= '0' && *s <= '9') {
spec.width_ = internal::parse_nonnegative_int(s);
} else if (*s == '*') {
++s;
spec.width_ = internal::WidthHandler(spec).visit(get_arg(s));
}
return arg_index;
}
template <typename Char, typename AF>
void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) {
const Char *start = format_str.c_str();
const Char *s = start;
while (*s) {
Char c = *s++;
if (c != '%') continue;
if (*s == c) {
write(writer_, start, s);
start = ++s;
continue;
}
write(writer_, start, s - 1);
FormatSpec spec;
spec.align_ = ALIGN_RIGHT;
// Parse argument index, flags and width.
unsigned arg_index = parse_header(s, spec);
// Parse precision.
if (*s == '.') {
++s;
if ('0' <= *s && *s <= '9') {
spec.precision_ = static_cast<int>(internal::parse_nonnegative_int(s));
} else if (*s == '*') {
++s;
spec.precision_ = internal::PrecisionHandler().visit(get_arg(s));
} else {
spec.precision_ = 0;
}
}
using internal::Arg;
Arg arg = get_arg(s, arg_index);
if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg))
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
if (spec.fill_ == '0') {
if (arg.type <= Arg::LAST_NUMERIC_TYPE)
spec.align_ = ALIGN_NUMERIC;
else
spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
}
// Parse length and convert the argument to the required type.
using internal::ArgConverter;
switch (*s++) {
case 'h':
if (*s == 'h')
ArgConverter<signed char>(arg, *++s).visit(arg);
else
ArgConverter<short>(arg, *s).visit(arg);
break;
case 'l':
if (*s == 'l')
ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
else
ArgConverter<long>(arg, *s).visit(arg);
break;
case 'j':
ArgConverter<intmax_t>(arg, *s).visit(arg);
break;
case 'z':
ArgConverter<std::size_t>(arg, *s).visit(arg);
break;
case 't':
ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
break;
case 'L':
// printf produces garbage when 'L' is omitted for long double, no
// need to do the same.
break;
default:
--s;
ArgConverter<void>(arg, *s).visit(arg);
}
// Parse type.
if (!*s)
FMT_THROW(FormatError("invalid format string"));
spec.type_ = static_cast<char>(*s++);
if (spec.type_ == 's') {
// set the format type to the default if 's' is specified
spec.type_ = internal::DefaultType().visit(arg);
}
if (arg.type <= Arg::LAST_INTEGER_TYPE) {
// Normalize type.
switch (spec.type_) {
case 'i': case 'u':
spec.type_ = 'd';
break;
case 'c':
// TODO: handle wchar_t
internal::CharConverter(arg).visit(arg);
break;
}
}
start = s;
// Format argument.
AF(writer_, spec).visit(arg);
}
write(writer_, start, s);
}
inline void printf(Writer &w, CStringRef format, ArgList args) {
PrintfFormatter<char>(args, w).format(format);
}
FMT_VARIADIC(void, printf, Writer &, CStringRef)
inline void printf(WWriter &w, WCStringRef format, ArgList args) {
PrintfFormatter<wchar_t>(args, w).format(format);
}
FMT_VARIADIC(void, printf, WWriter &, WCStringRef)
/**
\rst
Formats arguments and returns the result as a string.
**Example**::
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
*/
inline std::string sprintf(CStringRef format, ArgList args) {
MemoryWriter w;
printf(w, format, args);
return w.str();
}
FMT_VARIADIC(std::string, sprintf, CStringRef)
inline std::wstring sprintf(WCStringRef format, ArgList args) {
WMemoryWriter w;
printf(w, format, args);
return w.str();
}
FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef)
/**
\rst
Prints formatted data to the file *f*.
**Example**::
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args);
FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
/**
\rst
Prints formatted data to ``stdout``.
**Example**::
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
inline int printf(CStringRef format, ArgList args) {
return fprintf(stdout, format, args);
}
FMT_VARIADIC(int, printf, CStringRef)
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) {
MemoryWriter w;
printf(w, format_str, args);
internal::write(os, w);
return static_cast<int>(w.size());
}
FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
} // namespace fmt
#ifdef FMT_HEADER_ONLY
# include "printf.cc"
#endif
#endif // FMT_PRINTF_H_

View File

@@ -1,148 +0,0 @@
/*
Formatting library for C++ - string utilities
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#ifdef FMT_INCLUDE
# error "Add the fmt's parent directory and not fmt itself to includes."
#endif
#ifndef FMT_STRING_H_
#define FMT_STRING_H_
#include "format.h"
namespace fmt {
namespace internal {
// A buffer that stores data in ``std::basic_string``.
template <typename Char, typename Allocator = std::allocator<Char> >
class StringBuffer : public Buffer<Char> {
public:
typedef std::basic_string<Char, std::char_traits<Char>, Allocator> StringType;
private:
StringType data_;
protected:
virtual void grow(std::size_t size) FMT_OVERRIDE {
data_.resize(size);
this->ptr_ = &data_[0];
this->capacity_ = size;
}
public:
explicit StringBuffer(const Allocator &allocator = Allocator())
: data_(allocator) {}
// Moves the data to ``str`` clearing the buffer.
void move_to(StringType &str) {
data_.resize(this->size_);
str.swap(data_);
this->capacity_ = this->size_ = 0;
this->ptr_ = FMT_NULL;
}
};
} // namespace internal
/**
\rst
This class template provides operations for formatting and writing data
into a character stream. The output is stored in a ``std::basic_string``
that grows dynamically.
You can use one of the following typedefs for common character types
and the standard allocator:
+---------------+----------------------------+
| Type | Definition |
+===============+============================+
| StringWriter | BasicStringWriter<char> |
+---------------+----------------------------+
| WStringWriter | BasicStringWriter<wchar_t> |
+---------------+----------------------------+
**Example**::
StringWriter out;
out << "The answer is " << 42 << "\n";
This will write the following output to the ``out`` object:
.. code-block:: none
The answer is 42
The output can be moved to a ``std::basic_string`` with ``out.move_to()``.
\endrst
*/
template <typename Char, typename Allocator = std::allocator<Char> >
class BasicStringWriter : public BasicWriter<Char> {
private:
internal::StringBuffer<Char, Allocator> buffer_;
public:
/**
\rst
Constructs a :class:`fmt::BasicStringWriter` object.
\endrst
*/
explicit BasicStringWriter(const Allocator &allocator = Allocator())
: BasicWriter<Char>(buffer_), buffer_(allocator) {}
/**
\rst
Moves the buffer content to *str* clearing the buffer.
\endrst
*/
void move_to(std::basic_string<Char, std::char_traits<Char>, Allocator> &str) {
buffer_.move_to(str);
}
};
typedef BasicStringWriter<char> StringWriter;
typedef BasicStringWriter<wchar_t> WStringWriter;
/**
\rst
Converts *value* to ``std::string`` using the default format for type *T*.
**Example**::
#include "fmt/string.h"
std::string answer = fmt::to_string(42);
\endrst
*/
template <typename T>
std::string to_string(const T &value) {
fmt::MemoryWriter w;
w << value;
return w.str();
}
/**
\rst
Converts *value* to ``std::wstring`` using the default format for type *T*.
**Example**::
#include "fmt/string.h"
std::wstring answer = fmt::to_wstring(42);
\endrst
*/
template <typename T>
std::wstring to_wstring(const T &value) {
fmt::WMemoryWriter w;
w << value;
return w.str();
}
}
#endif // FMT_STRING_H_

View File

@@ -1,143 +0,0 @@
/*
Formatting library for C++ - time formatting
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#ifndef FMT_TIME_H_
#define FMT_TIME_H_
#include "format.h"
#include <ctime>
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4702) // unreachable code
# pragma warning(disable: 4996) // "deprecated" functions
#endif
namespace fmt {
template <typename ArgFormatter>
void format_arg(BasicFormatter<char, ArgFormatter> &f,
const char *&format_str, const std::tm &tm) {
if (*format_str == ':')
++format_str;
const char *end = format_str;
while (*end && *end != '}')
++end;
if (*end != '}')
FMT_THROW(FormatError("missing '}' in format string"));
internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> format;
format.append(format_str, end + 1);
format[format.size() - 1] = '\0';
Buffer<char> &buffer = f.writer().buffer();
std::size_t start = buffer.size();
for (;;) {
std::size_t size = buffer.capacity() - start;
std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm);
if (count != 0) {
buffer.resize(start + count);
break;
}
if (size >= format.size() * 256) {
// If the buffer is 256 times larger than the format string, assume
// that `strftime` gives an empty result. There doesn't seem to be a
// better way to distinguish the two cases:
// https://github.com/fmtlib/fmt/issues/367
break;
}
const std::size_t MIN_GROWTH = 10;
buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
}
format_str = end + 1;
}
namespace internal{
inline Null<> localtime_r(...) { return Null<>(); }
inline Null<> localtime_s(...) { return Null<>(); }
inline Null<> gmtime_r(...) { return Null<>(); }
inline Null<> gmtime_s(...) { return Null<>(); }
}
// Thread-safe replacement for std::localtime
inline std::tm localtime(std::time_t time) {
struct LocalTime {
std::time_t time_;
std::tm tm_;
LocalTime(std::time_t t): time_(t) {}
bool run() {
using namespace fmt::internal;
return handle(localtime_r(&time_, &tm_));
}
bool handle(std::tm *tm) { return tm != FMT_NULL; }
bool handle(internal::Null<>) {
using namespace fmt::internal;
return fallback(localtime_s(&tm_, &time_));
}
bool fallback(int res) { return res == 0; }
bool fallback(internal::Null<>) {
using namespace fmt::internal;
std::tm *tm = std::localtime(&time_);
if (tm) tm_ = *tm;
return tm != FMT_NULL;
}
};
LocalTime lt(time);
if (lt.run())
return lt.tm_;
// Too big time values may be unsupported.
FMT_THROW(fmt::FormatError("time_t value out of range"));
return std::tm();
}
// Thread-safe replacement for std::gmtime
inline std::tm gmtime(std::time_t time) {
struct GMTime {
std::time_t time_;
std::tm tm_;
GMTime(std::time_t t): time_(t) {}
bool run() {
using namespace fmt::internal;
return handle(gmtime_r(&time_, &tm_));
}
bool handle(std::tm *tm) { return tm != FMT_NULL; }
bool handle(internal::Null<>) {
using namespace fmt::internal;
return fallback(gmtime_s(&tm_, &time_));
}
bool fallback(int res) { return res == 0; }
bool fallback(internal::Null<>) {
std::tm *tm = std::gmtime(&time_);
if (tm != FMT_NULL) tm_ = *tm;
return tm != FMT_NULL;
}
};
GMTime gt(time);
if (gt.run())
return gt.tm_;
// Too big time values may be unsupported.
FMT_THROW(fmt::FormatError("time_t value out of range"));
return std::tm();
}
} //namespace fmt
#ifdef _MSC_VER
# pragma warning(pop)
#endif
#endif // FMT_TIME_H_

1331
include/fmt/core.h Normal file

File diff suppressed because it is too large Load Diff

564
include/fmt/format-inl.h Normal file
View File

@@ -0,0 +1,564 @@
// Formatting library for C++
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_FORMAT_INL_H_
#define FMT_FORMAT_INL_H_
#include "format.h"
#include <string.h>
#include <cctype>
#include <cerrno>
#include <climits>
#include <cmath>
#include <cstdarg>
#include <cstddef> // for std::ptrdiff_t
#include <locale>
#if defined(_WIN32) && defined(__MINGW32__)
# include <cstring>
#endif
#if FMT_USE_WINDOWS_H
# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)
# define WIN32_LEAN_AND_MEAN
# endif
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
# include <windows.h>
# else
# define NOMINMAX
# include <windows.h>
# undef NOMINMAX
# endif
#endif
#if FMT_EXCEPTIONS
# define FMT_TRY try
# define FMT_CATCH(x) catch (x)
#else
# define FMT_TRY if (true)
# define FMT_CATCH(x) if (false)
#endif
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant
# pragma warning(disable: 4702) // unreachable code
// Disable deprecation warning for strerror. The latter is not called but
// MSVC fails to detect it.
# pragma warning(disable: 4996)
#endif
// Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available.
inline fmt::internal::null<> strerror_r(int, char *, ...) {
return fmt::internal::null<>();
}
inline fmt::internal::null<> strerror_s(char *, std::size_t, ...) {
return fmt::internal::null<>();
}
FMT_BEGIN_NAMESPACE
namespace {
#ifndef _MSC_VER
# define FMT_SNPRINTF snprintf
#else // _MSC_VER
inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
va_list args;
va_start(args, format);
int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
va_end(args);
return result;
}
# define FMT_SNPRINTF fmt_snprintf
#endif // _MSC_VER
#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
# define FMT_SWPRINTF snwprintf
#else
# define FMT_SWPRINTF swprintf
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
typedef void (*FormatFunc)(internal::buffer &, int, string_view);
// Portable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code.
// This can be either a pointer to a string stored in buffer,
// or a pointer to some static immutable string.
// Returns one of the following values:
// 0 - success
// ERANGE - buffer is not large enough to store the error message
// other - failure
// Buffer should be at least of size 1.
int safe_strerror(
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer");
class dispatcher {
private:
int error_code_;
char *&buffer_;
std::size_t buffer_size_;
// A noop assignment operator to avoid bogus warnings.
void operator=(const dispatcher &) {}
// Handle the result of XSI-compliant version of strerror_r.
int handle(int result) {
// glibc versions before 2.13 return result in errno.
return result == -1 ? errno : result;
}
// Handle the result of GNU-specific version of strerror_r.
int handle(char *message) {
// If the buffer is full then the message is probably truncated.
if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
return ERANGE;
buffer_ = message;
return 0;
}
// Handle the case when strerror_r is not available.
int handle(internal::null<>) {
return fallback(strerror_s(buffer_, buffer_size_, error_code_));
}
// Fallback to strerror_s when strerror_r is not available.
int fallback(int result) {
// If the buffer is full then the message is probably truncated.
return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
ERANGE : result;
}
// Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(internal::null<>) {
errno = 0;
buffer_ = strerror(error_code_);
return errno;
}
public:
dispatcher(int err_code, char *&buf, std::size_t buf_size)
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
int run() {
return handle(strerror_r(error_code_, buffer_, buffer_size_));
}
};
return dispatcher(error_code, buffer, buffer_size).run();
}
void format_error_code(internal::buffer &out, int error_code,
string_view message) FMT_NOEXCEPT {
// Report error code making sure that the output fits into
// inline_buffer_size to avoid dynamic memory allocation and potential
// bad_alloc.
out.resize(0);
static const char SEP[] = ": ";
static const char ERROR_STR[] = "error ";
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
typedef internal::int_traits<int>::main_type main_type;
main_type abs_value = static_cast<main_type>(error_code);
if (internal::is_negative(error_code)) {
abs_value = 0 - abs_value;
++error_code_size;
}
error_code_size += internal::count_digits(abs_value);
writer w(out);
if (message.size() <= inline_buffer_size - error_code_size) {
w.write(message);
w.write(SEP);
}
w.write(ERROR_STR);
w.write(error_code);
assert(out.size() <= inline_buffer_size);
}
void report_error(FormatFunc func, int error_code,
string_view message) FMT_NOEXCEPT {
memory_buffer full_message;
func(full_message, error_code, message);
// Use Writer::data instead of Writer::c_str to avoid potential memory
// allocation.
std::fwrite(full_message.data(), full_message.size(), 1, stderr);
std::fputc('\n', stderr);
}
} // namespace
class locale {
private:
std::locale locale_;
public:
explicit locale(std::locale loc = std::locale()) : locale_(loc) {}
std::locale get() { return locale_; }
};
template <typename Char>
FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
std::locale loc = lp ? lp->locale().get() : std::locale();
return std::use_facet<std::numpunct<Char>>(loc).thousands_sep();
}
FMT_FUNC void system_error::init(
int err_code, string_view format_str, format_args args) {
error_code_ = err_code;
memory_buffer buffer;
format_system_error(buffer, err_code, vformat(format_str, args));
std::runtime_error &base = *this;
base = std::runtime_error(to_string(buffer));
}
namespace internal {
template <typename T>
int char_traits<char>::format_float(
char *buffer, std::size_t size, const char *format, int precision, T value) {
return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, value) :
FMT_SNPRINTF(buffer, size, format, precision, value);
}
template <typename T>
int char_traits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format, int precision,
T value) {
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, value) :
FMT_SWPRINTF(buffer, size, format, precision, value);
}
template <typename T>
const char basic_data<T>::DIGITS[] =
"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";
#define FMT_POWERS_OF_10(factor) \
factor * 10, \
factor * 100, \
factor * 1000, \
factor * 10000, \
factor * 100000, \
factor * 1000000, \
factor * 10000000, \
factor * 100000000, \
factor * 1000000000
template <typename T>
const uint32_t basic_data<T>::POWERS_OF_10_32[] = {
0, FMT_POWERS_OF_10(1)
};
template <typename T>
const uint64_t basic_data<T>::POWERS_OF_10_64[] = {
0,
FMT_POWERS_OF_10(1),
FMT_POWERS_OF_10(1000000000ull),
10000000000000000000ull
};
// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340.
// These are generated by support/compute-powers.py.
template <typename T>
const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {
0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, 0xcf42894a5dce35ea,
0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f,
0xbe5691ef416bd60c, 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, 0xc21094364dfb5637,
0x9096ea6f3848984f, 0xd77485cb25823ac7, 0xa086cfcd97bf97f4, 0xef340a98172aace5,
0xb23867fb2a35b28e, 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, 0xb5b5ada8aaff80b8,
0x87625f056c7c4a8b, 0xc9bcff6034c13053, 0x964e858c91ba2655, 0xdff9772470297ebd,
0xa6dfbd9fb8e5b88f, 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, 0xaa242499697392d3,
0xfd87b5f28300ca0e, 0xbce5086492111aeb, 0x8cbccc096f5088cc, 0xd1b71758e219652c,
0x9c40000000000000, 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984,
0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, 0x9f4f2726179a2245,
0xed63a231d4c4fb27, 0xb0de65388cc8ada8, 0x83c7088e1aab65db, 0xc45d1df942711d9a,
0x924d692ca61be758, 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85,
0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, 0x952ab45cfa97a0b3,
0xde469fbd99a05fe3, 0xa59bc234db398c25, 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece,
0x88fcf317f22241e2, 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a,
0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, 0x8bab8eefb6409c1a,
0xd01fef10a657842c, 0x9b10a4e5e9913129, 0xe7109bfba19c0c9d, 0xac2820d9623bf429,
0x80444b5e7aa7cf85, 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b
};
// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding
// to significands above.
template <typename T>
const int16_t basic_data<T>::POW10_EXPONENTS[] = {
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954,
-927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661,
-635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369,
-343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77,
-50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216,
242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508,
534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800,
827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066
};
template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
FMT_FUNC fp operator*(fp x, fp y) {
// Multiply 32-bit parts of significands.
uint64_t mask = (1ULL << 32) - 1;
uint64_t a = x.f >> 32, b = x.f & mask;
uint64_t c = y.f >> 32, d = y.f & mask;
uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
// Compute mid 64-bit of result and round.
uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64);
}
FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
int index = static_cast<int>(std::ceil(
(min_exponent + fp::significand_size - 1) * one_over_log2_10));
// Decimal exponent of the first (smallest) cached power of 10.
const int first_dec_exp = -348;
// Difference between two consecutive decimal exponents in cached powers of 10.
const int dec_exp_step = 8;
index = (index - first_dec_exp - 1) / dec_exp_step + 1;
pow10_exponent = first_dec_exp + index * dec_exp_step;
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
}
} // namespace internal
#if FMT_USE_WINDOWS_H
FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
if (s.size() > INT_MAX)
FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG));
int s_size = static_cast<int>(s.size());
if (s_size == 0) {
// MultiByteToWideChar does not support zero length, handle separately.
buffer_.resize(1);
buffer_[0] = 0;
return;
}
int length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
if (length == 0)
FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
buffer_.resize(length + 1);
length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
if (length == 0)
FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
buffer_[length] = 0;
}
FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
if (int error_code = convert(s)) {
FMT_THROW(windows_error(error_code,
"cannot convert string from UTF-16 to UTF-8"));
}
}
FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
if (s.size() > INT_MAX)
return ERROR_INVALID_PARAMETER;
int s_size = static_cast<int>(s.size());
if (s_size == 0) {
// WideCharToMultiByte does not support zero length, handle separately.
buffer_.resize(1);
buffer_[0] = 0;
return 0;
}
int length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
if (length == 0)
return GetLastError();
buffer_.resize(length + 1);
length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
if (length == 0)
return GetLastError();
buffer_[length] = 0;
return 0;
}
FMT_FUNC void windows_error::init(
int err_code, string_view format_str, format_args args) {
error_code_ = err_code;
memory_buffer buffer;
internal::format_windows_error(buffer, err_code, vformat(format_str, args));
std::runtime_error &base = *this;
base = std::runtime_error(to_string(buffer));
}
FMT_FUNC void internal::format_windows_error(
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
FMT_TRY {
wmemory_buffer buf;
buf.resize(inline_buffer_size);
for (;;) {
wchar_t *system_message = &buf[0];
int result = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
system_message, static_cast<uint32_t>(buf.size()), FMT_NULL);
if (result != 0) {
utf16_to_utf8 utf8_message;
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
writer w(out);
w.write(message);
w.write(": ");
w.write(utf8_message);
return;
}
break;
}
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
break; // Can't get error message, report error code instead.
buf.resize(buf.size() * 2);
}
} FMT_CATCH(...) {}
format_error_code(out, error_code, message);
}
#endif // FMT_USE_WINDOWS_H
FMT_FUNC void format_system_error(
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
FMT_TRY {
memory_buffer buf;
buf.resize(inline_buffer_size);
for (;;) {
char *system_message = &buf[0];
int result = safe_strerror(error_code, system_message, buf.size());
if (result == 0) {
writer w(out);
w.write(message);
w.write(": ");
w.write(system_message);
return;
}
if (result != ERANGE)
break; // Can't get error message, report error code instead.
buf.resize(buf.size() * 2);
}
} FMT_CATCH(...) {}
format_error_code(out, error_code, message);
}
template <typename Char>
void basic_fixed_buffer<Char>::grow(std::size_t) {
FMT_THROW(std::runtime_error("buffer overflow"));
}
FMT_FUNC void internal::error_handler::on_error(const char *message) {
FMT_THROW(format_error(message));
}
FMT_FUNC void report_system_error(
int error_code, fmt::string_view message) FMT_NOEXCEPT {
report_error(format_system_error, error_code, message);
}
#if FMT_USE_WINDOWS_H
FMT_FUNC void report_windows_error(
int error_code, fmt::string_view message) FMT_NOEXCEPT {
report_error(internal::format_windows_error, error_code, message);
}
#endif
FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
memory_buffer buffer;
vformat_to(buffer, format_str, args);
std::fwrite(buffer.data(), 1, buffer.size(), f);
}
FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
wmemory_buffer buffer;
vformat_to(buffer, format_str, args);
std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
}
FMT_FUNC void vprint(string_view format_str, format_args args) {
vprint(stdout, format_str, args);
}
FMT_FUNC void vprint(wstring_view format_str, wformat_args args) {
vprint(stdout, format_str, args);
}
#ifndef FMT_EXTENDED_COLORS
FMT_FUNC void vprint_colored(color c, string_view format, format_args args) {
char escape[] = "\x1b[30m";
escape[3] = static_cast<char>('0' + c);
std::fputs(escape, stdout);
vprint(format, args);
std::fputs(internal::data::RESET_COLOR, stdout);
}
FMT_FUNC void vprint_colored(color c, wstring_view format, wformat_args args) {
wchar_t escape[] = L"\x1b[30m";
escape[3] = static_cast<wchar_t>('0' + c);
std::fputws(escape, stdout);
vprint(format, args);
std::fputws(internal::data::WRESET_COLOR, stdout);
}
#else
namespace internal {
FMT_CONSTEXPR void to_esc(uint8_t c, char out[], int offset) {
out[offset + 0] = static_cast<char>('0' + c / 100);
out[offset + 1] = static_cast<char>('0' + c / 10 % 10);
out[offset + 2] = static_cast<char>('0' + c % 10);
}
} // namespace internal
FMT_FUNC void vprint_rgb(rgb fd, string_view format, format_args args) {
char escape_fd[] = "\x1b[38;2;000;000;000m";
internal::to_esc(fd.r, escape_fd, 7);
internal::to_esc(fd.g, escape_fd, 11);
internal::to_esc(fd.b, escape_fd, 15);
std::fputs(escape_fd, stdout);
vprint(format, args);
std::fputs(internal::data::RESET_COLOR, stdout);
}
FMT_FUNC void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args) {
char escape_fd[] = "\x1b[38;2;000;000;000m"; // foreground color
char escape_bg[] = "\x1b[48;2;000;000;000m"; // background color
internal::to_esc(fd.r, escape_fd, 7);
internal::to_esc(fd.g, escape_fd, 11);
internal::to_esc(fd.b, escape_fd, 15);
internal::to_esc(bg.r, escape_bg, 7);
internal::to_esc(bg.g, escape_bg, 11);
internal::to_esc(bg.b, escape_bg, 15);
std::fputs(escape_fd, stdout);
std::fputs(escape_bg, stdout);
vprint(format, args);
std::fputs(internal::data::RESET_COLOR, stdout);
}
#endif
FMT_FUNC locale locale_provider::locale() { return fmt::locale(); }
FMT_END_NAMESPACE
#ifdef _MSC_VER
# pragma warning(pop)
#endif
#endif // FMT_FORMAT_INL_H_

3937
include/fmt/format.h Normal file

File diff suppressed because it is too large Load Diff

162
include/fmt/ostream.h Normal file
View File

@@ -0,0 +1,162 @@
// Formatting library for C++ - std::ostream support
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_
#include "format.h"
#include <ostream>
FMT_BEGIN_NAMESPACE
namespace internal {
template <class Char>
class formatbuf : public std::basic_streambuf<Char> {
private:
typedef typename std::basic_streambuf<Char>::int_type int_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
basic_buffer<Char> &buffer_;
public:
formatbuf(basic_buffer<Char> &buffer) : buffer_(buffer) {}
protected:
// The put-area is actually always empty. This makes the implementation
// simpler and has the advantage that the streambuf and the buffer are always
// in sync and sputc never writes into uninitialized memory. The obvious
// disadvantage is that each call to sputc always results in a (virtual) call
// to overflow. There is no disadvantage here for sputn since this always
// results in a call to xsputn.
int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
if (!traits_type::eq_int_type(ch, traits_type::eof()))
buffer_.push_back(static_cast<Char>(ch));
return ch;
}
std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE {
buffer_.append(s, s + count);
return count;
}
};
template <typename Char>
struct test_stream : std::basic_ostream<Char> {
private:
struct null;
// Hide all operator<< from std::basic_ostream<Char>.
void operator<<(null);
};
// Checks if T has a user-defined operator<< (e.g. not a member of std::ostream).
template <typename T, typename Char>
class is_streamable {
private:
template <typename U>
static decltype(
internal::declval<test_stream<Char>&>()
<< internal::declval<U>(), std::true_type()) test(int);
template <typename>
static std::false_type test(...);
typedef decltype(test<T>(0)) result;
public:
// std::string operator<< is not considered user-defined because we handle strings
// specially.
static const bool value = result::value && !std::is_same<T, std::string>::value;
};
// Disable conversion to int if T has an overloaded operator<< which is a free
// function (not a member of std::ostream).
template <typename T, typename Char>
class convert_to_int<T, Char, true> {
public:
static const bool value =
convert_to_int<T, Char, false>::value && !is_streamable<T, Char>::value;
};
// Write the content of buf to os.
template <typename Char>
void write(std::basic_ostream<Char> &os, basic_buffer<Char> &buf) {
const Char *data = buf.data();
typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize;
UnsignedStreamSize size = buf.size();
UnsignedStreamSize max_size =
internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
do {
UnsignedStreamSize n = size <= max_size ? size : max_size;
os.write(data, static_cast<std::streamsize>(n));
data += n;
size -= n;
} while (size != 0);
}
template <typename Char, typename T>
void format_value(basic_buffer<Char> &buffer, const T &value) {
internal::formatbuf<Char> format_buf(buffer);
std::basic_ostream<Char> output(&format_buf);
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
output << value;
buffer.resize(buffer.size());
}
// Disable builtin formatting of enums and use operator<< instead.
template <typename T>
struct format_enum<T,
typename std::enable_if<std::is_enum<T>::value>::type> : std::false_type {};
} // namespace internal
// Formats an object of type T that has an overloaded ostream operator<<.
template <typename T, typename Char>
struct formatter<T, Char,
typename std::enable_if<internal::is_streamable<T, Char>::value>::type>
: formatter<basic_string_view<Char>, Char> {
template <typename Context>
auto format(const T &value, Context &ctx) -> decltype(ctx.out()) {
basic_memory_buffer<Char> buffer;
internal::format_value(buffer, value);
basic_string_view<Char> str(buffer.data(), buffer.size());
formatter<basic_string_view<Char>, Char>::format(str, ctx);
return ctx.out();
}
};
template <typename Char>
inline void vprint(std::basic_ostream<Char> &os,
basic_string_view<Char> format_str,
basic_format_args<typename buffer_context<Char>::type> args) {
basic_memory_buffer<Char> buffer;
vformat_to(buffer, format_str, args);
internal::write(os, buffer);
}
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fmt::print(cerr, "Don't {}!", "panic");
\endrst
*/
template <typename... Args>
inline void print(std::ostream &os, string_view format_str,
const Args & ... args) {
vprint<char>(os, format_str, make_format_args<format_context>(args...));
}
template <typename... Args>
inline void print(std::wostream &os, wstring_view format_str,
const Args & ... args) {
vprint<wchar_t>(os, format_str, make_format_args<wformat_context>(args...));
}
FMT_END_NAMESPACE
#endif // FMT_OSTREAM_H_

View File

@@ -1,11 +1,9 @@
/*
A C++ interface to POSIX functions.
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
// A C++ interface to POSIX functions.
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_POSIX_H_
#define FMT_POSIX_H_
@@ -64,34 +62,82 @@
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
namespace fmt {
FMT_BEGIN_NAMESPACE
/**
\rst
A reference to a null-terminated string. It can be constructed from a C
string or ``std::string``.
You can use one of the following typedefs for common character types:
+---------------+-----------------------------+
| Type | Definition |
+===============+=============================+
| cstring_view | basic_cstring_view<char> |
+---------------+-----------------------------+
| wcstring_view | basic_cstring_view<wchar_t> |
+---------------+-----------------------------+
This class is most useful as a parameter type to allow passing
different types of strings to a function, for example::
template <typename... Args>
std::string format(cstring_view format_str, const Args & ... args);
format("{}", 42);
format(std::string("{}"), 42);
\endrst
*/
template <typename Char>
class basic_cstring_view {
private:
const Char *data_;
public:
/** Constructs a string reference object from a C string. */
basic_cstring_view(const Char *s) : data_(s) {}
/**
\rst
Constructs a string reference from an ``std::string`` object.
\endrst
*/
basic_cstring_view(const std::basic_string<Char> &s) : data_(s.c_str()) {}
/** Returns the pointer to a C string. */
const Char *c_str() const { return data_; }
};
typedef basic_cstring_view<char> cstring_view;
typedef basic_cstring_view<wchar_t> wcstring_view;
// An error code.
class ErrorCode {
class error_code {
private:
int value_;
public:
explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {}
explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {}
int get() const FMT_NOEXCEPT { return value_; }
};
// A buffered file.
class BufferedFile {
class buffered_file {
private:
FILE *file_;
friend class File;
friend class file;
explicit BufferedFile(FILE *f) : file_(f) {}
explicit buffered_file(FILE *f) : file_(f) {}
public:
// Constructs a BufferedFile object which doesn't represent any file.
BufferedFile() FMT_NOEXCEPT : file_(FMT_NULL) {}
// Constructs a buffered_file object which doesn't represent any file.
buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {}
// Destroys the object closing the file it represents if any.
FMT_API ~BufferedFile() FMT_NOEXCEPT;
FMT_API ~buffered_file() FMT_DTOR_NOEXCEPT;
#if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue
@@ -106,22 +152,22 @@ class BufferedFile {
public:
// A "move constructor" for moving from a temporary.
BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {}
buffered_file(Proxy p) FMT_NOEXCEPT : file_(p.file) {}
// A "move constructor" for moving from an lvalue.
BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) {
buffered_file(buffered_file &f) FMT_NOEXCEPT : file_(f.file_) {
f.file_ = FMT_NULL;
}
// A "move assignment operator" for moving from a temporary.
BufferedFile &operator=(Proxy p) {
buffered_file &operator=(Proxy p) {
close();
file_ = p.file;
return *this;
}
// A "move assignment operator" for moving from an lvalue.
BufferedFile &operator=(BufferedFile &other) {
buffered_file &operator=(buffered_file &other) {
close();
file_ = other.file_;
other.file_ = FMT_NULL;
@@ -129,7 +175,7 @@ public:
}
// Returns a proxy object for moving from a temporary:
// BufferedFile file = BufferedFile(...);
// buffered_file file = buffered_file(...);
operator Proxy() FMT_NOEXCEPT {
Proxy p = {file_};
file_ = FMT_NULL;
@@ -138,14 +184,14 @@ public:
#else
private:
FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile);
FMT_DISALLOW_COPY_AND_ASSIGN(buffered_file);
public:
BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) {
buffered_file(buffered_file &&other) FMT_NOEXCEPT : file_(other.file_) {
other.file_ = FMT_NULL;
}
BufferedFile& operator=(BufferedFile &&other) {
buffered_file& operator=(buffered_file &&other) {
close();
file_ = other.file_;
other.file_ = FMT_NULL;
@@ -154,7 +200,7 @@ public:
#endif
// Opens a file.
FMT_API BufferedFile(CStringRef filename, CStringRef mode);
FMT_API buffered_file(cstring_view filename, cstring_view mode);
// Closes the file.
FMT_API void close();
@@ -166,24 +212,28 @@ public:
// of MinGW that define fileno as a macro.
FMT_API int (fileno)() const;
void print(CStringRef format_str, const ArgList &args) {
fmt::print(file_, format_str, args);
void vprint(string_view format_str, format_args args) {
fmt::vprint(file_, format_str, args);
}
template <typename... Args>
inline void print(string_view format_str, const Args & ... args) {
vprint(format_str, make_format_args(args...));
}
FMT_VARIADIC(void, print, CStringRef)
};
// A file. Closed file is represented by a File object with descriptor -1.
// A file. Closed file is represented by a file object with descriptor -1.
// Methods that are not declared with FMT_NOEXCEPT may throw
// fmt::SystemError in case of failure. Note that some errors such as
// fmt::system_error in case of failure. Note that some errors such as
// closing the file multiple times will cause a crash on Windows rather
// than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler.
class File {
class file {
private:
int fd_; // File descriptor.
// Constructs a File object with a given descriptor.
explicit File(int fd) : fd_(fd) {}
// Constructs a file object with a given descriptor.
explicit file(int fd) : fd_(fd) {}
public:
// Possible values for the oflag argument to the constructor.
@@ -193,11 +243,11 @@ class File {
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
};
// Constructs a File object which doesn't represent any file.
File() FMT_NOEXCEPT : fd_(-1) {}
// Constructs a file object which doesn't represent any file.
file() FMT_NOEXCEPT : fd_(-1) {}
// Opens a file and constructs a File object representing this file.
FMT_API File(CStringRef path, int oflag);
// Opens a file and constructs a file object representing this file.
FMT_API file(cstring_view path, int oflag);
#if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue
@@ -212,22 +262,22 @@ class File {
public:
// A "move constructor" for moving from a temporary.
File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
file(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
// A "move constructor" for moving from an lvalue.
File(File &other) FMT_NOEXCEPT : fd_(other.fd_) {
file(file &other) FMT_NOEXCEPT : fd_(other.fd_) {
other.fd_ = -1;
}
// A "move assignment operator" for moving from a temporary.
File &operator=(Proxy p) {
file &operator=(Proxy p) {
close();
fd_ = p.fd;
return *this;
}
// A "move assignment operator" for moving from an lvalue.
File &operator=(File &other) {
file &operator=(file &other) {
close();
fd_ = other.fd_;
other.fd_ = -1;
@@ -235,7 +285,7 @@ class File {
}
// Returns a proxy object for moving from a temporary:
// File file = File(...);
// file f = file(...);
operator Proxy() FMT_NOEXCEPT {
Proxy p = {fd_};
fd_ = -1;
@@ -244,14 +294,14 @@ class File {
#else
private:
FMT_DISALLOW_COPY_AND_ASSIGN(File);
FMT_DISALLOW_COPY_AND_ASSIGN(file);
public:
File(File &&other) FMT_NOEXCEPT : fd_(other.fd_) {
file(file &&other) FMT_NOEXCEPT : fd_(other.fd_) {
other.fd_ = -1;
}
File& operator=(File &&other) {
file& operator=(file &&other) {
close();
fd_ = other.fd_;
other.fd_ = -1;
@@ -260,7 +310,7 @@ class File {
#endif
// Destroys the object closing the file it represents if any.
FMT_API ~File() FMT_NOEXCEPT;
FMT_API ~file() FMT_DTOR_NOEXCEPT;
// Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT { return fd_; }
@@ -270,7 +320,7 @@ class File {
// Returns the file size. The size has signed type for consistency with
// stat::st_size.
FMT_API LongLong size() const;
FMT_API long long size() const;
// Attempts to read count bytes from the file into the specified buffer.
FMT_API std::size_t read(void *buffer, std::size_t count);
@@ -280,7 +330,7 @@ class File {
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
FMT_API static File dup(int fd);
FMT_API static file dup(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
@@ -288,22 +338,22 @@ class File {
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
FMT_API void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT;
FMT_API void dup2(int fd, error_code &ec) FMT_NOEXCEPT;
// Creates a pipe setting up read_end and write_end file objects for reading
// and writing respectively.
FMT_API static void pipe(File &read_end, File &write_end);
FMT_API static void pipe(file &read_end, file &write_end);
// Creates a BufferedFile object associated with this file and detaches
// this File object from the file.
FMT_API BufferedFile fdopen(const char *mode);
// Creates a buffered_file object associated with this file and detaches
// this file object from the file.
FMT_API buffered_file fdopen(const char *mode);
};
// Returns the memory page size.
long getpagesize();
#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
!defined(__ANDROID__) && !defined(__CYGWIN__)
!defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__)
# define FMT_LOCALE
#endif
@@ -338,7 +388,7 @@ class Locale {
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) {
if (!locale_)
FMT_THROW(fmt::SystemError(errno, "cannot create locale"));
FMT_THROW(system_error(errno, "cannot create locale"));
}
~Locale() { freelocale(locale_); }
@@ -354,13 +404,13 @@ class Locale {
}
};
#endif // FMT_LOCALE
} // namespace fmt
FMT_END_NAMESPACE
#if !FMT_USE_RVALUE_REFERENCES
namespace std {
// For compatibility with C++98.
inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; }
inline fmt::File &move(fmt::File &f) { return f; }
inline fmt::buffered_file &move(fmt::buffered_file &f) { return f; }
inline fmt::file &move(fmt::file &f) { return f; }
}
#endif

728
include/fmt/printf.h Normal file
View File

@@ -0,0 +1,728 @@
// Formatting library for C++
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_PRINTF_H_
#define FMT_PRINTF_H_
#include <algorithm> // std::fill_n
#include <limits> // std::numeric_limits
#include "ostream.h"
FMT_BEGIN_NAMESPACE
namespace internal {
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
template <bool IsSigned>
struct int_checker {
template <typename T>
static bool fits_in_int(T value) {
unsigned max = std::numeric_limits<int>::max();
return value <= max;
}
static bool fits_in_int(bool) { return true; }
};
template <>
struct int_checker<true> {
template <typename T>
static bool fits_in_int(T value) {
return value >= std::numeric_limits<int>::min() &&
value <= std::numeric_limits<int>::max();
}
static bool fits_in_int(int) { return true; }
};
class printf_precision_handler: public function<int> {
public:
template <typename T>
typename std::enable_if<std::is_integral<T>::value, int>::type
operator()(T value) {
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
FMT_THROW(format_error("number is too big"));
return static_cast<int>(value);
}
template <typename T>
typename std::enable_if<!std::is_integral<T>::value, int>::type operator()(T) {
FMT_THROW(format_error("precision is not integer"));
return 0;
}
};
// An argument visitor that returns true iff arg is a zero integer.
class is_zero_int: public function<bool> {
public:
template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type
operator()(T value) { return value == 0; }
template <typename T>
typename std::enable_if<!std::is_integral<T>::value, bool>::type
operator()(T) { return false; }
};
template <typename T>
struct make_unsigned_or_bool : std::make_unsigned<T> {};
template <>
struct make_unsigned_or_bool<bool> {
typedef bool type;
};
template <typename T, typename Context>
class arg_converter: public function<void> {
private:
typedef typename Context::char_type Char;
basic_format_arg<Context> &arg_;
typename Context::char_type type_;
public:
arg_converter(basic_format_arg<Context> &arg, Char type)
: arg_(arg), type_(type) {}
void operator()(bool value) {
if (type_ != 's')
operator()<bool>(value);
}
template <typename U>
typename std::enable_if<std::is_integral<U>::value>::type
operator()(U value) {
bool is_signed = type_ == 'd' || type_ == 'i';
typedef typename std::conditional<
std::is_same<T, void>::value, U, T>::type TargetType;
if (const_check(sizeof(TargetType) <= sizeof(int))) {
// Extra casts are used to silence warnings.
if (is_signed) {
arg_ = internal::make_arg<Context>(
static_cast<int>(static_cast<TargetType>(value)));
} else {
typedef typename make_unsigned_or_bool<TargetType>::type Unsigned;
arg_ = internal::make_arg<Context>(
static_cast<unsigned>(static_cast<Unsigned>(value)));
}
} else {
if (is_signed) {
// glibc's printf doesn't sign extend arguments of smaller types:
// std::printf("%lld", -42); // prints "4294967254"
// but we don't have to do the same because it's a UB.
arg_ = internal::make_arg<Context>(static_cast<long long>(value));
} else {
arg_ = internal::make_arg<Context>(
static_cast<typename make_unsigned_or_bool<U>::type>(value));
}
}
}
template <typename U>
typename std::enable_if<!std::is_integral<U>::value>::type operator()(U) {
// No coversion needed for non-integral types.
}
};
// Converts an integer argument to T for printf, if T is an integral type.
// If T is void, the argument is converted to corresponding signed or unsigned
// type depending on the type specifier: 'd' and 'i' - signed, other -
// unsigned).
template <typename T, typename Context, typename Char>
void convert_arg(basic_format_arg<Context> &arg, Char type) {
visit(arg_converter<T, Context>(arg, type), arg);
}
// Converts an integer argument to char for printf.
template <typename Context>
class char_converter: public function<void> {
private:
basic_format_arg<Context> &arg_;
FMT_DISALLOW_COPY_AND_ASSIGN(char_converter);
public:
explicit char_converter(basic_format_arg<Context> &arg) : arg_(arg) {}
template <typename T>
typename std::enable_if<std::is_integral<T>::value>::type
operator()(T value) {
typedef typename Context::char_type Char;
arg_ = internal::make_arg<Context>(static_cast<Char>(value));
}
template <typename T>
typename std::enable_if<!std::is_integral<T>::value>::type operator()(T) {
// No coversion needed for non-integral types.
}
};
// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
template <typename Char>
class printf_width_handler: public function<unsigned> {
private:
typedef basic_format_specs<Char> format_specs;
format_specs &spec_;
FMT_DISALLOW_COPY_AND_ASSIGN(printf_width_handler);
public:
explicit printf_width_handler(format_specs &spec) : spec_(spec) {}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, unsigned>::type
operator()(T value) {
typedef typename internal::int_traits<T>::main_type UnsignedType;
UnsignedType width = static_cast<UnsignedType>(value);
if (internal::is_negative(value)) {
spec_.align_ = ALIGN_LEFT;
width = 0 - width;
}
unsigned int_max = std::numeric_limits<int>::max();
if (width > int_max)
FMT_THROW(format_error("number is too big"));
return static_cast<unsigned>(width);
}
template <typename T>
typename std::enable_if<!std::is_integral<T>::value, unsigned>::type
operator()(T) {
FMT_THROW(format_error("width is not integer"));
return 0;
}
};
} // namespace internal
template <typename Range>
class printf_arg_formatter;
template <
typename OutputIt, typename Char,
typename ArgFormatter =
printf_arg_formatter<back_insert_range<internal::basic_buffer<Char>>>>
class basic_printf_context;
/**
\rst
The ``printf`` argument formatter.
\endrst
*/
template <typename Range>
class printf_arg_formatter:
public internal::function<
typename internal::arg_formatter_base<Range>::iterator>,
public internal::arg_formatter_base<Range> {
private:
typedef typename Range::value_type char_type;
typedef decltype(internal::declval<Range>().begin()) iterator;
typedef internal::arg_formatter_base<Range> base;
typedef basic_printf_context<iterator, char_type> context_type;
context_type &context_;
void write_null_pointer(char) {
this->spec().type_ = 0;
this->write("(nil)");
}
void write_null_pointer(wchar_t) {
this->spec().type_ = 0;
this->write(L"(nil)");
}
public:
typedef typename base::format_specs format_specs;
/**
\rst
Constructs an argument formatter object.
*buffer* is a reference to the output buffer and *spec* contains format
specifier information for standard argument types.
\endrst
*/
printf_arg_formatter(internal::basic_buffer<char_type> &buffer,
format_specs &spec, context_type &ctx)
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer), spec),
context_(ctx) {}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, iterator>::type
operator()(T value) {
// MSVC2013 fails to compile separate overloads for bool and char_type so
// use std::is_same instead.
if (std::is_same<T, bool>::value) {
format_specs &fmt_spec = this->spec();
if (fmt_spec.type_ != 's')
return base::operator()(value ? 1 : 0);
fmt_spec.type_ = 0;
this->write(value != 0);
} else if (std::is_same<T, char_type>::value) {
format_specs &fmt_spec = this->spec();
if (fmt_spec.type_ && fmt_spec.type_ != 'c')
return (*this)(static_cast<int>(value));
fmt_spec.flags_ = 0;
fmt_spec.align_ = ALIGN_RIGHT;
return base::operator()(value);
} else {
return base::operator()(value);
}
return this->out();
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, iterator>::type
operator()(T value) {
return base::operator()(value);
}
/** Formats a null-terminated C string. */
iterator operator()(const char *value) {
if (value)
base::operator()(value);
else if (this->spec().type_ == 'p')
write_null_pointer(char_type());
else
this->write("(null)");
return this->out();
}
/** Formats a null-terminated wide C string. */
iterator operator()(const wchar_t *value) {
if (value)
base::operator()(value);
else if (this->spec().type_ == 'p')
write_null_pointer(char_type());
else
this->write(L"(null)");
return this->out();
}
iterator operator()(basic_string_view<char_type> value) {
return base::operator()(value);
}
iterator operator()(monostate value) {
return base::operator()(value);
}
/** Formats a pointer. */
iterator operator()(const void *value) {
if (value)
return base::operator()(value);
this->spec().type_ = 0;
write_null_pointer(char_type());
return this->out();
}
/** Formats an argument of a custom (user-defined) type. */
iterator operator()(typename basic_format_arg<context_type>::handle handle) {
handle.format(context_);
return this->out();
}
};
template <typename T>
struct printf_formatter {
template <typename ParseContext>
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { return ctx.begin(); }
template <typename FormatContext>
auto format(const T &value, FormatContext &ctx) -> decltype(ctx.out()) {
internal::format_value(internal::get_container(ctx.out()), value);
return ctx.out();
}
};
/** This template formats data and writes the output to a writer. */
template <typename OutputIt, typename Char, typename ArgFormatter>
class basic_printf_context :
private internal::context_base<
OutputIt, basic_printf_context<OutputIt, Char, ArgFormatter>, Char> {
public:
/** The character type for the output. */
typedef Char char_type;
template <typename T>
struct formatter_type { typedef printf_formatter<T> type; };
private:
typedef internal::context_base<OutputIt, basic_printf_context, Char> base;
typedef typename base::format_arg format_arg;
typedef basic_format_specs<char_type> format_specs;
typedef internal::null_terminating_iterator<char_type> iterator;
void parse_flags(format_specs &spec, iterator &it);
// Returns the argument with specified index or, if arg_index is equal
// to the maximum unsigned value, the next argument.
format_arg get_arg(
iterator it,
unsigned arg_index = (std::numeric_limits<unsigned>::max)());
// Parses argument index, flags and width and returns the argument index.
unsigned parse_header(iterator &it, format_specs &spec);
public:
/**
\rst
Constructs a ``printf_context`` object. References to the arguments and
the writer are stored in the context object so make sure they have
appropriate lifetimes.
\endrst
*/
basic_printf_context(OutputIt out, basic_string_view<char_type> format_str,
basic_format_args<basic_printf_context> args)
: base(out, format_str, args) {}
using base::parse_context;
using base::out;
using base::advance_to;
/** Formats stored arguments and writes the output to the range. */
void format();
};
template <typename OutputIt, typename Char, typename AF>
void basic_printf_context<OutputIt, Char, AF>::parse_flags(
format_specs &spec, iterator &it) {
for (;;) {
switch (*it++) {
case '-':
spec.align_ = ALIGN_LEFT;
break;
case '+':
spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
break;
case '0':
spec.fill_ = '0';
break;
case ' ':
spec.flags_ |= SIGN_FLAG;
break;
case '#':
spec.flags_ |= HASH_FLAG;
break;
default:
--it;
return;
}
}
}
template <typename OutputIt, typename Char, typename AF>
typename basic_printf_context<OutputIt, Char, AF>::format_arg
basic_printf_context<OutputIt, Char, AF>::get_arg(
iterator it, unsigned arg_index) {
(void)it;
if (arg_index == std::numeric_limits<unsigned>::max())
return this->do_get_arg(this->parse_context().next_arg_id());
return base::get_arg(arg_index - 1);
}
template <typename OutputIt, typename Char, typename AF>
unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
iterator &it, format_specs &spec) {
unsigned arg_index = std::numeric_limits<unsigned>::max();
char_type c = *it;
if (c >= '0' && c <= '9') {
// Parse an argument index (if followed by '$') or a width possibly
// preceded with '0' flag(s).
internal::error_handler eh;
unsigned value = parse_nonnegative_int(it, eh);
if (*it == '$') { // value is an argument index
++it;
arg_index = value;
} else {
if (c == '0')
spec.fill_ = '0';
if (value != 0) {
// Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now.
spec.width_ = value;
return arg_index;
}
}
}
parse_flags(spec, it);
// Parse width.
if (*it >= '0' && *it <= '9') {
internal::error_handler eh;
spec.width_ = parse_nonnegative_int(it, eh);
} else if (*it == '*') {
++it;
spec.width_ =
visit(internal::printf_width_handler<char_type>(spec), get_arg(it));
}
return arg_index;
}
template <typename OutputIt, typename Char, typename AF>
void basic_printf_context<OutputIt, Char, AF>::format() {
auto &buffer = internal::get_container(this->out());
auto start = iterator(this->parse_context());
auto it = start;
using internal::pointer_from;
while (*it) {
char_type c = *it++;
if (c != '%') continue;
if (*it == c) {
buffer.append(pointer_from(start), pointer_from(it));
start = ++it;
continue;
}
buffer.append(pointer_from(start), pointer_from(it) - 1);
format_specs spec;
spec.align_ = ALIGN_RIGHT;
// Parse argument index, flags and width.
unsigned arg_index = parse_header(it, spec);
// Parse precision.
if (*it == '.') {
++it;
if ('0' <= *it && *it <= '9') {
internal::error_handler eh;
spec.precision_ = static_cast<int>(parse_nonnegative_int(it, eh));
} else if (*it == '*') {
++it;
spec.precision_ =
visit(internal::printf_precision_handler(), get_arg(it));
} else {
spec.precision_ = 0;
}
}
format_arg arg = get_arg(it, arg_index);
if (spec.flag(HASH_FLAG) && visit(internal::is_zero_int(), arg))
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
if (spec.fill_ == '0') {
if (arg.is_arithmetic())
spec.align_ = ALIGN_NUMERIC;
else
spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
}
// Parse length and convert the argument to the required type.
using internal::convert_arg;
switch (*it++) {
case 'h':
if (*it == 'h')
convert_arg<signed char>(arg, *++it);
else
convert_arg<short>(arg, *it);
break;
case 'l':
if (*it == 'l')
convert_arg<long long>(arg, *++it);
else
convert_arg<long>(arg, *it);
break;
case 'j':
convert_arg<intmax_t>(arg, *it);
break;
case 'z':
convert_arg<std::size_t>(arg, *it);
break;
case 't':
convert_arg<std::ptrdiff_t>(arg, *it);
break;
case 'L':
// printf produces garbage when 'L' is omitted for long double, no
// need to do the same.
break;
default:
--it;
convert_arg<void>(arg, *it);
}
// Parse type.
if (!*it)
FMT_THROW(format_error("invalid format string"));
spec.type_ = static_cast<char>(*it++);
if (arg.is_integral()) {
// Normalize type.
switch (spec.type_) {
case 'i': case 'u':
spec.type_ = 'd';
break;
case 'c':
// TODO: handle wchar_t better?
visit(internal::char_converter<basic_printf_context>(arg), arg);
break;
}
}
start = it;
// Format argument.
visit(AF(buffer, spec, *this), arg);
}
buffer.append(pointer_from(start), pointer_from(it));
}
template <typename Char, typename Context>
void printf(internal::basic_buffer<Char> &buf, basic_string_view<Char> format,
basic_format_args<Context> args) {
Context(std::back_inserter(buf), format, args).format();
}
template <typename Buffer>
struct printf_context {
typedef basic_printf_context<
std::back_insert_iterator<Buffer>, typename Buffer::value_type> type;
};
template <typename ...Args>
inline format_arg_store<printf_context<internal::buffer>::type, Args...>
make_printf_args(const Args & ... args) {
return format_arg_store<printf_context<internal::buffer>::type, Args...>(
args...);
}
typedef basic_format_args<printf_context<internal::buffer>::type> printf_args;
typedef basic_format_args<printf_context<internal::wbuffer>::type> wprintf_args;
inline std::string vsprintf(string_view format, printf_args args) {
memory_buffer buffer;
printf(buffer, format, args);
return to_string(buffer);
}
/**
\rst
Formats arguments and returns the result as a string.
**Example**::
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
*/
template <typename... Args>
inline std::string sprintf(string_view format_str, const Args & ... args) {
return vsprintf(format_str,
make_format_args<typename printf_context<internal::buffer>::type>(args...));
}
inline std::wstring vsprintf(wstring_view format, wprintf_args args) {
wmemory_buffer buffer;
printf(buffer, format, args);
return to_string(buffer);
}
template <typename... Args>
inline std::wstring sprintf(wstring_view format_str, const Args & ... args) {
return vsprintf(format_str,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
}
template <typename Char>
inline int vfprintf(std::FILE *f, basic_string_view<Char> format,
basic_format_args<typename printf_context<
internal::basic_buffer<Char>>::type> args) {
basic_memory_buffer<Char> buffer;
printf(buffer, format, args);
std::size_t size = buffer.size();
return std::fwrite(
buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size);
}
/**
\rst
Prints formatted data to the file *f*.
**Example**::
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
template <typename... Args>
inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args) {
auto vargs = make_format_args<
typename printf_context<internal::buffer>::type>(args...);
return vfprintf<char>(f, format_str, vargs);
}
template <typename... Args>
inline int fprintf(std::FILE *f, wstring_view format_str,
const Args & ... args) {
return vfprintf(f, format_str,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
}
inline int vprintf(string_view format, printf_args args) {
return vfprintf(stdout, format, args);
}
inline int vprintf(wstring_view format, wprintf_args args) {
return vfprintf(stdout, format, args);
}
/**
\rst
Prints formatted data to ``stdout``.
**Example**::
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
template <typename... Args>
inline int printf(string_view format_str, const Args & ... args) {
return vprintf(format_str,
make_format_args<typename printf_context<internal::buffer>::type>(args...));
}
template <typename... Args>
inline int printf(wstring_view format_str, const Args & ... args) {
return vprintf(format_str,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
}
inline int vfprintf(std::ostream &os, string_view format_str,
printf_args args) {
memory_buffer buffer;
printf(buffer, format_str, args);
internal::write(os, buffer);
return static_cast<int>(buffer.size());
}
inline int vfprintf(std::wostream &os, wstring_view format_str,
wprintf_args args) {
wmemory_buffer buffer;
printf(buffer, format_str, args);
internal::write(os, buffer);
return static_cast<int>(buffer.size());
}
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fmt::fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
template <typename... Args>
inline int fprintf(std::ostream &os, string_view format_str,
const Args & ... args) {
auto vargs = make_format_args<
typename printf_context<internal::buffer>::type>(args...);
return vfprintf(os, format_str, vargs);
}
template <typename... Args>
inline int fprintf(std::wostream &os, wstring_view format_str,
const Args & ... args) {
auto vargs = make_format_args<
typename printf_context<internal::buffer>::type>(args...);
return vfprintf(os, format_str, vargs);
}
FMT_END_NAMESPACE
#endif // FMT_PRINTF_H_

305
include/fmt/ranges.h Normal file
View File

@@ -0,0 +1,305 @@
// Formatting library for C++ - the core API
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
//
// Copyright (c) 2018 - present, Remotion (Igor Schulz)
// All Rights Reserved
// {fmt} support for ranges, containers and types tuple interface.
#ifndef FMT_RANGES_H_
#define FMT_RANGES_H_
#include "format.h"
#include <type_traits>
// output only up to N items from the range.
#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT
# define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256
#endif
FMT_BEGIN_NAMESPACE
template <typename Char>
struct formatting_base {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
};
template <typename Char, typename Enable = void>
struct formatting_range : formatting_base<Char> {
static FMT_CONSTEXPR_DECL const std::size_t range_length_limit =
FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range.
Char prefix;
Char delimiter;
Char postfix;
formatting_range() : prefix('{'), delimiter(','), postfix('}') {}
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
};
template <typename Char, typename Enable = void>
struct formatting_tuple : formatting_base<Char> {
Char prefix;
Char delimiter;
Char postfix;
formatting_tuple() : prefix('('), delimiter(','), postfix(')') {}
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
};
namespace internal {
template <typename RangeT, typename OutputIterator>
void copy(const RangeT &range, OutputIterator out) {
for (auto it = range.begin(), end = range.end(); it != end; ++it)
*out++ = *it;
}
template <typename OutputIterator>
void copy(const char *str, OutputIterator out) {
const char *p_curr = str;
while (*p_curr) {
*out++ = *p_curr++;
}
}
template <typename OutputIterator>
void copy(char ch, OutputIterator out) {
*out++ = ch;
}
/// Return true value if T has std::string interface, like std::string_view.
template <typename T>
class is_like_std_string {
template <typename U>
static auto check(U *p) ->
decltype(p->find('a'), p->length(), p->data(), int());
template <typename>
static void check(...);
public:
static FMT_CONSTEXPR_DECL const bool value =
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
};
template <typename... Ts>
struct conditional_helper {};
template <typename T, typename _ = void>
struct is_range_ : std::false_type {};
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
template <typename T>
struct is_range_<T, typename std::conditional<
false,
conditional_helper<decltype(internal::declval<T>().begin()),
decltype(internal::declval<T>().end())>,
void>::type> : std::true_type {};
#endif
/// tuple_size and tuple_element check.
template <typename T>
class is_tuple_like_ {
template <typename U>
static auto check(U *p) ->
decltype(std::tuple_size<U>::value,
internal::declval<typename std::tuple_element<0, U>::type>(), int());
template <typename>
static void check(...);
public:
static FMT_CONSTEXPR_DECL const bool value =
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
};
// Check for integer_sequence
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
template <typename T, T... N>
using integer_sequence = std::integer_sequence<T, N...>;
template <std::size_t... N>
using index_sequence = std::index_sequence<N...>;
template <std::size_t N>
using make_index_sequence = std::make_index_sequence<N>;
#else
template <typename T, T... N>
struct integer_sequence {
typedef T value_type;
static FMT_CONSTEXPR std::size_t size() {
return sizeof...(N);
}
};
template <std::size_t... N>
using index_sequence = integer_sequence<std::size_t, N...>;
template <typename T, std::size_t N, T... Ns>
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
template <typename T, T... Ns>
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
template <std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
#endif
template <class Tuple, class F, size_t... Is>
void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT {
using std::get;
// using free function get<I>(T) now.
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
(void)_; // blocks warnings
}
template <class T>
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value>
get_indexes(T const &) { return {}; }
template <class Tuple, class F>
void for_each(Tuple &&tup, F &&f) {
const auto indexes = get_indexes(tup);
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
}
template<typename Arg>
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&,
typename std::enable_if<
!is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
return add_space ? " {}" : "{}";
}
template<typename Arg>
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&,
typename std::enable_if<
is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
return add_space ? " \"{}\"" : "\"{}\"";
}
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char*) {
return add_space ? " \"{}\"" : "\"{}\"";
}
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) {
return add_space ? L" \"{}\"" : L"\"{}\"";
}
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
return add_space ? " '{}'" : "'{}'";
}
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
return add_space ? L" '{}'" : L"'{}'";
}
} // namespace internal
template <typename T>
struct is_tuple_like {
static FMT_CONSTEXPR_DECL const bool value =
internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value;
};
template <typename TupleT, typename Char>
struct formatter<TupleT, Char,
typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> {
private:
// C++11 generic lambda for format()
template <typename FormatContext>
struct format_each {
template <typename T>
void operator()(const T& v) {
if (i > 0) {
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
internal::copy(formatting.delimiter, out);
}
format_to(out,
internal::format_str_quoted(
(formatting.add_delimiter_spaces && i > 0), v),
v);
++i;
}
formatting_tuple<Char>& formatting;
std::size_t& i;
typename std::add_lvalue_reference<decltype(std::declval<FormatContext>().out())>::type out;
};
public:
formatting_tuple<Char> formatting;
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return formatting.parse(ctx);
}
template <typename FormatContext = format_context>
auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) {
auto out = ctx.out();
std::size_t i = 0;
internal::copy(formatting.prefix, out);
internal::for_each(values, format_each<FormatContext>{formatting, i, out});
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
internal::copy(formatting.postfix, out);
return ctx.out();
}
};
template <typename T>
struct is_range {
static FMT_CONSTEXPR_DECL const bool value =
internal::is_range_<T>::value && !internal::is_like_std_string<T>::value;
};
template <typename RangeT, typename Char>
struct formatter<RangeT, Char,
typename std::enable_if<fmt::is_range<RangeT>::value>::type> {
formatting_range<Char> formatting;
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return formatting.parse(ctx);
}
template <typename FormatContext>
typename FormatContext::iterator format(
const RangeT &values, FormatContext &ctx) {
auto out = ctx.out();
internal::copy(formatting.prefix, out);
std::size_t i = 0;
for (auto it = values.begin(), end = values.end(); it != end; ++it) {
if (i > 0) {
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
internal::copy(formatting.delimiter, out);
}
format_to(out,
internal::format_str_quoted(
(formatting.add_delimiter_spaces && i > 0), *it),
*it);
if (++i > formatting.range_length_limit) {
format_to(out, " ... <other elements>");
break;
}
}
if (formatting.add_prepostfix_space) {
*out++ = ' ';
}
internal::copy(formatting.postfix, out);
return ctx.out();
}
};
FMT_END_NAMESPACE
#endif // FMT_RANGES_H_

152
include/fmt/time.h Normal file
View File

@@ -0,0 +1,152 @@
// Formatting library for C++ - time formatting
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_TIME_H_
#define FMT_TIME_H_
#include "format.h"
#include <ctime>
FMT_BEGIN_NAMESPACE
namespace internal{
inline null<> localtime_r(...) { return null<>(); }
inline null<> localtime_s(...) { return null<>(); }
inline null<> gmtime_r(...) { return null<>(); }
inline null<> gmtime_s(...) { return null<>(); }
}
// Thread-safe replacement for std::localtime
inline std::tm localtime(std::time_t time) {
struct dispatcher {
std::time_t time_;
std::tm tm_;
dispatcher(std::time_t t): time_(t) {}
bool run() {
using namespace fmt::internal;
return handle(localtime_r(&time_, &tm_));
}
bool handle(std::tm *tm) { return tm != FMT_NULL; }
bool handle(internal::null<>) {
using namespace fmt::internal;
return fallback(localtime_s(&tm_, &time_));
}
bool fallback(int res) { return res == 0; }
bool fallback(internal::null<>) {
using namespace fmt::internal;
std::tm *tm = std::localtime(&time_);
if (tm) tm_ = *tm;
return tm != FMT_NULL;
}
};
dispatcher lt(time);
if (lt.run())
return lt.tm_;
// Too big time values may be unsupported.
FMT_THROW(format_error("time_t value out of range"));
}
// Thread-safe replacement for std::gmtime
inline std::tm gmtime(std::time_t time) {
struct dispatcher {
std::time_t time_;
std::tm tm_;
dispatcher(std::time_t t): time_(t) {}
bool run() {
using namespace fmt::internal;
return handle(gmtime_r(&time_, &tm_));
}
bool handle(std::tm *tm) { return tm != FMT_NULL; }
bool handle(internal::null<>) {
using namespace fmt::internal;
return fallback(gmtime_s(&tm_, &time_));
}
bool fallback(int res) { return res == 0; }
bool fallback(internal::null<>) {
std::tm *tm = std::gmtime(&time_);
if (tm) tm_ = *tm;
return tm != FMT_NULL;
}
};
dispatcher gt(time);
if (gt.run())
return gt.tm_;
// Too big time values may be unsupported.
FMT_THROW(format_error("time_t value out of range"));
}
namespace internal {
inline std::size_t strftime(char *str, std::size_t count, const char *format,
const std::tm *time) {
return std::strftime(str, count, format, time);
}
inline std::size_t strftime(wchar_t *str, std::size_t count,
const wchar_t *format, const std::tm *time) {
return std::wcsftime(str, count, format, time);
}
}
template <typename Char>
struct formatter<std::tm, Char> {
template <typename ParseContext>
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
auto it = internal::null_terminating_iterator<Char>(ctx);
if (*it == ':')
++it;
auto end = it;
while (*end && *end != '}')
++end;
tm_format.reserve(end - it + 1);
using internal::pointer_from;
tm_format.append(pointer_from(it), pointer_from(end));
tm_format.push_back('\0');
return pointer_from(end);
}
template <typename FormatContext>
auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) {
internal::basic_buffer<Char> &buf = internal::get_container(ctx.out());
std::size_t start = buf.size();
for (;;) {
std::size_t size = buf.capacity() - start;
std::size_t count =
internal::strftime(&buf[start], size, &tm_format[0], &tm);
if (count != 0) {
buf.resize(start + count);
break;
}
if (size >= tm_format.size() * 256) {
// If the buffer is 256 times larger than the format string, assume
// that `strftime` gives an empty result. There doesn't seem to be a
// better way to distinguish the two cases:
// https://github.com/fmtlib/fmt/issues/367
break;
}
const std::size_t MIN_GROWTH = 10;
buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
}
return ctx.out();
}
basic_memory_buffer<Char> tm_format;
};
FMT_END_NAMESPACE
#endif // FMT_TIME_H_

52
src/format.cc Normal file
View File

@@ -0,0 +1,52 @@
// Formatting library for C++
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/format-inl.h"
FMT_BEGIN_NAMESPACE
namespace internal {
// Force linking of inline functions into the library.
std::string (*vformat_ref)(string_view, format_args) = vformat;
std::wstring (*vformat_wref)(wstring_view, wformat_args) = vformat;
}
template struct internal::basic_data<void>;
// Explicit instantiations for char.
template FMT_API char internal::thousands_sep(locale_provider *lp);
template void basic_fixed_buffer<char>::grow(std::size_t);
template void internal::arg_map<format_context>::init(
const basic_format_args<format_context> &args);
template FMT_API int internal::char_traits<char>::format_float(
char *buffer, std::size_t size, const char *format, int precision,
double value);
template FMT_API int internal::char_traits<char>::format_float(
char *buffer, std::size_t size, const char *format, int precision,
long double value);
// Explicit instantiations for wchar_t.
template FMT_API wchar_t internal::thousands_sep(locale_provider *lp);
template void basic_fixed_buffer<wchar_t>::grow(std::size_t);
template void internal::arg_map<wformat_context>::init(
const basic_format_args<wformat_context> &args);
template FMT_API int internal::char_traits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
int precision, double value);
template FMT_API int internal::char_traits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
int precision, long double value);
FMT_END_NAMESPACE

View File

@@ -1,18 +1,16 @@
/*
A C++ interface to POSIX functions.
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
// A C++ interface to POSIX functions.
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
// Disable bogus MSVC warnings.
#ifndef _CRT_SECURE_NO_WARNINGS
#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "posix.h"
#include "fmt/posix.h"
#include <limits.h>
#include <sys/types.h>
@@ -66,38 +64,40 @@ inline std::size_t convert_rwcount(std::size_t count) { return count; }
#endif
}
fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT {
FMT_BEGIN_NAMESPACE
buffered_file::~buffered_file() FMT_NOEXCEPT {
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
fmt::report_system_error(errno, "cannot close file");
report_system_error(errno, "cannot close file");
}
fmt::BufferedFile::BufferedFile(
fmt::CStringRef filename, fmt::CStringRef mode) {
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0);
buffered_file::buffered_file(cstring_view filename, cstring_view mode) {
FMT_RETRY_VAL(file_,
FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), FMT_NULL);
if (!file_)
FMT_THROW(SystemError(errno, "cannot open file {}", filename));
FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str()));
}
void fmt::BufferedFile::close() {
void buffered_file::close() {
if (!file_)
return;
int result = FMT_SYSTEM(fclose(file_));
file_ = FMT_NULL;
if (result != 0)
FMT_THROW(SystemError(errno, "cannot close file"));
FMT_THROW(system_error(errno, "cannot close file"));
}
// A macro used to prevent expansion of fileno on broken versions of MinGW.
#define FMT_ARGS
int fmt::BufferedFile::fileno() const {
int buffered_file::fileno() const {
int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
if (fd == -1)
FMT_THROW(SystemError(errno, "cannot get file descriptor"));
FMT_THROW(system_error(errno, "cannot get file descriptor"));
return fd;
}
fmt::File::File(fmt::CStringRef path, int oflag) {
file::file(cstring_view path, int oflag) {
int mode = S_IRUSR | S_IWUSR;
#if defined(_WIN32) && !defined(__MINGW32__)
fd_ = -1;
@@ -106,17 +106,17 @@ fmt::File::File(fmt::CStringRef path, int oflag) {
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
#endif
if (fd_ == -1)
FMT_THROW(SystemError(errno, "cannot open file {}", path));
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
}
fmt::File::~File() FMT_NOEXCEPT {
file::~file() FMT_NOEXCEPT {
// Don't retry close in case of EINTR!
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
fmt::report_system_error(errno, "cannot close file");
report_system_error(errno, "cannot close file");
}
void fmt::File::close() {
void file::close() {
if (fd_ == -1)
return;
// Don't retry close in case of EINTR!
@@ -124,10 +124,10 @@ void fmt::File::close() {
int result = FMT_POSIX_CALL(close(fd_));
fd_ = -1;
if (result != 0)
FMT_THROW(SystemError(errno, "cannot close file"));
FMT_THROW(system_error(errno, "cannot close file"));
}
fmt::LongLong fmt::File::size() const {
long long file::size() const {
#ifdef _WIN32
// Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
// is less than 0x0500 as is the case with some default MinGW builds.
@@ -138,63 +138,63 @@ fmt::LongLong fmt::File::size() const {
if (size_lower == INVALID_FILE_SIZE) {
DWORD error = GetLastError();
if (error != NO_ERROR)
FMT_THROW(WindowsError(GetLastError(), "cannot get file size"));
FMT_THROW(windows_error(GetLastError(), "cannot get file size"));
}
fmt::ULongLong long_size = size_upper;
unsigned long long long_size = size_upper;
return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
#else
typedef struct stat Stat;
Stat file_stat = Stat();
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
FMT_THROW(SystemError(errno, "cannot get file attributes"));
FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size),
"return type of File::size is not large enough");
FMT_THROW(system_error(errno, "cannot get file attributes"));
static_assert(sizeof(long long) >= sizeof(file_stat.st_size),
"return type of file::size is not large enough");
return file_stat.st_size;
#endif
}
std::size_t fmt::File::read(void *buffer, std::size_t count) {
std::size_t file::read(void *buffer, std::size_t count) {
RWResult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
if (result < 0)
FMT_THROW(SystemError(errno, "cannot read from file"));
FMT_THROW(system_error(errno, "cannot read from file"));
return internal::to_unsigned(result);
}
std::size_t fmt::File::write(const void *buffer, std::size_t count) {
std::size_t file::write(const void *buffer, std::size_t count) {
RWResult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
if (result < 0)
FMT_THROW(SystemError(errno, "cannot write to file"));
FMT_THROW(system_error(errno, "cannot write to file"));
return internal::to_unsigned(result);
}
fmt::File fmt::File::dup(int fd) {
file file::dup(int fd) {
// Don't retry as dup doesn't return EINTR.
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
int new_fd = FMT_POSIX_CALL(dup(fd));
if (new_fd == -1)
FMT_THROW(SystemError(errno, "cannot duplicate file descriptor {}", fd));
return File(new_fd);
FMT_THROW(system_error(errno, "cannot duplicate file descriptor {}", fd));
return file(new_fd);
}
void fmt::File::dup2(int fd) {
void file::dup2(int fd) {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) {
FMT_THROW(SystemError(errno,
FMT_THROW(system_error(errno,
"cannot duplicate file descriptor {} to {}", fd_, fd));
}
}
void fmt::File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT {
void file::dup2(int fd, error_code &ec) FMT_NOEXCEPT {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1)
ec = ErrorCode(errno);
ec = error_code(errno);
}
void fmt::File::pipe(File &read_end, File &write_end) {
void file::pipe(file &read_end, file &write_end) {
// Close the descriptors first to make sure that assignments don't throw
// and there are no leaks.
read_end.close();
@@ -210,24 +210,25 @@ void fmt::File::pipe(File &read_end, File &write_end) {
int result = FMT_POSIX_CALL(pipe(fds));
#endif
if (result != 0)
FMT_THROW(SystemError(errno, "cannot create pipe"));
FMT_THROW(system_error(errno, "cannot create pipe"));
// The following assignments don't throw because read_fd and write_fd
// are closed.
read_end = File(fds[0]);
write_end = File(fds[1]);
read_end = file(fds[0]);
write_end = file(fds[1]);
}
fmt::BufferedFile fmt::File::fdopen(const char *mode) {
buffered_file file::fdopen(const char *mode) {
// Don't retry as fdopen doesn't return EINTR.
FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode));
if (!f)
FMT_THROW(SystemError(errno, "cannot associate stream with file descriptor"));
BufferedFile file(f);
FMT_THROW(system_error(errno,
"cannot associate stream with file descriptor"));
buffered_file bf(f);
fd_ = -1;
return file;
return bf;
}
long fmt::getpagesize() {
long getpagesize() {
#ifdef _WIN32
SYSTEM_INFO si;
GetSystemInfo(&si);
@@ -235,7 +236,9 @@ long fmt::getpagesize() {
#else
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
if (size < 0)
FMT_THROW(SystemError(errno, "cannot get memory page size"));
FMT_THROW(system_error(errno, "cannot get memory page size"));
return size;
#endif
}
FMT_END_NAMESPACE

View File

@@ -4,7 +4,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := fmt_static
LOCAL_MODULE_FILENAME := libfmt
LOCAL_SRC_FILES := fmt/format.cc
LOCAL_SRC_FILES := ../src/format.cc
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)

View File

@@ -0,0 +1 @@
<manifest package="fmt" />

View File

@@ -2,3 +2,5 @@ This directory contains build support files such as
* CMake modules
* Build scripts
* qmake (static build with dynamic libc only)

15
support/appveyor-build.py Executable file → Normal file
View File

@@ -6,9 +6,11 @@ from subprocess import check_call
build = os.environ['BUILD']
config = os.environ['CONFIGURATION']
platform = os.environ.get('PLATFORM')
platform = os.environ['PLATFORM']
path = os.environ['PATH']
cmake_command = ['cmake', '-DFMT_PEDANTIC=ON', '-DCMAKE_BUILD_TYPE=' + config]
image = os.environ['APPVEYOR_BUILD_WORKER_IMAGE']
jobid = os.environ['APPVEYOR_JOB_ID']
cmake_command = ['cmake', '-DFMT_PEDANTIC=ON', '-DCMAKE_BUILD_TYPE=' + config, '..']
if build == 'mingw':
cmake_command.append('-GMinGW Makefiles')
build_command = ['mingw32-make', '-j4']
@@ -20,8 +22,13 @@ if build == 'mingw':
else:
# Add MSBuild 14.0 to PATH as described in
# http://help.appveyor.com/discussions/problems/2229-v140-not-found-on-vs2105rc.
os.environ['PATH'] = r'C:\Program Files (x86)\MSBuild\14.0\Bin;' + path
generator = 'Visual Studio 14 2015'
os.environ['PATH'] = r'C:\Program Files (x86)\MSBuild\15.0\Bin;' + path
if image == 'Visual Studio 2013':
generator = 'Visual Studio 12 2013'
elif image == 'Visual Studio 2015':
generator = 'Visual Studio 14 2015'
elif image == 'Visual Studio 2017':
generator = 'Visual Studio 15 2017'
if platform == 'x64':
generator += ' Win64'
cmake_command.append('-G' + generator)

View File

@@ -2,20 +2,28 @@ configuration:
- Debug
- Release
clone_depth: 1
platform:
- Win32
- x64
image:
- Visual Studio 2013
- Visual Studio 2015
- Visual Studio 2017
environment:
CTEST_OUTPUT_ON_FAILURE: 1
matrix:
- BUILD: msvc
- BUILD: msvc
PLATFORM: x64
- BUILD: mingw
MSVC_DEFAULT_OPTIONS: ON
BUILD: msvc
before_build:
# Workaround for CMake not wanting sh.exe on PATH for MinGW.
- set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
- mkdir build
- cd build
build_script:
- python support/appveyor-build.py
- python ../support/appveyor-build.py
on_failure:
- appveyor PushArtifact Testing/Temporary/LastTest.log

98
support/build.gradle Normal file
View File

@@ -0,0 +1,98 @@
// General gradle arguments for root project
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
}
}
// Output: Shared library (.so) for Android
apply plugin: 'com.android.library'
android {
compileSdkVersion 25 // Android 7.0
// Target ABI
// - This option controls target platform of module
// - The platform might be limited by compiler's support
// some can work with Clang(default), but some can work only with GCC...
// if bad, both toolchains might not support it
splits {
abi {
enable true
// Be general, as much as possible ...
// universalApk true
// Specify platforms for Application
reset()
include "x86", "x86_64", "armeabi-v7a", "arm64-v8a"
}
}
defaultConfig {
minSdkVersion 21 // Android 5.0+
targetSdkVersion 25 // Follow Compile SDK
versionCode 16 // Follow release count
versionName "4.1.0" // Follow Official version
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_shared" // Specify Android STL
arguments "-DBUILD_SHARED_LIBS=true" // Build shared object
arguments "-DFMT_TEST=false" // Skip test
arguments "-DFMT_DOC=false" // Skip document
cppFlags "-std=c++14"
}
}
println("Gradle CMake Plugin: ")
println(externalNativeBuild.cmake.cppFlags)
println(externalNativeBuild.cmake.arguments)
}
// External Native build
// - Use existing CMakeList.txt
// - Give path to CMake. This gradle file should be
// neighbor of the top level cmake
externalNativeBuild {
cmake {
path "../CMakeLists.txt"
// buildStagingDirectory "./build" // Custom path for cmake output
}
//println(cmake.path)
}
sourceSets{
// Android Manifest for Gradle
main {
manifest.srcFile 'AndroidManifest.xml'
}
}
}
assemble.doLast
{
// Instead of `ninja install`, Gradle will deploy the files.
// We are doing this since FMT is dependent to the ANDROID_STL after build
copy {
from 'build/intermediates/cmake'
into '../libs'
}
// Copy debug binaries
copy {
from '../libs/debug/obj'
into '../libs/debug'
}
// Copy Release binaries
copy {
from '../libs/release/obj'
into '../libs/release'
}
// Remove empty directory
delete '../libs/debug/obj'
delete '../libs/release/obj'
}

View File

@@ -1,85 +0,0 @@
# C++11 feature support detection
if (NOT FMT_USE_CPP11)
return()
endif ()
include(CheckCXXCompilerFlag)
if (FMT_USE_CPP11)
check_cxx_compiler_flag(-std=c++11 HAVE_STD_CPP11_FLAG)
if (HAVE_STD_CPP11_FLAG)
# Check if including cmath works with -std=c++11 and -O3.
# It may not in MinGW due to bug http://ehc.ac/p/mingw/bugs/2250/.
set(CMAKE_REQUIRED_FLAGS "-std=c++11 -O3")
check_cxx_source_compiles("
#include <cmath>
int main() {}" FMT_CPP11_CMATH)
# Check if including <unistd.h> works with -std=c++11.
# It may not in MinGW due to bug http://sourceforge.net/p/mingw/bugs/2024/.
check_cxx_source_compiles("
#include <unistd.h>
int main() {}" FMT_CPP11_UNISTD_H)
# Check if snprintf works with -std=c++11. It may not in MinGW.
check_cxx_source_compiles("
#include <stdio.h>
int main() {
char buffer[10];
snprintf(buffer, 10, \"foo\");
}" FMT_CPP11_SNPRINTF)
if (FMT_CPP11_CMATH AND FMT_CPP11_UNISTD_H AND FMT_CPP11_SNPRINTF)
set(CPP11_FLAG -std=c++11)
else ()
check_cxx_compiler_flag(-std=gnu++11 HAVE_STD_GNUPP11_FLAG)
if (HAVE_STD_CPP11_FLAG)
set(CPP11_FLAG -std=gnu++11)
endif ()
endif ()
set(CMAKE_REQUIRED_FLAGS )
else ()
check_cxx_compiler_flag(-std=c++0x HAVE_STD_CPP0X_FLAG)
if (HAVE_STD_CPP0X_FLAG)
set(CPP11_FLAG -std=c++0x)
endif ()
endif ()
endif ()
if (CMAKE_CXX_STANDARD)
# Don't use -std compiler flag if CMAKE_CXX_STANDARD is specified.
set(CPP11_FLAG )
endif ()
set(CMAKE_REQUIRED_FLAGS ${CPP11_FLAG})
# Check if variadic templates are working and not affected by GCC bug 39653:
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39653
check_cxx_source_compiles("
template <class T, class ...Types>
struct S { typedef typename S<Types...>::type type; };
int main() {}" SUPPORTS_VARIADIC_TEMPLATES)
# Check if initializer lists are supported.
check_cxx_source_compiles("
#include <initializer_list>
int main() {}" SUPPORTS_INITIALIZER_LIST)
# Check if enum bases are available
check_cxx_source_compiles("
enum C : char {A};
int main() {}"
SUPPORTS_ENUM_BASE)
# Check if type traits are available
check_cxx_source_compiles("
#include <type_traits>
class C { void operator=(const C&); };
int main() { static_assert(!std::is_copy_assignable<C>::value, \"\"); }"
SUPPORTS_TYPE_TRAITS)
# Check if user-defined literals are available
check_cxx_source_compiles("
void operator\"\" _udl(long double);
int main() {}"
SUPPORTS_USER_DEFINED_LITERALS)
set(CMAKE_REQUIRED_FLAGS )

97
support/cmake/cxx14.cmake Normal file
View File

@@ -0,0 +1,97 @@
# C++14 feature support detection
include(CheckCXXSourceCompiles)
include(CheckCXXCompilerFlag)
if (NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
endif()
message(STATUS "CXX_STANDARD: ${CMAKE_CXX_STANDARD}")
if (CMAKE_CXX_STANDARD EQUAL 20)
check_cxx_compiler_flag(-std=c++20 has_std_20_flag)
check_cxx_compiler_flag(-std=c++2a has_std_2a_flag)
if (has_std_20_flag)
set(CXX_STANDARD_FLAG -std=c++20)
elseif (has_std_2a_flag)
set(CXX_STANDARD_FLAG -std=c++2a)
endif ()
elseif (CMAKE_CXX_STANDARD EQUAL 17)
check_cxx_compiler_flag(-std=c++17 has_std_17_flag)
check_cxx_compiler_flag(-std=c++1z has_std_1z_flag)
if (has_std_17_flag)
set(CXX_STANDARD_FLAG -std=c++17)
elseif (has_std_1z_flag)
set(CXX_STANDARD_FLAG -std=c++1z)
endif ()
elseif (CMAKE_CXX_STANDARD EQUAL 14)
check_cxx_compiler_flag(-std=c++14 has_std_14_flag)
check_cxx_compiler_flag(-std=c++1y has_std_1y_flag)
if (has_std_14_flag)
set(CXX_STANDARD_FLAG -std=c++14)
elseif (has_std_1y_flag)
set(CXX_STANDARD_FLAG -std=c++1y)
endif ()
elseif (CMAKE_CXX_STANDARD EQUAL 11)
check_cxx_compiler_flag(-std=c++11 has_std_11_flag)
check_cxx_compiler_flag(-std=c++0x has_std_0x_flag)
if (has_std_11_flag)
set(CXX_STANDARD_FLAG -std=c++11)
elseif (has_std_0x_flag)
set(CXX_STANDARD_FLAG -std=c++0x)
endif ()
endif ()
set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG})
# Check if variadic templates are working and not affected by GCC bug 39653:
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39653
check_cxx_source_compiles("
template <class T, class ...Types>
struct S { typedef typename S<Types...>::type type; };
int main() {}" SUPPORTS_VARIADIC_TEMPLATES)
if (NOT SUPPORTS_VARIADIC_TEMPLATES)
set (SUPPORTS_VARIADIC_TEMPLATES OFF)
endif ()
# Check if initializer lists are supported.
check_cxx_source_compiles("
#include <initializer_list>
int main() {}" SUPPORTS_INITIALIZER_LIST)
if (NOT SUPPORTS_INITIALIZER_LIST)
set (SUPPORTS_INITIALIZER_LIST OFF)
endif ()
# Check if enum bases are available
check_cxx_source_compiles("
enum C : char {A};
int main() {}"
SUPPORTS_ENUM_BASE)
if (NOT SUPPORTS_ENUM_BASE)
set (SUPPORTS_ENUM_BASE OFF)
endif ()
# Check if type traits are available
check_cxx_source_compiles("
#include <type_traits>
class C { void operator=(const C&); };
int main() { static_assert(!std::is_copy_assignable<C>::value, \"\"); }"
SUPPORTS_TYPE_TRAITS)
if (NOT SUPPORTS_TYPE_TRAITS)
set (SUPPORTS_TYPE_TRAITS OFF)
endif ()
# Check if user-defined literals are available
check_cxx_source_compiles("
void operator\"\" _udl(long double);
int main() {}"
SUPPORTS_USER_DEFINED_LITERALS)
if (NOT SUPPORTS_USER_DEFINED_LITERALS)
set (SUPPORTS_USER_DEFINED_LITERALS OFF)
endif ()
set(CMAKE_REQUIRED_FLAGS )

53
support/compute-powers.py Executable file
View File

@@ -0,0 +1,53 @@
#!/usr/bin/env python
# Compute 10 ** exp with exp in the range [min_exponent, max_exponent] and print
# normalized (with most-significant bit equal to 1) significands in hexadecimal.
from __future__ import print_function
min_exponent = -348
max_exponent = 340
step = 8
significand_size = 64
exp_offset = 2000
class fp:
pass
powers = []
for i, exp in enumerate(range(min_exponent, max_exponent + 1, step)):
result = fp()
n = 10 ** exp if exp >= 0 else 2 ** exp_offset / 10 ** -exp
k = significand_size + 1
# Convert to binary and round.
binary = '{:b}'.format(n)
result.f = (int('{:0<{}}'.format(binary[:k], k), 2) + 1) / 2
result.e = len(binary) - (exp_offset if exp < 0 else 0) - significand_size
powers.append(result)
# Sanity check.
exp_offset10 = 400
actual = result.f * 10 ** exp_offset10
if result.e > 0:
actual *= 2 ** result.e
else:
for j in range(-result.e):
actual /= 2
expected = 10 ** (exp_offset10 + exp)
precision = len('{}'.format(expected)) - len('{}'.format(actual - expected))
if precision < 19:
print('low precision:', precision)
exit(1)
print('Significands:', end='')
for i, fp in enumerate(powers):
if i % 4 == 0:
print(end='\n ')
print(' {:0<#16x}'.format(fp.f, ), end=',')
print('\n\nExponents:', end='')
for i, fp in enumerate(powers):
if i % 11 == 0:
print(end='\n ')
print(' {:5}'.format(fp.e), end=',')
print('\n\nMax exponent difference:',
max([x.e - powers[i - 1].e for i, x in enumerate(powers)][1:]))

27
support/fmt.pro Normal file
View File

@@ -0,0 +1,27 @@
# Staticlib configuration for qmake builds
# For some reason qmake 3.1 fails to identify source dependencies and excludes format.cc and printf.cc
# from compilation so it _MUST_ be called as qmake -nodepend
# A workaround is implemented below: a custom compiler is defined which does not track dependencies
TEMPLATE = lib
TARGET = fmt
QMAKE_EXT_CPP = .cc
CONFIG = staticlib warn_on c++11
FMT_SOURCES = \
../src/format.cc \
../src/posix.cc
fmt.name = libfmt
fmt.input = FMT_SOURCES
fmt.output = ${QMAKE_FILE_BASE}$$QMAKE_EXT_OBJ
fmt.clean = ${QMAKE_FILE_BASE}$$QMAKE_EXT_OBJ
fmt.depends = ${QMAKE_FILE_IN}
# QMAKE_RUN_CXX will not be expanded
fmt.commands = $$QMAKE_CXX -c $$QMAKE_CXXFLAGS $$QMAKE_CXXFLAGS_WARN_ON $$QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO $$QMAKE_CXXFLAGS_CXX11 ${QMAKE_FILE_IN}
fmt.variable_out = OBJECTS
fmt.CONFIG = no_dependencies no_link
QMAKE_EXTRA_COMPILERS += fmt

View File

@@ -141,6 +141,7 @@ def update_site(env):
b.data = re.sub(pattern, r'doxygenfunction:: \1(int)', b.data)
b.data = b.data.replace('std::FILE*', 'std::FILE *')
b.data = b.data.replace('unsigned int', 'unsigned')
b.data = b.data.replace('operator""_', 'operator"" _')
# Fix a broken link in index.rst.
index = os.path.join(target_doc_dir, 'index.rst')
with rewrite(index) as b:
@@ -151,7 +152,9 @@ def update_site(env):
if os.path.exists(html_dir):
shutil.rmtree(html_dir)
include_dir = env.fmt_repo.dir
if LooseVersion(version) >= LooseVersion('3.0.0'):
if LooseVersion(version) >= LooseVersion('5.0.0'):
include_dir = os.path.join(include_dir, 'include', 'fmt')
elif LooseVersion(version) >= LooseVersion('3.0.0'):
include_dir = os.path.join(include_dir, 'fmt')
import build
build.build_docs(version, doc_dir=target_doc_dir,
@@ -242,12 +245,11 @@ def release(args):
id = r.json()['id']
uploads_url = 'https://uploads.github.com/repos/fmtlib/fmt/releases'
package = 'fmt-{}.zip'.format(version)
with open('build/fmt/' + package, 'rb') as f:
r = requests.post(
'{}/{}/assets?name={}'.format(uploads_url, id, package),
params=params, files={package: f})
if r.status_code != 201:
raise Exception('Failed to upload an asset ' + str(r))
r = requests.post(
'{}/{}/assets?name={}'.format(uploads_url, id, package),
params=params, files={package: open('build/fmt/' + package, 'rb')})
if r.status_code != 201:
raise Exception('Failed to upload an asset ' + str(r))
if __name__ == '__main__':

View File

@@ -2,8 +2,8 @@
# Build the project on Travis CI.
from __future__ import print_function
import errno, os, re, shutil, sys, tempfile, urllib
from subprocess import call, check_call, check_output, Popen, PIPE, STDOUT
import errno, os, shutil, subprocess, sys, urllib
from subprocess import call, check_call, Popen, PIPE, STDOUT
def rmtree_if_exists(dir):
try:
@@ -75,7 +75,7 @@ if build == 'Doc':
# Print the output without the key.
print(p.communicate()[0].replace(os.environ['KEY'], '$KEY'))
if p.returncode != 0:
raise CalledProcessError(p.returncode, cmd)
raise subprocess.CalledProcessError(p.returncode, cmd)
exit(0)
standard = os.environ['STANDARD']
@@ -85,16 +85,12 @@ test_build_dir = os.path.join(fmt_dir, "_build_test")
# Configure library.
makedirs_if_not_exist(build_dir)
common_cmake_flags = [
'-DCMAKE_INSTALL_PREFIX=' + install_dir, '-DCMAKE_BUILD_TYPE=' + build
cmake_flags = [
'-DCMAKE_INSTALL_PREFIX=' + install_dir, '-DCMAKE_BUILD_TYPE=' + build,
'-DCMAKE_CXX_STANDARD=' + standard
]
extra_cmake_flags = []
if standard != '0x':
extra_cmake_flags = [
'-DCMAKE_CXX_FLAGS=-std=c++' + standard, '-DFMT_USE_CPP11=OFF'
]
check_call(['cmake', '-DFMT_DOC=OFF', '-DFMT_PEDANTIC=ON', fmt_dir] +
common_cmake_flags + extra_cmake_flags, cwd=build_dir)
check_call(['cmake', '-DFMT_DOC=OFF', '-DFMT_PEDANTIC=ON', '-DFMT_WERROR=ON', fmt_dir] +
cmake_flags, cwd=build_dir)
# Build library.
check_call(['make', '-j4'], cwd=build_dir)
@@ -103,7 +99,7 @@ check_call(['make', '-j4'], cwd=build_dir)
env = os.environ.copy()
env['CTEST_OUTPUT_ON_FAILURE'] = '1'
if call(['make', 'test'], env=env, cwd=build_dir):
with open('Testing/Temporary/LastTest.log', 'r') as f:
with open(os.path.join(build_dir, 'Testing', 'Temporary', 'LastTest.log'), 'r') as f:
print(f.read())
sys.exit(-1)
@@ -112,7 +108,6 @@ check_call(['make', 'install'], cwd=build_dir)
# Test installation.
makedirs_if_not_exist(test_build_dir)
check_call(['cmake', '-DCMAKE_CXX_FLAGS=-std=c++' + standard,
os.path.join(fmt_dir, "test", "find-package-test")] +
common_cmake_flags, cwd=test_build_dir)
check_call(['cmake', os.path.join(fmt_dir, "test", "find-package-test")] +
cmake_flags, cwd=test_build_dir)
check_call(['make', '-j4'], cwd=test_build_dir)

View File

@@ -7,9 +7,8 @@
# at http://code.google.com/p/googletest/wiki/FAQ for more details.
add_library(gmock STATIC
gmock-gtest-all.cc gmock/gmock.h gtest/gtest.h gtest/gtest-spi.h)
target_compile_options(gmock PUBLIC ${CPP11_FLAG})
target_compile_definitions(gmock PUBLIC GTEST_HAS_STD_WSTRING=1)
target_include_directories(gmock PUBLIC .)
target_include_directories(gmock SYSTEM PUBLIC . gmock gtest)
find_package(Threads)
if (Threads_FOUND)
@@ -32,6 +31,10 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_definitions(gmock PUBLIC GTEST_USE_OWN_TR1_TUPLE=1)
endif ()
# Silence MSVC tr1 deprecation warning in gmock.
target_compile_definitions(gmock
PUBLIC _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=0)
#------------------------------------------------------------------------------
# Build the actual library tests
@@ -39,6 +42,7 @@ set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc)
add_library(test-main STATIC ${TEST_MAIN_SRC})
target_compile_definitions(test-main PUBLIC
FMT_USE_FILE_DESCRIPTORS=$<BOOL:${HAVE_OPEN}>)
target_include_directories(test-main SYSTEM PUBLIC gtest gmock)
target_link_libraries(test-main gmock fmt)
include(CheckCXXCompilerFlag)
@@ -53,7 +57,7 @@ endif ()
# Use less strict pedantic flags for the tests because GMock doesn't compile
# cleanly with -pedantic and -std=c++98.
if (CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wno-long-long -Wno-variadic-macros)
#set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wno-long-long -Wno-variadic-macros)
endif ()
function(add_fmt_executable name)
@@ -69,41 +73,39 @@ function(add_fmt_test name)
add_fmt_executable(${name} ${name}.cc ${ARGN})
target_link_libraries(${name} test-main)
# define if certain c++ features can be used
# Define if certain C++ features can be used.
target_compile_definitions(${name} PRIVATE
FMT_USE_TYPE_TRAITS=$<BOOL:${SUPPORTS_TYPE_TRAITS}>
FMT_USE_ENUM_BASE=$<BOOL:${SUPPORTS_ENUM_BASE}>)
if (FMT_PEDANTIC)
target_compile_options(${name} PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
target_include_directories(${name} SYSTEM PUBLIC gtest gmock)
add_test(NAME ${name} COMMAND ${name})
endfunction()
add_fmt_test(assert-test)
add_fmt_test(container-test)
add_fmt_test(gtest-extra-test)
add_fmt_test(format-test)
add_fmt_test(format-impl-test)
add_fmt_test(ostream-test)
add_fmt_test(printf-test)
add_fmt_test(string-test)
add_fmt_test(time-test)
add_fmt_test(util-test mock-allocator.h)
add_fmt_test(macro-test)
add_fmt_test(custom-formatter-test)
# Enable stricter options for one test to make sure that the header is free of
# warnings.
if (FMT_PEDANTIC AND MSVC)
target_compile_options(format-test PRIVATE /W4)
endif ()
add_fmt_test(ranges-test)
if (HAVE_OPEN)
add_fmt_executable(posix-mock-test
posix-mock-test.cc ../fmt/format.cc ../fmt/printf.cc ${TEST_MAIN_SRC})
target_include_directories(posix-mock-test PRIVATE ${PROJECT_SOURCE_DIR})
posix-mock-test.cc ../src/format.cc ${TEST_MAIN_SRC})
target_include_directories(
posix-mock-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_definitions(posix-mock-test PRIVATE FMT_USE_FILE_DESCRIPTORS=1)
target_link_libraries(posix-mock-test gmock)
target_include_directories(posix-mock-test SYSTEM PUBLIC gtest gmock)
if (FMT_PEDANTIC)
target_compile_options(posix-mock-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
add_test(NAME posix-mock-test COMMAND posix-mock-test)
add_fmt_test(posix-test)
endif ()
@@ -111,27 +113,41 @@ endif ()
add_fmt_executable(header-only-test
header-only-test.cc header-only-test2.cc test-main.cc)
target_link_libraries(header-only-test gmock)
target_include_directories(header-only-test SYSTEM PUBLIC gtest gmock)
if (TARGET fmt-header-only)
target_link_libraries(header-only-test fmt-header-only)
else ()
target_include_directories(header-only-test PRIVATE ${PROJECT_SOURCE_DIR})
target_include_directories(
header-only-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_definitions(header-only-test PRIVATE FMT_HEADER_ONLY=1)
endif ()
# Test that the library can be compiled with exceptions disabled.
check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG)
if (HAVE_FNO_EXCEPTIONS_FLAG)
add_library(noexception-test ../fmt/format.cc)
target_include_directories(noexception-test PRIVATE ${PROJECT_SOURCE_DIR})
add_library(noexception-test ../src/format.cc)
target_include_directories(
noexception-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_options(noexception-test PRIVATE -fno-exceptions)
if (FMT_PEDANTIC)
target_compile_options(noexception-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
target_include_directories(noexception-test SYSTEM PUBLIC gtest gmock)
endif ()
message(STATUS "FMT_PEDANTIC: ${FMT_PEDANTIC}")
if (FMT_PEDANTIC)
# Test that the library compiles without windows.h.
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_library(no-windows-h-test ../fmt/format.cc)
target_include_directories(no-windows-h-test PRIVATE ${PROJECT_SOURCE_DIR})
add_library(no-windows-h-test ../src/format.cc)
target_include_directories(
no-windows-h-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_definitions(no-windows-h-test PRIVATE FMT_USE_WINDOWS_H=0)
if (FMT_PEDANTIC)
target_compile_options(no-windows-h-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
target_include_directories(no-windows-h-test SYSTEM PUBLIC gtest gmock)
endif ()
add_test(compile-test ${CMAKE_CTEST_COMMAND}
@@ -142,7 +158,9 @@ if (FMT_PEDANTIC)
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCPP11_FLAG=${CPP11_FLAG}"
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DCXX_STANDARD_FLAG=${CXX_STANDARD_FLAG}"
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
"-DSUPPORTS_USER_DEFINED_LITERALS=${SUPPORTS_USER_DEFINED_LITERALS}")
# test if the targets are findable from the build directory
@@ -155,7 +173,9 @@ if (FMT_PEDANTIC)
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DFMT_DIR=${PROJECT_BINARY_DIR}"
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
# test if the targets are findable when add_subdirectory is used
@@ -168,5 +188,7 @@ if (FMT_PEDANTIC)
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
endif ()

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 2.8.12)
cmake_minimum_required(VERSION 3.1.0)
project(fmt-test)
@@ -6,8 +6,12 @@ add_subdirectory(../.. fmt)
add_executable(library-test "main.cc")
target_link_libraries(library-test fmt::fmt)
target_compile_options(library-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
target_include_directories(library-test PUBLIC SYSTEM .)
if (TARGET fmt::fmt-header-only)
add_executable(header-only-test "main.cc")
target_link_libraries(header-only-test fmt::fmt-header-only)
target_compile_options(header-only-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
target_include_directories(header-only-test PUBLIC SYSTEM .)
endif ()

View File

@@ -1,32 +1,12 @@
/*
Assertion tests
// Formatting library for C++ - assertion tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
Copyright (c) 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fmt/format.h"
#include "gtest/gtest.h"
#include "fmt/core.h"
#include "gtest.h"
#if GTEST_HAS_DEATH_TEST
# define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \
@@ -37,5 +17,6 @@
#endif
TEST(AssertTest, Fail) {
EXPECT_DEBUG_DEATH_IF_SUPPORTED(FMT_ASSERT(false, "don't panic!"), "don't panic!");
EXPECT_DEBUG_DEATH_IF_SUPPORTED(
FMT_ASSERT(false, "don't panic!"), "don't panic!");
}

View File

@@ -1,15 +1,17 @@
# Test if compile errors are produced where necessary.
cmake_minimum_required(VERSION 2.8)
cmake_minimum_required(VERSION 3.1.0)
include(CheckCXXSourceCompiles)
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/../..)
set(CMAKE_REQUIRED_FLAGS ${CPP11_FLAG})
include(CheckCXXCompilerFlag)
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG} ${PEDANTIC_COMPILE_FLAGS})
function (generate_source result fragment)
set(${result} "
#define FMT_HEADER_ONLY 1
#include \"fmt/posix.h\"
#include \"fmt/format.h\"
int main() {
${fragment}
}
@@ -47,24 +49,23 @@ endfunction ()
# check if the source file skeleton compiles
expect_compile("")
# MakeArg doesn't accept [const] volatile char *.
expect_compile_error("volatile char s[] = \"test\"; (fmt::internal::MakeArg<char>)(s);")
expect_compile_error("const volatile char s[] = \"test\"; (fmt::internal::MakeArg<char>)(s);")
# MakeArg<char> doesn't accept wchar_t.
expect_compile_error("fmt::internal::MakeValue<char>(L'a');")
expect_compile_error("fmt::internal::MakeValue<char>(L\"test\");")
# Writing a wide character to a character stream Writer is forbidden.
expect_compile_error("fmt::MemoryWriter() << L'a';")
expect_compile_error("fmt::MemoryWriter() << fmt::pad(\"abc\", 5, L' ');")
expect_compile_error("fmt::MemoryWriter() << fmt::pad(42, 5, L' ');")
# Formatting a wide character with a narrow format string is forbidden.
expect_compile_error("fmt::format(\"{}\", L'a';")
expect_compile_error("fmt::format(\"{}\", L'a');")
expect_compile("FMT_STATIC_ASSERT(true, \"this should never happen\");")
expect_compile_error("FMT_STATIC_ASSERT(0 > 1, \"oops\");")
# Formatting a wide string with a narrow format string is forbidden.
expect_compile_error("fmt::format(\"{}\", L\"foo\");")
# Formatting a narrow string with a wide format string is forbidden because
# mixing UTF-8 with UTF-16/32 can result in an invalid output.
expect_compile_error("fmt::format(L\"{}\", \"foo\");")
# Formatting a wide string with a narrow format string is forbidden.
expect_compile_error("
struct S {
operator std::string() const { return std::string(); }
};
fmt::format(\"{}\", S());
")
# Make sure that compiler features detected in the header
# match the features detected in CMake.

View File

@@ -1,94 +0,0 @@
/*
Tests of container utilities
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#include "fmt/container.h"
#include "gtest/gtest.h"
using fmt::internal::ContainerBuffer;
TEST(ContainerBufferTest, Empty) {
std::string data;
ContainerBuffer<std::string> buffer(data);
EXPECT_EQ(0u, buffer.size());
EXPECT_EQ(0u, buffer.capacity());
}
TEST(ContainerBufferTest, Reserve) {
std::string data;
ContainerBuffer<std::string> buffer(data);
std::size_t capacity = std::string().capacity() + 10;
buffer.reserve(capacity);
EXPECT_EQ(0u, buffer.size());
EXPECT_EQ(capacity, buffer.capacity());
}
TEST(ContainerBufferTest, Resize) {
std::string data;
ContainerBuffer<std::string> buffer(data);
std::size_t size = std::string().capacity() + 10;
buffer.resize(size);
EXPECT_EQ(size, buffer.size());
EXPECT_EQ(size, buffer.capacity());
}
TEST(ContainerBufferTest, Append) {
std::string data("Why so");
const std::string serious(" serious");
ContainerBuffer<std::string> buffer(data);
buffer.append(serious.c_str(), serious.c_str() + serious.length());
EXPECT_EQ("Why so serious", data);
EXPECT_EQ(data.length(), buffer.size());
}
TEST(BasicContainerWriterTest, String) {
std::string data;
fmt::BasicContainerWriter<std::string> out(data);
out << "The answer is " << 42 << "\n";
EXPECT_EQ("The answer is 42\n", data);
EXPECT_EQ(17u, out.size());
}
TEST(BasicContainerWriterTest, WString) {
std::wstring data;
fmt::BasicContainerWriter<std::wstring> out(data);
out << "The answer is " << 42 << "\n";
EXPECT_EQ(L"The answer is 42\n", data);
EXPECT_EQ(17u, out.size());
}
TEST(BasicContainerWriterTest, Vector) {
std::vector<char> data;
fmt::BasicContainerWriter<std::vector<char> > out(data);
out << "The answer is " << 42 << "\n";
EXPECT_EQ(17u, data.size());
EXPECT_EQ(out.size(), data.size());
}
TEST(BasicContainerWriterTest, StringAppend) {
std::string data("The");
fmt::BasicContainerWriter<std::string> out(data);
EXPECT_EQ(3u, data.size());
EXPECT_EQ(3u, out.size());
out << " answer is " << 42 << "\n";
EXPECT_EQ("The answer is 42\n", data);
EXPECT_EQ(17u, out.size());
}
TEST(BasicContainerWriterTest, VectorAppend) {
std::vector<char> data;
data.push_back('T');
data.push_back('h');
data.push_back('e');
fmt::BasicContainerWriter<std::vector<char> > out(data);
EXPECT_EQ(3u, data.size());
EXPECT_EQ(3u, out.size());
out << " answer is " << 42 << "\n";
EXPECT_EQ(17u, data.size());
EXPECT_EQ(17u, out.size());
}

View File

@@ -1,68 +1,51 @@
/*
Custom argument formatter tests
// Formatting library for C++ - custom argument formatter tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
Copyright (c) 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#include "fmt/printf.h"
#include "fmt/format.h"
#include "gtest-extra.h"
using fmt::BasicPrintfArgFormatter;
// MSVC 2013 is known to be broken.
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
// A custom argument formatter that doesn't print `-` for floating-point values
// rounded to 0.
class CustomArgFormatter
: public fmt::BasicArgFormatter<CustomArgFormatter, char> {
class custom_arg_formatter :
public fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>> {
public:
CustomArgFormatter(fmt::BasicFormatter<char, CustomArgFormatter> &f,
fmt::FormatSpec &s, const char *fmt)
: fmt::BasicArgFormatter<CustomArgFormatter, char>(f, s, fmt) {}
typedef fmt::back_insert_range<fmt::internal::buffer> range;
typedef fmt::arg_formatter<range> base;
void visit_double(double value) {
if (round(value * pow(10, spec().precision())) == 0)
custom_arg_formatter(fmt::format_context &ctx, fmt::format_specs &s)
: base(ctx, s) {}
using base::operator();
iterator operator()(double value) {
// Comparing a float to 0.0 is safe
if (round(value * pow(10, spec().precision())) == 0.0)
value = 0;
fmt::BasicArgFormatter<CustomArgFormatter, char>::visit_double(value);
return base::operator()(value);
}
};
// A custom argument formatter that doesn't print `-` for floating-point values
// rounded to 0.
class CustomPrintfArgFormatter :
public BasicPrintfArgFormatter<CustomPrintfArgFormatter, char> {
public:
typedef BasicPrintfArgFormatter<CustomPrintfArgFormatter, char> Base;
CustomPrintfArgFormatter(fmt::BasicWriter<char> &w, fmt::FormatSpec &spec)
: Base(w, spec) {}
void visit_double(double value) {
if (round(value * pow(10, spec().precision())) == 0)
value = 0;
Base::visit_double(value);
}
};
std::string custom_format(const char *format_str, fmt::ArgList args) {
fmt::MemoryWriter writer;
// Pass custom argument formatter as a template arg to BasicFormatter.
fmt::BasicFormatter<char, CustomArgFormatter> formatter(args, writer);
formatter.format(format_str);
return writer.str();
std::string custom_vformat(fmt::string_view format_str, fmt::format_args args) {
fmt::memory_buffer buffer;
// Pass custom argument formatter as a template arg to vwrite.
fmt::vformat_to<custom_arg_formatter>(buffer, format_str, args);
return std::string(buffer.data(), buffer.size());
}
FMT_VARIADIC(std::string, custom_format, const char *)
std::string custom_sprintf(const char* format_str, fmt::ArgList args){
fmt::MemoryWriter writer;
fmt::PrintfFormatter<char, CustomPrintfArgFormatter> formatter(args, writer);
formatter.format(format_str);
return writer.str();
template <typename... Args>
std::string custom_format(const char *format_str, const Args & ... args) {
auto va = fmt::make_format_args(args...);
return custom_vformat(format_str, va);
}
FMT_VARIADIC(std::string, custom_sprintf, const char*);
TEST(CustomFormatterTest, Format) {
EXPECT_EQ("0.00", custom_format("{:.2f}", -.00001));
EXPECT_EQ("0.00", custom_sprintf("%.2f", -.00001));
}
#endif

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 2.8.12)
cmake_minimum_required(VERSION 3.1.0)
project(fmt-test)
@@ -6,8 +6,12 @@ find_package(FMT REQUIRED)
add_executable(library-test main.cc)
target_link_libraries(library-test fmt::fmt)
target_compile_options(library-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
target_include_directories(library-test PUBLIC SYSTEM .)
if (TARGET fmt::fmt-header-only)
add_executable(header-only-test main.cc)
target_link_libraries(header-only-test fmt::fmt-header-only)
target_compile_options(header-only-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
target_include_directories(header-only-test PUBLIC SYSTEM .)
endif ()

View File

@@ -1,69 +1,61 @@
/*
Formatting library implementation tests.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - formatting library implementation tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#define FMT_EXTENDED_COLORS
#define FMT_NOEXCEPT
#undef FMT_SHARED
#include "test-assert.h"
// Include *.cc instead of *.h to test implementation-specific stuff.
#include "fmt/format.cc"
#include "fmt/printf.cc"
// Include format.cc instead of format.h to test implementation.
#include "../src/format.cc"
#include "fmt/printf.h"
#include <algorithm>
#include <cstring>
#include "gmock/gmock.h"
#include "gmock.h"
#include "gtest-extra.h"
#include "util.h"
#undef min
#undef max
template <typename T>
struct ValueExtractor: fmt::internal::function<T> {
T operator()(T value) {
return value;
}
template <typename U>
FMT_NORETURN T operator()(U) {
throw std::runtime_error(fmt::format("invalid type {}", typeid(U).name()));
}
};
TEST(FormatTest, ArgConverter) {
using fmt::internal::Arg;
Arg arg = Arg();
arg.type = Arg::LONG_LONG;
arg.long_long_value = std::numeric_limits<fmt::LongLong>::max();
fmt::internal::ArgConverter<fmt::LongLong>(arg, 'd').visit(arg);
EXPECT_EQ(Arg::LONG_LONG, arg.type);
long long value = std::numeric_limits<long long>::max();
auto arg = fmt::internal::make_arg<fmt::format_context>(value);
visit(fmt::internal::arg_converter<long long, fmt::format_context>(arg, 'd'),
arg);
EXPECT_EQ(value, visit(ValueExtractor<long long>(), arg));
}
TEST(FormatTest, FormatNegativeNaN) {
double nan = std::numeric_limits<double>::quiet_NaN();
if (fmt::internal::FPUtil::isnegative(-nan))
if (fmt::internal::fputil::isnegative(-nan))
EXPECT_EQ("-nan", fmt::format("{}", -nan));
else
fmt::print("Warning: compiler doesn't handle negative NaN correctly");
}
TEST(FormatTest, StrError) {
char *message = 0;
char *message = nullptr;
char buffer[BUFFER_SIZE];
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = 0, 0), "invalid buffer");
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = nullptr, 0), "invalid buffer");
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = buffer, 0),
"invalid buffer");
buffer[0] = 'x';
@@ -95,33 +87,40 @@ TEST(FormatTest, StrError) {
TEST(FormatTest, FormatErrorCode) {
std::string msg = "error 42", sep = ": ";
{
fmt::MemoryWriter w;
w << "garbage";
fmt::format_error_code(w, 42, "test");
EXPECT_EQ("test: " + msg, w.str());
fmt::memory_buffer buffer;
format_to(buffer, "garbage");
fmt::format_error_code(buffer, 42, "test");
EXPECT_EQ("test: " + msg, to_string(buffer));
}
{
fmt::MemoryWriter w;
fmt::memory_buffer buffer;
std::string prefix(
fmt::internal::INLINE_BUFFER_SIZE - msg.size() - sep.size() + 1, 'x');
fmt::format_error_code(w, 42, prefix);
EXPECT_EQ(msg, w.str());
fmt::inline_buffer_size - msg.size() - sep.size() + 1, 'x');
fmt::format_error_code(buffer, 42, prefix);
EXPECT_EQ(msg, to_string(buffer));
}
int codes[] = {42, -1};
for (std::size_t i = 0, n = sizeof(codes) / sizeof(*codes); i < n; ++i) {
// Test maximum buffer size.
msg = fmt::format("error {}", codes[i]);
fmt::MemoryWriter w;
fmt::memory_buffer buffer;
std::string prefix(
fmt::internal::INLINE_BUFFER_SIZE - msg.size() - sep.size(), 'x');
fmt::format_error_code(w, codes[i], prefix);
EXPECT_EQ(prefix + sep + msg, w.str());
std::size_t size = fmt::internal::INLINE_BUFFER_SIZE;
EXPECT_EQ(size, w.size());
w.clear();
fmt::inline_buffer_size - msg.size() - sep.size(), 'x');
fmt::format_error_code(buffer, codes[i], prefix);
EXPECT_EQ(prefix + sep + msg, to_string(buffer));
std::size_t size = fmt::inline_buffer_size;
EXPECT_EQ(size, buffer.size());
buffer.resize(0);
// Test with a message that doesn't fit into the buffer.
prefix += 'x';
fmt::format_error_code(w, codes[i], prefix);
EXPECT_EQ(msg, w.str());
fmt::format_error_code(buffer, codes[i], prefix);
EXPECT_EQ(msg, to_string(buffer));
}
}
TEST(ColorsTest, Colors) {
EXPECT_WRITE(stdout, fmt::print(fmt::rgb(255,20,30), "rgb(255,20,30)"),
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
EXPECT_WRITE(stdout, fmt::print(fmt::color::blue,"blue"),
"\x1b[38;2;000;000;255mblue\x1b[0m");
}

File diff suppressed because it is too large Load Diff

View File

@@ -36,7 +36,7 @@
// This line ensures that gtest.h can be compiled on its own, even
// when it's fused.
#include "gtest/gtest.h"
#include "gtest.h"
// The following lines pull in the real gtest *.cc files.
// Copyright 2005, Google Inc.

View File

@@ -235,7 +235,7 @@
// Most of the types needed for porting Google Mock are also required
// for Google Test and are defined in gtest-port.h.
#include "gtest/gtest.h"
#include "gtest.h"
// To avoid conditional compilation everywhere, we make it
// gmock-port.h's responsibility to #include the header implementing
@@ -825,8 +825,9 @@ template <typename T> struct DecayArray<T[]> {
// crashes).
template <typename T>
inline T Invalid() {
void *p = NULL;
return const_cast<typename remove_reference<T>::type&>(
*static_cast<volatile typename remove_reference<T>::type*>(NULL));
*static_cast<volatile typename remove_reference<T>::type*>(p));
}
template <>
inline void Invalid<void>() {}

View File

@@ -1,29 +1,9 @@
/*
Tests of custom Google Test assertions.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - tests of custom Google Test assertions
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "gtest-extra.h"
@@ -78,7 +58,7 @@ void throw_exception() {
}
void throw_system_error() {
throw fmt::SystemError(EDOM, "test");
throw fmt::system_error(EDOM, "test");
}
// Tests that when EXPECT_THROW_MSG fails, it evaluates its message argument
@@ -207,11 +187,11 @@ TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) {
// EXPECT_SYSTEM_ERROR macro.
TEST(ExpectSystemErrorTest, DoesNotGenerateUnreachableCodeWarning) {
int n = 0;
EXPECT_SYSTEM_ERROR(throw fmt::SystemError(EDOM, "test"), EDOM, "test");
EXPECT_SYSTEM_ERROR(throw fmt::system_error(EDOM, "test"), EDOM, "test");
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(n++, EDOM, ""), "");
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(throw 1, EDOM, ""), "");
EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(
throw fmt::SystemError(EDOM, "aaa"), EDOM, "bbb"), "");
throw fmt::system_error(EDOM, "aaa"), EDOM, "bbb"), "");
}
TEST(AssertionSyntaxTest, ExceptionAssertionBehavesLikeSingleStatement) {
@@ -268,10 +248,10 @@ TEST(ExpectTest, EXPECT_SYSTEM_ERROR) {
EXPECT_NONFATAL_FAILURE(
EXPECT_SYSTEM_ERROR(throw_exception(), EDOM, "test"),
"Expected: throw_exception() throws an exception of "
"type fmt::SystemError.\n Actual: it throws a different type.");
"type fmt::system_error.\n Actual: it throws a different type.");
EXPECT_NONFATAL_FAILURE(
EXPECT_SYSTEM_ERROR(do_nothing(), EDOM, "test"),
"Expected: do_nothing() throws an exception of type fmt::SystemError.\n"
"Expected: do_nothing() throws an exception of type fmt::system_error.\n"
" Actual: it throws nothing.");
EXPECT_NONFATAL_FAILURE(
EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "other"),
@@ -319,27 +299,27 @@ TEST(StreamingAssertionsTest, EXPECT_WRITE) {
}
TEST(UtilTest, FormatSystemError) {
fmt::MemoryWriter out;
fmt::memory_buffer out;
fmt::format_system_error(out, EDOM, "test message");
EXPECT_EQ(out.str(), format_system_error(EDOM, "test message"));
EXPECT_EQ(to_string(out), format_system_error(EDOM, "test message"));
}
#if FMT_USE_FILE_DESCRIPTORS
using fmt::BufferedFile;
using fmt::ErrorCode;
using fmt::File;
using fmt::buffered_file;
using fmt::error_code;
using fmt::file;
TEST(ErrorCodeTest, Ctor) {
EXPECT_EQ(0, ErrorCode().get());
EXPECT_EQ(42, ErrorCode(42).get());
EXPECT_EQ(0, error_code().get());
EXPECT_EQ(42, error_code(42).get());
}
TEST(OutputRedirectTest, ScopedRedirect) {
File read_end, write_end;
File::pipe(read_end, write_end);
file read_end, write_end;
file::pipe(read_end, write_end);
{
BufferedFile file(write_end.fdopen("w"));
buffered_file file(write_end.fdopen("w"));
std::fprintf(file.get(), "[[[");
{
OutputRedirect redir(file.get());
@@ -352,53 +332,53 @@ TEST(OutputRedirectTest, ScopedRedirect) {
// Test that OutputRedirect handles errors in flush correctly.
TEST(OutputRedirectTest, FlushErrorInCtor) {
File read_end, write_end;
File::pipe(read_end, write_end);
file read_end, write_end;
file::pipe(read_end, write_end);
int write_fd = write_end.descriptor();
File write_copy = write_end.dup(write_fd);
BufferedFile f = write_end.fdopen("w");
file write_copy = write_end.dup(write_fd);
buffered_file f = write_end.fdopen("w");
// Put a character in a file buffer.
EXPECT_EQ('x', fputc('x', f.get()));
FMT_POSIX(close(write_fd));
scoped_ptr<OutputRedirect> redir;
scoped_ptr<OutputRedirect> redir{nullptr};
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())),
EBADF, "cannot flush stream");
redir.reset();
redir.reset(nullptr);
write_copy.dup2(write_fd); // "undo" close or dtor will fail
}
TEST(OutputRedirectTest, DupErrorInCtor) {
BufferedFile f = open_buffered_file();
buffered_file f = open_buffered_file();
int fd = (f.fileno)();
File copy = File::dup(fd);
file copy = file::dup(fd);
FMT_POSIX(close(fd));
scoped_ptr<OutputRedirect> redir;
scoped_ptr<OutputRedirect> redir{nullptr};
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())),
EBADF, fmt::format("cannot duplicate file descriptor {}", fd));
copy.dup2(fd); // "undo" close or dtor will fail
}
TEST(OutputRedirectTest, RestoreAndRead) {
File read_end, write_end;
File::pipe(read_end, write_end);
BufferedFile file(write_end.fdopen("w"));
file read_end, write_end;
file::pipe(read_end, write_end);
buffered_file file(write_end.fdopen("w"));
std::fprintf(file.get(), "[[[");
OutputRedirect redir(file.get());
std::fprintf(file.get(), "censored");
EXPECT_EQ("censored", sanitize(redir.restore_and_read()));
EXPECT_EQ("", sanitize(redir.restore_and_read()));
std::fprintf(file.get(), "]]]");
file = BufferedFile();
file = buffered_file();
EXPECT_READ(read_end, "[[[]]]");
}
// Test that OutputRedirect handles errors in flush correctly.
TEST(OutputRedirectTest, FlushErrorInRestoreAndRead) {
File read_end, write_end;
File::pipe(read_end, write_end);
file read_end, write_end;
file::pipe(read_end, write_end);
int write_fd = write_end.descriptor();
File write_copy = write_end.dup(write_fd);
BufferedFile f = write_end.fdopen("w");
file write_copy = write_end.dup(write_fd);
buffered_file f = write_end.fdopen("w");
OutputRedirect redir(f.get());
// Put a character in a file buffer.
EXPECT_EQ('x', fputc('x', f.get()));
@@ -409,11 +389,11 @@ TEST(OutputRedirectTest, FlushErrorInRestoreAndRead) {
}
TEST(OutputRedirectTest, ErrorInDtor) {
File read_end, write_end;
File::pipe(read_end, write_end);
file read_end, write_end;
file::pipe(read_end, write_end);
int write_fd = write_end.descriptor();
File write_copy = write_end.dup(write_fd);
BufferedFile f = write_end.fdopen("w");
file write_copy = write_end.dup(write_fd);
buffered_file f = write_end.fdopen("w");
scoped_ptr<OutputRedirect> redir(new OutputRedirect(f.get()));
// Put a character in a file buffer.
EXPECT_EQ('x', fputc('x', f.get()));
@@ -423,9 +403,9 @@ TEST(OutputRedirectTest, ErrorInDtor) {
// output in EXPECT_STDERR and the second close will break output
// redirection.
FMT_POSIX(close(write_fd));
SUPPRESS_ASSERT(redir.reset());
SUPPRESS_ASSERT(redir.reset(nullptr));
}, format_system_error(EBADF, "cannot flush stream"));
write_copy.dup2(write_fd); // "undo" close or dtor of BufferedFile will fail
write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail
}
#endif // FMT_USE_FILE_DESCRIPTORS

View File

@@ -1,35 +1,15 @@
/*
Custom Google Test assertions.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - custom Google Test assertions
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "gtest-extra.h"
#if FMT_USE_FILE_DESCRIPTORS
using fmt::File;
using fmt::file;
void OutputRedirect::flush() {
#if EOF != -1
@@ -38,7 +18,7 @@ void OutputRedirect::flush() {
int result = 0;
FMT_RETRY(result, fflush(file_));
if (result != 0)
throw fmt::SystemError(errno, "cannot flush stream");
throw fmt::system_error(errno, "cannot flush stream");
}
void OutputRedirect::restore() {
@@ -50,14 +30,14 @@ void OutputRedirect::restore() {
original_.close();
}
OutputRedirect::OutputRedirect(FILE *file) : file_(file) {
OutputRedirect::OutputRedirect(FILE *f) : file_(f) {
flush();
int fd = FMT_POSIX(fileno(file));
// Create a File object referring to the original file.
original_ = File::dup(fd);
int fd = FMT_POSIX(fileno(f));
// Create a file object referring to the original file.
original_ = file::dup(fd);
// Create a pipe.
File write_end;
File::pipe(read_end_, write_end);
file write_end;
file::pipe(read_end_, write_end);
// Connect the passed FILE object to the write end of the pipe.
write_end.dup2(fd);
}
@@ -89,13 +69,13 @@ std::string OutputRedirect::restore_and_read() {
return content;
}
std::string read(File &f, std::size_t count) {
std::string read(file &f, std::size_t count) {
std::string buffer(count, '\0');
std::size_t n = 0, offset = 0;
do {
n = f.read(&buffer[offset], count - offset);
// We can't read more than size_t bytes since count has type size_t.
offset += static_cast<std::size_t>(n);
offset += n;
} while (offset < count && n != 0);
buffer.resize(offset);
return buffer;
@@ -103,8 +83,8 @@ std::string read(File &f, std::size_t count) {
#endif // FMT_USE_FILE_DESCRIPTORS
std::string format_system_error(int error_code, fmt::StringRef message) {
fmt::MemoryWriter out;
fmt::format_system_error(out, error_code, message);
return out.str();
std::string format_system_error(int error_code, fmt::string_view message) {
fmt::memory_buffer out;
format_system_error(out, error_code, message);
return to_string(out);
}

View File

@@ -1,37 +1,17 @@
/*
Custom Google Test assertions.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - custom Google Test assertions
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_GTEST_EXTRA_H_
#define FMT_GTEST_EXTRA_H_
#include <string>
#include <gmock/gmock.h>
#include "gmock.h"
#include "fmt/format.h"
#include "fmt/core.h"
#ifndef FMT_USE_FILE_DESCRIPTORS
# define FMT_USE_FILE_DESCRIPTORS 0
@@ -81,10 +61,10 @@
FMT_TEST_THROW_(statement, expected_exception, \
expected_message, GTEST_NONFATAL_FAILURE_)
std::string format_system_error(int error_code, fmt::StringRef message);
std::string format_system_error(int error_code, fmt::string_view message);
#define EXPECT_SYSTEM_ERROR(statement, error_code, message) \
EXPECT_THROW_MSG(statement, fmt::SystemError, \
EXPECT_THROW_MSG(statement, fmt::system_error, \
format_system_error(error_code, message))
#if FMT_USE_FILE_DESCRIPTORS
@@ -94,8 +74,8 @@ std::string format_system_error(int error_code, fmt::StringRef message);
class OutputRedirect {
private:
FILE *file_;
fmt::File original_; // Original file passed to redirector.
fmt::File read_end_; // Read end of the pipe where the output is redirected.
fmt::file original_; // Original file passed to redirector.
fmt::file read_end_; // Read end of the pipe where the output is redirected.
GTEST_DISALLOW_COPY_AND_ASSIGN_(OutputRedirect);
@@ -165,7 +145,7 @@ class SuppressAssert {
EXPECT_SYSTEM_ERROR(SUPPRESS_ASSERT(statement), error_code, message)
// Attempts to read count characters from a file.
std::string read(fmt::File &f, std::size_t count);
std::string read(fmt::file &f, std::size_t count);
#define EXPECT_READ(file, expected_content) \
EXPECT_EQ(expected_content, read(file, std::strlen(expected_content)))
@@ -175,7 +155,7 @@ std::string read(fmt::File &f, std::size_t count);
template <typename Mock>
struct ScopedMock : testing::StrictMock<Mock> {
ScopedMock() { Mock::instance = this; }
~ScopedMock() { Mock::instance = 0; }
~ScopedMock() { Mock::instance = nullptr; }
};
#endif // FMT_GTEST_EXTRA_H_

View File

@@ -1,3 +1,3 @@
// Header-only configuration test
#include "fmt/format.h"
#include "fmt/core.h"

View File

@@ -1,3 +1,3 @@
// Additional translation unit for the header-only configuration test
#include "fmt/format.h"
#include "fmt/core.h"

View File

@@ -1,115 +0,0 @@
/*
Tests of variadic function emulation macros.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <utility>
#include <gtest/gtest.h>
#define FMT_USE_VARIADIC_TEMPLATES 0
#include "fmt/format.h"
#define IDENTITY(x) x
TEST(UtilTest, Gen) {
int values[] = {FMT_GEN(10, IDENTITY)};
for (int i = 0; i < 10; ++i)
EXPECT_EQ(i, values[i]);
}
#define MAKE_PAIR(x, y) std::make_pair(x, y)
TEST(UtilTest, ForEach) {
std::pair<char, int> values[] = {
FMT_FOR_EACH10(MAKE_PAIR, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j')
};
for (int i = 0; i < 10; ++i) {
EXPECT_EQ('a' + i, values[i].first);
EXPECT_EQ(i, values[i].second);
}
}
TEST(UtilTest, NArg) {
EXPECT_EQ(1, FMT_NARG(a));
EXPECT_EQ(2, FMT_NARG(a, b));
EXPECT_EQ(3, FMT_NARG(a, b, c));
EXPECT_EQ(4, FMT_NARG(a, b, c, d));
EXPECT_EQ(5, FMT_NARG(a, b, c, d, e));
EXPECT_EQ(6, FMT_NARG(a, b, c, d, e, f));
EXPECT_EQ(7, FMT_NARG(a, b, c, d, e, f, g));
EXPECT_EQ(8, FMT_NARG(a, b, c, d, e, f, g, h));
EXPECT_EQ(9, FMT_NARG(a, b, c, d, e, f, g, h, i));
EXPECT_EQ(10, FMT_NARG(a, b, c, d, e, f, g, h, i, j));
}
int result;
#define MAKE_TEST(func) \
void func(const char *, const fmt::ArgList &args) { \
result = 0; \
for (unsigned i = 0; args[i].type; ++i) \
result += args[i].int_value; \
}
MAKE_TEST(test_func)
typedef char Char;
FMT_WRAP1(test_func, const char *, 1)
TEST(UtilTest, Wrap1) {
result = 0;
test_func("", 42);
EXPECT_EQ(42, result);
}
MAKE_TEST(test_variadic_void)
FMT_VARIADIC_VOID(test_variadic_void, const char *)
TEST(UtilTest, VariadicVoid) {
result = 0;
test_variadic_void("", 10, 20, 30, 40, 50, 60, 70, 80, 90, 100);
EXPECT_EQ(550, result);
}
template <int>
struct S {};
#define GET_TYPE(n) S<n>
int test_variadic(FMT_GEN(10, GET_TYPE), const fmt::ArgList &args) { \
int result = 0; \
for (unsigned i = 0; args[i].type; ++i) \
result += args[i].int_value; \
return result;
}
FMT_VARIADIC(int, test_variadic,
S<0>, S<1>, S<2>, S<3>, S<4>, S<5>, S<6>, S<7>, S<8>, S<9>)
#define MAKE_ARG(n) S<n>()
TEST(UtilTest, Variadic) {
EXPECT_EQ(550, test_variadic(FMT_GEN(10, MAKE_ARG),
10, 20, 30, 40, 50, 60, 70, 80, 90, 100));
}

View File

@@ -1,34 +1,14 @@
/*
Mock allocator.
Copyright (c) 2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - mock allocator
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_MOCK_ALLOCATOR_H_
#define FMT_MOCK_ALLOCATOR_H_
#include "gmock/gmock.h"
#include "gmock.h"
template <typename T>
class MockAllocator {
@@ -36,8 +16,8 @@ class MockAllocator {
MockAllocator() {}
MockAllocator(const MockAllocator &) {}
typedef T value_type;
MOCK_METHOD2_T(allocate, T *(std::size_t n, const void *h));
MOCK_METHOD2_T(deallocate, void (T *p, std::size_t n));
MOCK_METHOD1_T(allocate, T* (std::size_t n));
MOCK_METHOD2_T(deallocate, void (T* p, std::size_t n));
};
template <typename Allocator>
@@ -48,7 +28,7 @@ class AllocatorRef {
public:
typedef typename Allocator::value_type value_type;
explicit AllocatorRef(Allocator *alloc = 0) : alloc_(alloc) {}
explicit AllocatorRef(Allocator *alloc = nullptr) : alloc_(alloc) {}
AllocatorRef(const AllocatorRef &other) : alloc_(other.alloc_) {}
@@ -61,7 +41,7 @@ class AllocatorRef {
private:
void move(AllocatorRef &other) {
alloc_ = other.alloc_;
other.alloc_ = 0;
other.alloc_ = nullptr;
}
public:
@@ -78,14 +58,10 @@ class AllocatorRef {
Allocator *get() const { return alloc_; }
value_type *allocate(std::size_t n, const void *h) {
#if FMT_USE_ALLOCATOR_TRAITS
return std::allocator_traits<Allocator>::allocate(*alloc_, n, h);
#else
return alloc_->allocate(n, h);
#endif
value_type* allocate(std::size_t n) {
return fmt::internal::allocate(*alloc_, n);
}
void deallocate(value_type *p, std::size_t n) { alloc_->deallocate(p, n); }
void deallocate(value_type* p, std::size_t n) { alloc_->deallocate(p, n); }
};
#endif // FMT_MOCK_ALLOCATOR_H_

View File

@@ -1,77 +1,65 @@
/*
std::ostream support tests
Copyright (c) 2012-2016, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - std::ostream support tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/ostream.h"
#include <sstream>
#include "gmock/gmock.h"
#include "gmock.h"
#include "gtest-extra.h"
#include "util.h"
using fmt::format;
using fmt::FormatError;
using fmt::format_error;
std::ostream &operator<<(std::ostream &os, const Date &d) {
static std::ostream &operator<<(std::ostream &os, const Date &d) {
os << d.year() << '-' << d.month() << '-' << d.day();
return os;
}
std::wostream &operator<<(std::wostream &os, const Date &d) {
static std::wostream &operator<<(std::wostream &os, const Date &d) {
os << d.year() << L'-' << d.month() << L'-' << d.day();
return os;
}
enum TestEnum {};
std::ostream &operator<<(std::ostream &os, TestEnum) {
static std::ostream &operator<<(std::ostream &os, TestEnum) {
return os << "TestEnum";
}
static std::wostream &operator<<(std::wostream &os, TestEnum) {
return os << L"TestEnum";
}
enum TestEnum2 {A};
TEST(OStreamTest, Enum) {
EXPECT_FALSE(fmt::internal::ConvertToInt<TestEnum>::value);
EXPECT_FALSE((fmt::internal::convert_to_int<TestEnum, char>::value));
EXPECT_EQ("TestEnum", fmt::format("{}", TestEnum()));
EXPECT_EQ("0", fmt::format("{}", A));
EXPECT_FALSE((fmt::internal::convert_to_int<TestEnum, wchar_t>::value));
EXPECT_EQ(L"TestEnum", fmt::format(L"{}", TestEnum()));
EXPECT_EQ(L"0", fmt::format(L"{}", A));
}
struct TestArgFormatter : fmt::BasicArgFormatter<TestArgFormatter, char> {
TestArgFormatter(fmt::BasicFormatter<char, TestArgFormatter> &f,
fmt::FormatSpec &s, const char *fmt)
: fmt::BasicArgFormatter<TestArgFormatter, char>(f, s, fmt) {}
typedef fmt::back_insert_range<fmt::internal::buffer> range;
struct test_arg_formatter: fmt::arg_formatter<range> {
test_arg_formatter(fmt::format_context &ctx, fmt::format_specs &s)
: fmt::arg_formatter<range>(ctx, s) {}
};
TEST(OStreamTest, CustomArg) {
fmt::MemoryWriter writer;
typedef fmt::BasicFormatter<char, TestArgFormatter> Formatter;
Formatter formatter(fmt::ArgList(), writer);
fmt::FormatSpec spec;
TestArgFormatter af(formatter, spec, "}");
af.visit(fmt::internal::MakeArg<Formatter>(TestEnum()));
EXPECT_EQ("TestEnum", writer.str());
fmt::memory_buffer buffer;
fmt::internal::buffer &base = buffer;
fmt::format_context ctx(std::back_inserter(base), "", fmt::format_args());
fmt::format_specs spec;
test_arg_formatter af(ctx, spec);
visit(af, fmt::internal::make_arg<fmt::format_context>(TestEnum()));
EXPECT_EQ("TestEnum", std::string(buffer.data(), buffer.size()));
}
TEST(OStreamTest, Format) {
@@ -87,19 +75,19 @@ TEST(OStreamTest, FormatSpecs) {
EXPECT_EQ("def ", format("{0:<5}", TestString("def")));
EXPECT_EQ(" def", format("{0:>5}", TestString("def")));
EXPECT_THROW_MSG(format("{0:=5}", TestString("def")),
FormatError, "format specifier '=' requires numeric argument");
format_error, "format specifier requires numeric argument");
EXPECT_EQ(" def ", format("{0:^5}", TestString("def")));
EXPECT_EQ("def**", format("{0:*<5}", TestString("def")));
EXPECT_THROW_MSG(format("{0:+}", TestString()),
FormatError, "format specifier '+' requires numeric argument");
format_error, "format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0:-}", TestString()),
FormatError, "format specifier '-' requires numeric argument");
format_error, "format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0: }", TestString()),
FormatError, "format specifier ' ' requires numeric argument");
format_error, "format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0:#}", TestString()),
FormatError, "format specifier '#' requires numeric argument");
format_error, "format specifier requires numeric argument");
EXPECT_THROW_MSG(format("{0:05}", TestString()),
FormatError, "format specifier '0' requires numeric argument");
format_error, "format specifier requires numeric argument");
EXPECT_EQ("test ", format("{0:13}", TestString("test")));
EXPECT_EQ("test ", format("{0:{1}}", TestString("test"), 13));
EXPECT_EQ("te", format("{0:.2}", TestString("test")));
@@ -107,7 +95,7 @@ TEST(OStreamTest, FormatSpecs) {
}
struct EmptyTest {};
std::ostream &operator<<(std::ostream &os, EmptyTest) {
static std::ostream &operator<<(std::ostream &os, EmptyTest) {
return os << "";
}
@@ -119,13 +107,17 @@ TEST(OStreamTest, Print) {
std::ostringstream os;
fmt::print(os, "Don't {}!", "panic");
EXPECT_EQ("Don't panic!", os.str());
std::wostringstream wos;
fmt::print(wos, L"Don't {}!", L"panic");
EXPECT_EQ(L"Don't panic!", wos.str());
}
TEST(OStreamTest, WriteToOStream) {
std::ostringstream os;
fmt::MemoryWriter w;
w << "foo";
fmt::internal::write(os, w);
fmt::memory_buffer buffer;
const char *foo = "foo";
buffer.append(foo, foo + std::strlen(foo));
fmt::internal::write(os, buffer);
EXPECT_EQ("foo", os.str());
}
@@ -135,55 +127,45 @@ TEST(OStreamTest, WriteToOStreamMaxSize) {
if (max_size <= fmt::internal::to_unsigned(max_streamsize))
return;
class TestWriter : public fmt::BasicWriter<char> {
private:
struct TestBuffer : fmt::Buffer<char> {
explicit TestBuffer(std::size_t size) { size_ = size; }
void grow(std::size_t) {}
} buffer_;
public:
explicit TestWriter(std::size_t size)
: fmt::BasicWriter<char>(buffer_), buffer_(size) {}
} w(max_size);
struct test_buffer : fmt::internal::buffer {
explicit test_buffer(std::size_t size) { resize(size); }
void grow(std::size_t) {}
} buffer(max_size);
struct MockStreamBuf : std::streambuf {
struct mock_streambuf : std::streambuf {
MOCK_METHOD2(xsputn, std::streamsize (const void *s, std::streamsize n));
std::streamsize xsputn(const char *s, std::streamsize n) {
const void *v = s;
return xsputn(v, n);
}
} buffer;
} streambuf;
struct TestOStream : std::ostream {
explicit TestOStream(MockStreamBuf &buffer) : std::ostream(&buffer) {}
} os(buffer);
struct test_ostream : std::ostream {
explicit test_ostream(mock_streambuf &buffer) : std::ostream(&buffer) {}
} os(streambuf);
testing::InSequence sequence;
const char *data = 0;
const char *data = nullptr;
std::size_t size = max_size;
do {
typedef fmt::internal::MakeUnsigned<std::streamsize>::Type UStreamSize;
UStreamSize n = std::min<UStreamSize>(
typedef std::make_unsigned<std::streamsize>::type ustreamsize;
ustreamsize n = std::min<ustreamsize>(
size, fmt::internal::to_unsigned(max_streamsize));
EXPECT_CALL(buffer, xsputn(data, static_cast<std::streamsize>(n)))
EXPECT_CALL(streambuf, xsputn(data, static_cast<std::streamsize>(n)))
.WillOnce(testing::Return(max_streamsize));
data += n;
size -= static_cast<std::size_t>(n);
size -= n;
} while (size != 0);
fmt::internal::write(os, w);
fmt::internal::write(os, buffer);
}
struct ConvertibleToInt {
template <typename ValueType>
operator ValueType() const {
return 0;
}
friend std::ostream &operator<<(std::ostream &o, ConvertibleToInt) {
return o << "foo";
}
};
TEST(FormatTest, FormatConvertibleToInt) {
EXPECT_EQ("foo", fmt::format("{}", ConvertibleToInt()));
TEST(OStreamTest, Join) {
int v[3] = {1, 2, 3};
EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join(v, v + 3, ", ")));
}
#if FMT_USE_CONSTEXPR
TEST(OStreamTest, ConstexprString) {
EXPECT_EQ("42", format(fmt("{}"), std::string("42")));
}
#endif

View File

@@ -1,35 +1,17 @@
/*
Tests of the C++ interface to POSIX functions that require mocks
Copyright (c) 2012-2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Tests of the C++ interface to POSIX functions that require mocks
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
// Disable bogus MSVC warnings.
#define _CRT_SECURE_NO_WARNINGS
#ifdef _MSC_VER
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "posix-mock.h"
#include "fmt/posix.cc"
#include "../src/posix.cc"
#include <errno.h>
#include <fcntl.h>
@@ -41,13 +23,13 @@
# undef ERROR
#endif
#include "gmock/gmock.h"
#include "gmock.h"
#include "gtest-extra.h"
#include "util.h"
using fmt::BufferedFile;
using fmt::ErrorCode;
using fmt::File;
using fmt::buffered_file;
using fmt::error_code;
using fmt::file;
using testing::internal::scoped_ptr;
using testing::_;
@@ -151,7 +133,7 @@ int test::dup2(int fildes, int fildes2) {
}
FILE *test::fdopen(int fildes, const char *mode) {
EMULATE_EINTR(fdopen, 0);
EMULATE_EINTR(fdopen, nullptr);
return ::FMT_POSIX(fdopen(fildes, mode));
}
@@ -180,7 +162,7 @@ int test::pipe(int *pfds, unsigned psize, int textmode) {
#endif
FILE *test::fopen(const char *filename, const char *mode) {
EMULATE_EINTR(fopen, 0);
EMULATE_EINTR(fopen, nullptr);
return ::fopen(filename, mode);
}
@@ -213,17 +195,11 @@ int (test::fileno)(FILE *stream) {
# define EXPECT_EQ_POSIX(expected, actual)
#endif
void write_file(fmt::CStringRef filename, fmt::StringRef content) {
fmt::BufferedFile f(filename, "w");
static void write_file(fmt::cstring_view filename, fmt::string_view content) {
fmt::buffered_file f(filename, "w");
f.print("{}", content);
}
TEST(UtilTest, StaticAssert) {
FMT_STATIC_ASSERT(true, "success");
// Static assertion failure is tested in compile-test because it causes
// a compile-time error.
}
TEST(UtilTest, GetPageSize) {
#ifdef _WIN32
SYSTEM_INFO si = {};
@@ -240,8 +216,8 @@ TEST(UtilTest, GetPageSize) {
TEST(FileTest, OpenRetry) {
write_file("test", "there must be something here");
scoped_ptr<File> f;
EXPECT_RETRY(f.reset(new File("test", File::RDONLY)),
scoped_ptr<file> f{nullptr};
EXPECT_RETRY(f.reset(new file("test", file::RDONLY)),
open, "cannot open file test");
#ifndef _WIN32
char c = 0;
@@ -250,13 +226,13 @@ TEST(FileTest, OpenRetry) {
}
TEST(FileTest, CloseNoRetryInDtor) {
File read_end, write_end;
File::pipe(read_end, write_end);
scoped_ptr<File> f(new File(std::move(read_end)));
file read_end, write_end;
file::pipe(read_end, write_end);
scoped_ptr<file> f(new file(std::move(read_end)));
int saved_close_count = 0;
EXPECT_WRITE(stderr, {
close_count = 1;
f.reset();
f.reset(nullptr);
saved_close_count = close_count;
close_count = 0;
}, format_system_error(EINTR, "cannot close file") + "\n");
@@ -264,8 +240,8 @@ TEST(FileTest, CloseNoRetryInDtor) {
}
TEST(FileTest, CloseNoRetry) {
File read_end, write_end;
File::pipe(read_end, write_end);
file read_end, write_end;
file::pipe(read_end, write_end);
close_count = 1;
EXPECT_SYSTEM_ERROR(read_end.close(), EINTR, "cannot close file");
EXPECT_EQ(2, close_count);
@@ -275,15 +251,15 @@ TEST(FileTest, CloseNoRetry) {
TEST(FileTest, Size) {
std::string content = "top secret, destroy before reading";
write_file("test", content);
File f("test", File::RDONLY);
file f("test", file::RDONLY);
EXPECT_GE(f.size(), 0);
EXPECT_EQ(content.size(), static_cast<fmt::ULongLong>(f.size()));
EXPECT_EQ(content.size(), static_cast<unsigned long long>(f.size()));
#ifdef _WIN32
fmt::MemoryWriter message;
fmt::memory_buffer message;
fmt::internal::format_windows_error(
message, ERROR_ACCESS_DENIED, "cannot get file size");
fstat_sim = ERROR;
EXPECT_THROW_MSG(f.size(), fmt::WindowsError, message.str());
EXPECT_THROW_MSG(f.size(), fmt::windows_error, fmt::to_string(message));
fstat_sim = NONE;
#else
f.close();
@@ -293,7 +269,7 @@ TEST(FileTest, Size) {
TEST(FileTest, MaxSize) {
write_file("test", "");
File f("test", File::RDONLY);
file f("test", file::RDONLY);
fstat_sim = MAX_SIZE;
EXPECT_GE(f.size(), 0);
EXPECT_EQ(max_file_size(), f.size());
@@ -301,8 +277,8 @@ TEST(FileTest, MaxSize) {
}
TEST(FileTest, ReadRetry) {
File read_end, write_end;
File::pipe(read_end, write_end);
file read_end, write_end;
file::pipe(read_end, write_end);
enum { SIZE = 4 };
write_end.write("test", SIZE);
write_end.close();
@@ -314,8 +290,8 @@ TEST(FileTest, ReadRetry) {
}
TEST(FileTest, WriteRetry) {
File read_end, write_end;
File::pipe(read_end, write_end);
file read_end, write_end;
file::pipe(read_end, write_end);
enum { SIZE = 4 };
std::size_t count = 0;
EXPECT_RETRY(count = write_end.write("test", SIZE),
@@ -332,29 +308,29 @@ TEST(FileTest, WriteRetry) {
#ifdef _WIN32
TEST(FileTest, ConvertReadCount) {
File read_end, write_end;
File::pipe(read_end, write_end);
file read_end, write_end;
file::pipe(read_end, write_end);
char c;
std::size_t size = UINT_MAX;
if (sizeof(unsigned) != sizeof(std::size_t))
++size;
read_count = 1;
read_nbyte = 0;
EXPECT_THROW(read_end.read(&c, size), fmt::SystemError);
EXPECT_THROW(read_end.read(&c, size), fmt::system_error);
read_count = 0;
EXPECT_EQ(UINT_MAX, read_nbyte);
}
TEST(FileTest, ConvertWriteCount) {
File read_end, write_end;
File::pipe(read_end, write_end);
file read_end, write_end;
file::pipe(read_end, write_end);
char c;
std::size_t size = UINT_MAX;
if (sizeof(unsigned) != sizeof(std::size_t))
++size;
write_count = 1;
write_nbyte = 0;
EXPECT_THROW(write_end.write(&c, size), fmt::SystemError);
EXPECT_THROW(write_end.write(&c, size), fmt::system_error);
write_count = 0;
EXPECT_EQ(UINT_MAX, write_nbyte);
}
@@ -363,14 +339,14 @@ TEST(FileTest, ConvertWriteCount) {
TEST(FileTest, DupNoRetry) {
int stdout_fd = FMT_POSIX(fileno(stdout));
dup_count = 1;
EXPECT_SYSTEM_ERROR(File::dup(stdout_fd), EINTR,
EXPECT_SYSTEM_ERROR(file::dup(stdout_fd), EINTR,
fmt::format("cannot duplicate file descriptor {}", stdout_fd));
dup_count = 0;
}
TEST(FileTest, Dup2Retry) {
int stdout_fd = FMT_POSIX(fileno(stdout));
File f1 = File::dup(stdout_fd), f2 = File::dup(stdout_fd);
file f1 = file::dup(stdout_fd), f2 = file::dup(stdout_fd);
EXPECT_RETRY(f1.dup2(f2.descriptor()), dup2,
fmt::format("cannot duplicate file descriptor {} to {}",
f1.descriptor(), f2.descriptor()));
@@ -378,8 +354,8 @@ TEST(FileTest, Dup2Retry) {
TEST(FileTest, Dup2NoExceptRetry) {
int stdout_fd = FMT_POSIX(fileno(stdout));
File f1 = File::dup(stdout_fd), f2 = File::dup(stdout_fd);
ErrorCode ec;
file f1 = file::dup(stdout_fd), f2 = file::dup(stdout_fd);
error_code ec;
dup2_count = 1;
f1.dup2(f2.descriptor(), ec);
#ifndef _WIN32
@@ -391,16 +367,16 @@ TEST(FileTest, Dup2NoExceptRetry) {
}
TEST(FileTest, PipeNoRetry) {
File read_end, write_end;
file read_end, write_end;
pipe_count = 1;
EXPECT_SYSTEM_ERROR(
File::pipe(read_end, write_end), EINTR, "cannot create pipe");
file::pipe(read_end, write_end), EINTR, "cannot create pipe");
pipe_count = 0;
}
TEST(FileTest, FdopenNoRetry) {
File read_end, write_end;
File::pipe(read_end, write_end);
file read_end, write_end;
file::pipe(read_end, write_end);
fdopen_count = 1;
EXPECT_SYSTEM_ERROR(read_end.fdopen("r"),
EINTR, "cannot associate stream with file descriptor");
@@ -409,24 +385,24 @@ TEST(FileTest, FdopenNoRetry) {
TEST(BufferedFileTest, OpenRetry) {
write_file("test", "there must be something here");
scoped_ptr<BufferedFile> f;
EXPECT_RETRY(f.reset(new BufferedFile("test", "r")),
scoped_ptr<buffered_file> f{nullptr};
EXPECT_RETRY(f.reset(new buffered_file("test", "r")),
fopen, "cannot open file test");
#ifndef _WIN32
char c = 0;
if (fread(&c, 1, 1, f->get()) < 1)
throw fmt::SystemError(errno, "fread failed");
throw fmt::system_error(errno, "fread failed");
#endif
}
TEST(BufferedFileTest, CloseNoRetryInDtor) {
File read_end, write_end;
File::pipe(read_end, write_end);
scoped_ptr<BufferedFile> f(new BufferedFile(read_end.fdopen("r")));
file read_end, write_end;
file::pipe(read_end, write_end);
scoped_ptr<buffered_file> f(new buffered_file(read_end.fdopen("r")));
int saved_fclose_count = 0;
EXPECT_WRITE(stderr, {
fclose_count = 1;
f.reset();
f.reset(nullptr);
saved_fclose_count = fclose_count;
fclose_count = 0;
}, format_system_error(EINTR, "cannot close file") + "\n");
@@ -434,9 +410,9 @@ TEST(BufferedFileTest, CloseNoRetryInDtor) {
}
TEST(BufferedFileTest, CloseNoRetry) {
File read_end, write_end;
File::pipe(read_end, write_end);
BufferedFile f = read_end.fdopen("r");
file read_end, write_end;
file::pipe(read_end, write_end);
buffered_file f = read_end.fdopen("r");
fclose_count = 1;
EXPECT_SYSTEM_ERROR(f.close(), EINTR, "cannot close file");
EXPECT_EQ(2, fclose_count);
@@ -444,9 +420,9 @@ TEST(BufferedFileTest, CloseNoRetry) {
}
TEST(BufferedFileTest, FilenoNoRetry) {
File read_end, write_end;
File::pipe(read_end, write_end);
BufferedFile f = read_end.fdopen("r");
file read_end, write_end;
file::pipe(read_end, write_end);
buffered_file f = read_end.fdopen("r");
fileno_count = 1;
EXPECT_SYSTEM_ERROR((f.fileno)(), EINTR, "cannot get file descriptor");
EXPECT_EQ(2, fileno_count);
@@ -462,8 +438,9 @@ TEST(ScopedMock, Scope) {
ScopedMock<TestMock> mock;
EXPECT_EQ(&mock, TestMock::instance);
TestMock &copy = mock;
static_cast<void>(copy);
}
EXPECT_EQ(0, TestMock::instance);
EXPECT_EQ(nullptr, TestMock::instance);
}
#ifdef FMT_LOCALE
@@ -498,25 +475,33 @@ double _strtod_l(const char *nptr, char **endptr, _locale_t locale) {
# pragma warning(pop)
#endif
LocaleType newlocale(int category_mask, const char *locale, LocaleType base) {
#if defined(__THROW) && FMT_GCC_VERSION > 0 && FMT_GCC_VERSION <= 408
#define FMT_LOCALE_THROW __THROW
#else
#define FMT_LOCALE_THROW
#endif
LocaleType newlocale(int category_mask, const char *locale, LocaleType base) FMT_LOCALE_THROW {
return LocaleMock::instance->newlocale(category_mask, locale, base);
}
#if defined(__APPLE__) || defined(__FreeBSD__)
#if defined(__APPLE__) || (defined(__FreeBSD__) && __FreeBSD_version < 1200002)
typedef int FreeLocaleResult;
#else
typedef void FreeLocaleResult;
#endif
FreeLocaleResult freelocale(LocaleType locale) {
FreeLocaleResult freelocale(LocaleType locale) FMT_LOCALE_THROW {
LocaleMock::instance->freelocale(locale);
return FreeLocaleResult();
}
double strtod_l(const char *nptr, char **endptr, LocaleType locale) {
double strtod_l(const char *nptr, char **endptr, LocaleType locale) FMT_LOCALE_THROW {
return LocaleMock::instance->strtod_l(nptr, endptr, locale);
}
#undef FMT_LOCALE_THROW
TEST(LocaleTest, LocaleMock) {
ScopedMock<LocaleMock> mock;
LocaleType locale = reinterpret_cast<LocaleType>(11);
@@ -530,7 +515,7 @@ TEST(LocaleTest, Locale) {
#endif
ScopedMock<LocaleMock> mock;
LocaleType impl = reinterpret_cast<LocaleType>(42);
EXPECT_CALL(mock, newlocale(LC_NUMERIC_MASK, StrEq("C"), 0))
EXPECT_CALL(mock, newlocale(LC_NUMERIC_MASK, StrEq("C"), nullptr))
.WillOnce(Return(impl));
EXPECT_CALL(mock, freelocale(impl));
fmt::Locale locale;

View File

@@ -1,29 +1,9 @@
/*
Mocks of POSIX functions
Copyright (c) 2012-2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - mocks of POSIX functions
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_POSIX_TEST_H
#define FMT_POSIX_TEST_H
@@ -34,6 +14,7 @@
#ifdef _WIN32
# include <windows.h>
#else
# include <sys/param.h> // for FreeBSD version
# include <sys/types.h> // for ssize_t
#endif

View File

@@ -1,29 +1,9 @@
/*
Tests of the C++ interface to POSIX functions
Copyright (c) 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - tests of the C++ interface to POSIX functions
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include <cstdlib> // std::exit
#include <cstring>
@@ -36,19 +16,19 @@
# undef fileno
#endif
using fmt::BufferedFile;
using fmt::ErrorCode;
using fmt::File;
using fmt::buffered_file;
using fmt::error_code;
using fmt::file;
using testing::internal::scoped_ptr;
// Checks if the file is open by reading one character from it.
bool isopen(int fd) {
static bool isopen(int fd) {
char buffer;
return FMT_POSIX(read(fd, &buffer, 1)) == 1;
}
bool isclosed(int fd) {
static bool isclosed(int fd) {
char buffer;
std::streamsize result = 0;
SUPPRESS_ASSERT(result = FMT_POSIX(read(fd, &buffer, 1)));
@@ -56,16 +36,16 @@ bool isclosed(int fd) {
}
// Opens a file for reading.
File open_file() {
File read_end, write_end;
File::pipe(read_end, write_end);
static file open_file() {
file read_end, write_end;
file::pipe(read_end, write_end);
write_end.write(FILE_CONTENT, std::strlen(FILE_CONTENT));
write_end.close();
return read_end;
}
// Attempts to write a string to a file.
void write(File &f, fmt::StringRef s) {
static void write(file &f, fmt::string_view s) {
std::size_t num_chars_left = s.size();
const char *ptr = s.data();
do {
@@ -73,57 +53,57 @@ void write(File &f, fmt::StringRef s) {
ptr += count;
// We can't write more than size_t bytes since num_chars_left
// has type size_t.
num_chars_left -= static_cast<std::size_t>(count);
num_chars_left -= count;
} while (num_chars_left != 0);
}
TEST(BufferedFileTest, DefaultCtor) {
BufferedFile f;
EXPECT_TRUE(f.get() == 0);
buffered_file f;
EXPECT_TRUE(f.get() == nullptr);
}
TEST(BufferedFileTest, MoveCtor) {
BufferedFile bf = open_buffered_file();
buffered_file bf = open_buffered_file();
FILE *fp = bf.get();
EXPECT_TRUE(fp != 0);
BufferedFile bf2(std::move(bf));
EXPECT_TRUE(fp != nullptr);
buffered_file bf2(std::move(bf));
EXPECT_EQ(fp, bf2.get());
EXPECT_TRUE(bf.get() == 0);
EXPECT_TRUE(bf.get() == nullptr);
}
TEST(BufferedFileTest, MoveAssignment) {
BufferedFile bf = open_buffered_file();
buffered_file bf = open_buffered_file();
FILE *fp = bf.get();
EXPECT_TRUE(fp != 0);
BufferedFile bf2;
EXPECT_TRUE(fp != nullptr);
buffered_file bf2;
bf2 = std::move(bf);
EXPECT_EQ(fp, bf2.get());
EXPECT_TRUE(bf.get() == 0);
EXPECT_TRUE(bf.get() == nullptr);
}
TEST(BufferedFileTest, MoveAssignmentClosesFile) {
BufferedFile bf = open_buffered_file();
BufferedFile bf2 = open_buffered_file();
buffered_file bf = open_buffered_file();
buffered_file bf2 = open_buffered_file();
int old_fd = bf2.fileno();
bf2 = std::move(bf);
EXPECT_TRUE(isclosed(old_fd));
}
TEST(BufferedFileTest, MoveFromTemporaryInCtor) {
FILE *fp = 0;
BufferedFile f(open_buffered_file(&fp));
FILE *fp = nullptr;
buffered_file f(open_buffered_file(&fp));
EXPECT_EQ(fp, f.get());
}
TEST(BufferedFileTest, MoveFromTemporaryInAssignment) {
FILE *fp = 0;
BufferedFile f;
FILE *fp = nullptr;
buffered_file f;
f = open_buffered_file(&fp);
EXPECT_EQ(fp, f.get());
}
TEST(BufferedFileTest, MoveFromTemporaryInAssignmentClosesFile) {
BufferedFile f = open_buffered_file();
buffered_file f = open_buffered_file();
int old_fd = f.fileno();
f = open_buffered_file();
EXPECT_TRUE(isclosed(old_fd));
@@ -132,60 +112,60 @@ TEST(BufferedFileTest, MoveFromTemporaryInAssignmentClosesFile) {
TEST(BufferedFileTest, CloseFileInDtor) {
int fd = 0;
{
BufferedFile f = open_buffered_file();
buffered_file f = open_buffered_file();
fd = f.fileno();
}
EXPECT_TRUE(isclosed(fd));
}
TEST(BufferedFileTest, CloseErrorInDtor) {
scoped_ptr<BufferedFile> f(new BufferedFile(open_buffered_file()));
scoped_ptr<buffered_file> f(new buffered_file(open_buffered_file()));
EXPECT_WRITE(stderr, {
// The close function must be called inside EXPECT_WRITE, otherwise
// the system may recycle closed file descriptor when redirecting the
// output in EXPECT_STDERR and the second close will break output
// redirection.
FMT_POSIX(close(f->fileno()));
SUPPRESS_ASSERT(f.reset());
SUPPRESS_ASSERT(f.reset(nullptr));
}, format_system_error(EBADF, "cannot close file") + "\n");
}
TEST(BufferedFileTest, Close) {
BufferedFile f = open_buffered_file();
buffered_file f = open_buffered_file();
int fd = f.fileno();
f.close();
EXPECT_TRUE(f.get() == 0);
EXPECT_TRUE(f.get() == nullptr);
EXPECT_TRUE(isclosed(fd));
}
TEST(BufferedFileTest, CloseError) {
BufferedFile f = open_buffered_file();
buffered_file f = open_buffered_file();
FMT_POSIX(close(f.fileno()));
EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
EXPECT_TRUE(f.get() == 0);
EXPECT_TRUE(f.get() == nullptr);
}
TEST(BufferedFileTest, Fileno) {
BufferedFile f;
buffered_file f;
#ifndef __COVERITY__
// fileno on a null FILE pointer either crashes or returns an error.
// Disable Coverity because this is intentional.
EXPECT_DEATH_IF_SUPPORTED({
try {
f.fileno();
} catch (fmt::SystemError) {
} catch (const fmt::system_error&) {
std::exit(1);
}
}, "");
#endif
f = open_buffered_file();
EXPECT_TRUE(f.fileno() != -1);
File copy = File::dup(f.fileno());
file copy = file::dup(f.fileno());
EXPECT_READ(copy, FILE_CONTENT);
}
TEST(FileTest, DefaultCtor) {
File f;
file f;
EXPECT_EQ(-1, f.descriptor());
}
@@ -193,64 +173,64 @@ TEST(FileTest, OpenBufferedFileInCtor) {
FILE *fp = safe_fopen("test-file", "w");
std::fputs(FILE_CONTENT, fp);
std::fclose(fp);
File f("test-file", File::RDONLY);
file f("test-file", file::RDONLY);
ASSERT_TRUE(isopen(f.descriptor()));
}
TEST(FileTest, OpenBufferedFileError) {
EXPECT_SYSTEM_ERROR(File("nonexistent", File::RDONLY),
EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY),
ENOENT, "cannot open file nonexistent");
}
TEST(FileTest, MoveCtor) {
File f = open_file();
file f = open_file();
int fd = f.descriptor();
EXPECT_NE(-1, fd);
File f2(std::move(f));
file f2(std::move(f));
EXPECT_EQ(fd, f2.descriptor());
EXPECT_EQ(-1, f.descriptor());
}
TEST(FileTest, MoveAssignment) {
File f = open_file();
file f = open_file();
int fd = f.descriptor();
EXPECT_NE(-1, fd);
File f2;
file f2;
f2 = std::move(f);
EXPECT_EQ(fd, f2.descriptor());
EXPECT_EQ(-1, f.descriptor());
}
TEST(FileTest, MoveAssignmentClosesFile) {
File f = open_file();
File f2 = open_file();
file f = open_file();
file f2 = open_file();
int old_fd = f2.descriptor();
f2 = std::move(f);
EXPECT_TRUE(isclosed(old_fd));
}
File OpenBufferedFile(int &fd) {
File f = open_file();
static file OpenBufferedFile(int &fd) {
file f = open_file();
fd = f.descriptor();
return f;
}
TEST(FileTest, MoveFromTemporaryInCtor) {
int fd = 0xdead;
File f(OpenBufferedFile(fd));
file f(OpenBufferedFile(fd));
EXPECT_EQ(fd, f.descriptor());
}
TEST(FileTest, MoveFromTemporaryInAssignment) {
int fd = 0xdead;
File f;
file f;
f = OpenBufferedFile(fd);
EXPECT_EQ(fd, f.descriptor());
}
TEST(FileTest, MoveFromTemporaryInAssignmentClosesFile) {
int fd = 0xdead;
File f = open_file();
file f = open_file();
int old_fd = f.descriptor();
f = OpenBufferedFile(fd);
EXPECT_TRUE(isclosed(old_fd));
@@ -259,26 +239,26 @@ TEST(FileTest, MoveFromTemporaryInAssignmentClosesFile) {
TEST(FileTest, CloseFileInDtor) {
int fd = 0;
{
File f = open_file();
file f = open_file();
fd = f.descriptor();
}
EXPECT_TRUE(isclosed(fd));
}
TEST(FileTest, CloseErrorInDtor) {
scoped_ptr<File> f(new File(open_file()));
scoped_ptr<file> f(new file(open_file()));
EXPECT_WRITE(stderr, {
// The close function must be called inside EXPECT_WRITE, otherwise
// the system may recycle closed file descriptor when redirecting the
// output in EXPECT_STDERR and the second close will break output
// redirection.
FMT_POSIX(close(f->descriptor()));
SUPPRESS_ASSERT(f.reset());
SUPPRESS_ASSERT(f.reset(nullptr));
}, format_system_error(EBADF, "cannot close file") + "\n");
}
TEST(FileTest, Close) {
File f = open_file();
file f = open_file();
int fd = f.descriptor();
f.close();
EXPECT_EQ(-1, f.descriptor());
@@ -286,19 +266,19 @@ TEST(FileTest, Close) {
}
TEST(FileTest, CloseError) {
File f = open_file();
file f = open_file();
FMT_POSIX(close(f.descriptor()));
EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
EXPECT_EQ(-1, f.descriptor());
}
TEST(FileTest, Read) {
File f = open_file();
file f = open_file();
EXPECT_READ(f, FILE_CONTENT);
}
TEST(FileTest, ReadError) {
File f("test-file", File::WRONLY);
file f("test-file", file::WRONLY);
char buf;
// We intentionally read from a file opened in the write-only mode to
// cause error.
@@ -306,23 +286,23 @@ TEST(FileTest, ReadError) {
}
TEST(FileTest, Write) {
File read_end, write_end;
File::pipe(read_end, write_end);
file read_end, write_end;
file::pipe(read_end, write_end);
write(write_end, "test");
write_end.close();
EXPECT_READ(read_end, "test");
}
TEST(FileTest, WriteError) {
File f("test-file", File::RDONLY);
file f("test-file", file::RDONLY);
// We intentionally write to a file opened in the read-only mode to
// cause error.
EXPECT_SYSTEM_ERROR(f.write(" ", 1), EBADF, "cannot write to file");
}
TEST(FileTest, Dup) {
File f = open_file();
File copy = File::dup(f.descriptor());
file f = open_file();
file copy = file::dup(f.descriptor());
EXPECT_NE(f.descriptor(), copy.descriptor());
EXPECT_EQ(FILE_CONTENT, read(copy, std::strlen(FILE_CONTENT)));
}
@@ -330,29 +310,29 @@ TEST(FileTest, Dup) {
#ifndef __COVERITY__
TEST(FileTest, DupError) {
int value = -1;
EXPECT_SYSTEM_ERROR_NOASSERT(File::dup(value),
EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value),
EBADF, "cannot duplicate file descriptor -1");
}
#endif
TEST(FileTest, Dup2) {
File f = open_file();
File copy = open_file();
file f = open_file();
file copy = open_file();
f.dup2(copy.descriptor());
EXPECT_NE(f.descriptor(), copy.descriptor());
EXPECT_READ(copy, FILE_CONTENT);
}
TEST(FileTest, Dup2Error) {
File f = open_file();
file f = open_file();
EXPECT_SYSTEM_ERROR_NOASSERT(f.dup2(-1), EBADF,
fmt::format("cannot duplicate file descriptor {} to -1", f.descriptor()));
}
TEST(FileTest, Dup2NoExcept) {
File f = open_file();
File copy = open_file();
ErrorCode ec;
file f = open_file();
file copy = open_file();
error_code ec;
f.dup2(copy.descriptor(), ec);
EXPECT_EQ(0, ec.get());
EXPECT_NE(f.descriptor(), copy.descriptor());
@@ -360,15 +340,15 @@ TEST(FileTest, Dup2NoExcept) {
}
TEST(FileTest, Dup2NoExceptError) {
File f = open_file();
ErrorCode ec;
file f = open_file();
error_code ec;
SUPPRESS_ASSERT(f.dup2(-1, ec));
EXPECT_EQ(EBADF, ec.get());
}
TEST(FileTest, Pipe) {
File read_end, write_end;
File::pipe(read_end, write_end);
file read_end, write_end;
file::pipe(read_end, write_end);
EXPECT_NE(-1, read_end.descriptor());
EXPECT_NE(-1, write_end.descriptor());
write(write_end, "test");
@@ -376,14 +356,14 @@ TEST(FileTest, Pipe) {
}
TEST(FileTest, Fdopen) {
File read_end, write_end;
File::pipe(read_end, write_end);
file read_end, write_end;
file::pipe(read_end, write_end);
int read_fd = read_end.descriptor();
EXPECT_EQ(read_fd, FMT_POSIX(fileno(read_end.fdopen("r").get())));
}
TEST(FileTest, FdopenError) {
File f;
file f;
EXPECT_SYSTEM_ERROR_NOASSERT(
f.fdopen("r"), EBADF, "cannot associate stream with file descriptor");
}

View File

@@ -1,51 +1,37 @@
/*
printf tests.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - printf tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include <cctype>
#include <climits>
#include <cstring>
#include "fmt/core.h"
#include "fmt/printf.h"
#include "fmt/format.h"
#include "gtest-extra.h"
#include "util.h"
using fmt::format;
using fmt::FormatError;
using fmt::format_error;
const unsigned BIG_NUM = INT_MAX + 1u;
// Makes format string argument positional.
std::string make_positional(fmt::StringRef format) {
std::string s(format.to_string());
static std::string make_positional(fmt::string_view format) {
std::string s(format.data(), format.size());
s.replace(s.find('%'), 1, "%1$");
return s;
}
static std::wstring make_positional(fmt::wstring_view format) {
std::wstring s(format.data(), format.size());
s.replace(s.find(L'%'), 1, L"%1$");
return s;
}
#define EXPECT_PRINTF(expected_output, format, arg) \
EXPECT_EQ(expected_output, fmt::sprintf(format, arg)) \
<< "format: " << format; \
@@ -53,6 +39,7 @@ std::string make_positional(fmt::StringRef format) {
TEST(PrintfTest, NoArgs) {
EXPECT_EQ("test", fmt::sprintf("test"));
EXPECT_EQ(L"test", fmt::sprintf(L"test"));
}
TEST(PrintfTest, Escape) {
@@ -61,6 +48,11 @@ TEST(PrintfTest, Escape) {
EXPECT_EQ("% after", fmt::sprintf("%% after"));
EXPECT_EQ("before % after", fmt::sprintf("before %% after"));
EXPECT_EQ("%s", fmt::sprintf("%%s"));
EXPECT_EQ(L"%", fmt::sprintf(L"%%"));
EXPECT_EQ(L"before %", fmt::sprintf(L"before %%"));
EXPECT_EQ(L"% after", fmt::sprintf(L"%% after"));
EXPECT_EQ(L"before % after", fmt::sprintf(L"before %% after"));
EXPECT_EQ(L"%s", fmt::sprintf(L"%%s"));
}
TEST(PrintfTest, PositionalArgs) {
@@ -80,45 +72,45 @@ TEST(PrintfTest, AutomaticArgIndexing) {
TEST(PrintfTest, NumberIsTooBigInArgIndex) {
EXPECT_THROW_MSG(fmt::sprintf(format("%{}$", BIG_NUM)),
FormatError, "number is too big");
format_error, "number is too big");
EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", BIG_NUM)),
FormatError, "number is too big");
format_error, "number is too big");
}
TEST(PrintfTest, SwitchArgIndexing) {
EXPECT_THROW_MSG(fmt::sprintf("%1$d%", 1, 2),
FormatError, "invalid format string");
format_error, "cannot switch from manual to automatic argument indexing");
EXPECT_THROW_MSG(fmt::sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
FormatError, "number is too big");
format_error, "number is too big");
EXPECT_THROW_MSG(fmt::sprintf("%1$d%d", 1, 2),
FormatError, "cannot switch from manual to automatic argument indexing");
format_error, "cannot switch from manual to automatic argument indexing");
EXPECT_THROW_MSG(fmt::sprintf("%d%1$", 1, 2),
FormatError, "invalid format string");
format_error, "cannot switch from automatic to manual argument indexing");
EXPECT_THROW_MSG(fmt::sprintf(format("%d%{}$d", BIG_NUM), 1, 2),
FormatError, "number is too big");
format_error, "number is too big");
EXPECT_THROW_MSG(fmt::sprintf("%d%1$d", 1, 2),
FormatError, "cannot switch from automatic to manual argument indexing");
format_error, "cannot switch from automatic to manual argument indexing");
// Indexing errors override width errors.
EXPECT_THROW_MSG(fmt::sprintf(format("%d%1${}d", BIG_NUM), 1, 2),
FormatError, "number is too big");
format_error, "number is too big");
EXPECT_THROW_MSG(fmt::sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
FormatError, "number is too big");
format_error, "number is too big");
}
TEST(PrintfTest, InvalidArgIndex) {
EXPECT_THROW_MSG(fmt::sprintf("%0$d", 42), FormatError,
EXPECT_THROW_MSG(fmt::sprintf("%0$d", 42), format_error,
"argument index out of range");
EXPECT_THROW_MSG(fmt::sprintf("%2$d", 42), FormatError,
EXPECT_THROW_MSG(fmt::sprintf("%2$d", 42), format_error,
"argument index out of range");
EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", INT_MAX), 42),
FormatError, "argument index out of range");
format_error, "argument index out of range");
EXPECT_THROW_MSG(fmt::sprintf("%2$", 42),
FormatError, "invalid format string");
format_error, "argument index out of range");
EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", BIG_NUM), 42),
FormatError, "number is too big");
format_error, "number is too big");
}
TEST(PrintfTest, DefaultAlignRight) {
@@ -137,7 +129,7 @@ TEST(PrintfTest, ZeroFlag) {
EXPECT_PRINTF("+00042", "%00+6d", 42);
// '0' flag is ignored for non-numeric types.
EXPECT_PRINTF(" x", "%05c", 'x');
EXPECT_PRINTF("0000x", "%05c", 'x');
}
TEST(PrintfTest, PlusFlag) {
@@ -202,27 +194,25 @@ TEST(PrintfTest, HashFlag) {
TEST(PrintfTest, Width) {
EXPECT_PRINTF(" abc", "%5s", "abc");
EXPECT_PRINTF(" -42", "%5s", "-42");
EXPECT_PRINTF(" 0.123456", "%10s", 0.123456);
// Width cannot be specified twice.
EXPECT_THROW_MSG(fmt::sprintf("%5-5d", 42), FormatError,
"unknown format code '-' for integer");
EXPECT_THROW_MSG(fmt::sprintf("%5-5d", 42), format_error,
"invalid type specifier");
EXPECT_THROW_MSG(fmt::sprintf(format("%{}d", BIG_NUM), 42),
FormatError, "number is too big");
format_error, "number is too big");
EXPECT_THROW_MSG(fmt::sprintf(format("%1${}d", BIG_NUM), 42),
FormatError, "number is too big");
format_error, "number is too big");
}
TEST(PrintfTest, DynamicWidth) {
EXPECT_EQ(" 42", fmt::sprintf("%*d", 5, 42));
EXPECT_EQ("42 ", fmt::sprintf("%*d", -5, 42));
EXPECT_THROW_MSG(fmt::sprintf("%*d", 5.0, 42), FormatError,
EXPECT_THROW_MSG(fmt::sprintf("%*d", 5.0, 42), format_error,
"width is not integer");
EXPECT_THROW_MSG(fmt::sprintf("%*d"), FormatError,
EXPECT_THROW_MSG(fmt::sprintf("%*d"), format_error,
"argument index out of range");
EXPECT_THROW_MSG(fmt::sprintf("%*d", BIG_NUM, 42), FormatError,
EXPECT_THROW_MSG(fmt::sprintf("%*d", BIG_NUM, 42), format_error,
"number is too big");
}
@@ -265,41 +255,41 @@ TEST(PrintfTest, IgnorePrecisionForNonNumericArg) {
TEST(PrintfTest, DynamicPrecision) {
EXPECT_EQ("00042", fmt::sprintf("%.*d", 5, 42));
EXPECT_EQ("42", fmt::sprintf("%.*d", -5, 42));
EXPECT_THROW_MSG(fmt::sprintf("%.*d", 5.0, 42), FormatError,
EXPECT_THROW_MSG(fmt::sprintf("%.*d", 5.0, 42), format_error,
"precision is not integer");
EXPECT_THROW_MSG(fmt::sprintf("%.*d"), FormatError,
EXPECT_THROW_MSG(fmt::sprintf("%.*d"), format_error,
"argument index out of range");
EXPECT_THROW_MSG(fmt::sprintf("%.*d", BIG_NUM, 42), FormatError,
EXPECT_THROW_MSG(fmt::sprintf("%.*d", BIG_NUM, 42), format_error,
"number is too big");
if (sizeof(fmt::LongLong) != sizeof(int)) {
fmt::LongLong prec = static_cast<fmt::LongLong>(INT_MIN) - 1;
EXPECT_THROW_MSG(fmt::sprintf("%.*d", prec, 42), FormatError,
if (sizeof(long long) != sizeof(int)) {
long long prec = static_cast<long long>(INT_MIN) - 1;
EXPECT_THROW_MSG(fmt::sprintf("%.*d", prec, 42), format_error,
"number is too big");
}
}
template <typename T>
struct MakeSigned { typedef T Type; };
struct make_signed { typedef T type; };
#define SPECIALIZE_MAKE_SIGNED(T, S) \
template <> \
struct MakeSigned<T> { typedef S Type; }
struct make_signed<T> { typedef S type; }
SPECIALIZE_MAKE_SIGNED(char, signed char);
SPECIALIZE_MAKE_SIGNED(unsigned char, signed char);
SPECIALIZE_MAKE_SIGNED(unsigned short, short);
SPECIALIZE_MAKE_SIGNED(unsigned, int);
SPECIALIZE_MAKE_SIGNED(unsigned long, long);
SPECIALIZE_MAKE_SIGNED(fmt::ULongLong, fmt::LongLong);
SPECIALIZE_MAKE_SIGNED(unsigned long long, long long);
// Test length format specifier ``length_spec``.
template <typename T, typename U>
void TestLength(const char *length_spec, U value) {
fmt::LongLong signed_value = 0;
fmt::ULongLong unsigned_value = 0;
long long signed_value = 0;
unsigned long long unsigned_value = 0;
// Apply integer promotion to the argument.
using std::numeric_limits;
fmt::ULongLong max = numeric_limits<U>::max();
unsigned long long max = numeric_limits<U>::max();
using fmt::internal::const_check;
if (const_check(max <= static_cast<unsigned>(numeric_limits<int>::max()))) {
signed_value = static_cast<int>(value);
@@ -308,13 +298,13 @@ void TestLength(const char *length_spec, U value) {
signed_value = static_cast<unsigned>(value);
unsigned_value = static_cast<unsigned>(value);
}
using fmt::internal::MakeUnsigned;
if (sizeof(U) <= sizeof(int) && sizeof(int) < sizeof(T)) {
signed_value = static_cast<fmt::LongLong>(value);
unsigned_value = static_cast<typename MakeUnsigned<unsigned>::Type>(value);
signed_value = static_cast<long long>(value);
unsigned_value =
static_cast<typename std::make_unsigned<unsigned>::type>(value);
} else {
signed_value = static_cast<typename MakeSigned<T>::Type>(value);
unsigned_value = static_cast<typename MakeUnsigned<T>::Type>(value);
signed_value = static_cast<typename make_signed<T>::type>(value);
unsigned_value = static_cast<typename std::make_unsigned<T>::type>(value);
}
std::ostringstream os;
os << signed_value;
@@ -341,20 +331,20 @@ void TestLength(const char *length_spec) {
TestLength<T>(length_spec, -42);
TestLength<T>(length_spec, min);
TestLength<T>(length_spec, max);
TestLength<T>(length_spec, fmt::LongLong(min) - 1);
fmt::ULongLong long_long_max = std::numeric_limits<fmt::LongLong>::max();
if (static_cast<fmt::ULongLong>(max) < long_long_max)
TestLength<T>(length_spec, fmt::LongLong(max) + 1);
TestLength<T>(length_spec, static_cast<long long>(min) - 1);
unsigned long long long_long_max = std::numeric_limits<long long>::max();
if (static_cast<unsigned long long>(max) < long_long_max)
TestLength<T>(length_spec, static_cast<long long>(max) + 1);
TestLength<T>(length_spec, std::numeric_limits<short>::min());
TestLength<T>(length_spec, std::numeric_limits<unsigned short>::max());
TestLength<T>(length_spec, std::numeric_limits<int>::min());
TestLength<T>(length_spec, std::numeric_limits<int>::max());
TestLength<T>(length_spec, std::numeric_limits<unsigned>::min());
TestLength<T>(length_spec, std::numeric_limits<unsigned>::max());
TestLength<T>(length_spec, std::numeric_limits<fmt::LongLong>::min());
TestLength<T>(length_spec, std::numeric_limits<fmt::LongLong>::max());
TestLength<T>(length_spec, std::numeric_limits<fmt::ULongLong>::min());
TestLength<T>(length_spec, std::numeric_limits<fmt::ULongLong>::max());
TestLength<T>(length_spec, std::numeric_limits<long long>::min());
TestLength<T>(length_spec, std::numeric_limits<long long>::max());
TestLength<T>(length_spec, std::numeric_limits<unsigned long long>::min());
TestLength<T>(length_spec, std::numeric_limits<unsigned long long>::max());
}
TEST(PrintfTest, Length) {
@@ -365,8 +355,8 @@ TEST(PrintfTest, Length) {
TestLength<unsigned short>("h");
TestLength<long>("l");
TestLength<unsigned long>("l");
TestLength<fmt::LongLong>("ll");
TestLength<fmt::ULongLong>("ll");
TestLength<long long>("ll");
TestLength<unsigned long long>("ll");
TestLength<intmax_t>("j");
TestLength<std::size_t>("z");
TestLength<std::ptrdiff_t>("t");
@@ -383,19 +373,17 @@ TEST(PrintfTest, Bool) {
TEST(PrintfTest, Int) {
EXPECT_PRINTF("-42", "%d", -42);
EXPECT_PRINTF("-42", "%i", -42);
EXPECT_PRINTF("-42", "%s", -42);
unsigned u = 0 - 42u;
EXPECT_PRINTF(fmt::format("{}", u), "%u", -42);
EXPECT_PRINTF(fmt::format("{:o}", u), "%o", -42);
EXPECT_PRINTF(fmt::format("{:x}", u), "%x", -42);
EXPECT_PRINTF(fmt::format("{:X}", u), "%X", -42);
EXPECT_PRINTF(fmt::format("{}", u), "%s", u);
}
TEST(PrintfTest, LongLong) {
TEST(PrintfTest, long_long) {
// fmt::printf allows passing long long arguments to %d without length
// specifiers.
fmt::LongLong max = std::numeric_limits<fmt::LongLong>::max();
long long max = std::numeric_limits<long long>::max();
EXPECT_PRINTF(fmt::format("{}", max), "%d", max);
}
@@ -405,7 +393,6 @@ TEST(PrintfTest, Float) {
EXPECT_PRINTF("392.6", "%.1f", 392.65);
EXPECT_PRINTF("393", "%.f", 392.65);
EXPECT_PRINTF("392.650000", "%F", 392.65);
EXPECT_PRINTF("392.65", "%s", 392.65);
char buffer[BUFFER_SIZE];
safe_sprintf(buffer, "%e", 392.65);
EXPECT_PRINTF(buffer, "%e", 392.65);
@@ -423,43 +410,52 @@ TEST(PrintfTest, Inf) {
double inf = std::numeric_limits<double>::infinity();
for (const char* type = "fega"; *type; ++type) {
EXPECT_PRINTF("inf", fmt::format("%{}", *type), inf);
char upper = std::toupper(*type);
char upper = static_cast<char>(std::toupper(*type));
EXPECT_PRINTF("INF", fmt::format("%{}", upper), inf);
}
}
TEST(PrintfTest, Char) {
EXPECT_PRINTF("x", "%c", 'x');
EXPECT_PRINTF("x", "%s", 'x');
int max = std::numeric_limits<int>::max();
EXPECT_PRINTF(fmt::format("{}", static_cast<char>(max)), "%c", max);
//EXPECT_PRINTF("x", "%lc", L'x');
// TODO: test wchar_t
EXPECT_PRINTF(L"x", L"%c", L'x');
EXPECT_PRINTF(fmt::format(L"{}", static_cast<wchar_t>(max)), L"%c", max);
}
TEST(PrintfTest, String) {
EXPECT_PRINTF("abc", "%s", "abc");
const char *null_str = 0;
const char *null_str = nullptr;
EXPECT_PRINTF("(null)", "%s", null_str);
EXPECT_PRINTF(" (null)", "%10s", null_str);
// TODO: wide string
EXPECT_PRINTF(L"abc", L"%s", L"abc");
const wchar_t *null_wstr = nullptr;
EXPECT_PRINTF(L"(null)", L"%s", null_wstr);
EXPECT_PRINTF(L" (null)", L"%10s", null_wstr);
}
TEST(PrintfTest, Pointer) {
int n;
void *p = &n;
EXPECT_PRINTF(fmt::format("{}", p), "%p", p);
EXPECT_PRINTF(fmt::format("{}", p), "%s", p);
p = 0;
p = nullptr;
EXPECT_PRINTF("(nil)", "%p", p);
EXPECT_PRINTF(" (nil)", "%10p", p);
EXPECT_PRINTF("(nil)", "%s", p);
EXPECT_PRINTF(" (nil)", "%10s", p);
const char *s = "test";
EXPECT_PRINTF(fmt::format("{:p}", s), "%p", s);
const char *null_str = 0;
const char *null_str = nullptr;
EXPECT_PRINTF("(nil)", "%p", null_str);
EXPECT_PRINTF("(null)", "%s", null_str);
p = &n;
EXPECT_PRINTF(fmt::format(L"{}", p), L"%p", p);
p = nullptr;
EXPECT_PRINTF(L"(nil)", L"%p", p);
EXPECT_PRINTF(L" (nil)", L"%10p", p);
const wchar_t *w = L"test";
EXPECT_PRINTF(fmt::format(L"{:p}", w), L"%p", w);
const wchar_t *null_wstr = nullptr;
EXPECT_PRINTF(L"(nil)", L"%p", null_wstr);
}
TEST(PrintfTest, Location) {
@@ -482,8 +478,8 @@ TEST(PrintfTest, Examples) {
}
TEST(PrintfTest, PrintfError) {
fmt::File read_end, write_end;
fmt::File::pipe(read_end, write_end);
fmt::file read_end, write_end;
fmt::file::pipe(read_end, write_end);
int result = fmt::fprintf(read_end.fdopen("r").get(), "test");
EXPECT_LT(result, 0);
}
@@ -503,9 +499,3 @@ TEST(PrintfTest, OStream) {
EXPECT_EQ("Don't panic!", os.str());
EXPECT_EQ(12, ret);
}
TEST(PrintfTest, Writer) {
fmt::MemoryWriter writer;
printf(writer, "%d", 42);
EXPECT_EQ("42", writer.str());
}

88
test/ranges-test.cc Normal file
View File

@@ -0,0 +1,88 @@
// Formatting library for C++ - the core API
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
//
// Copyright (c) 2018 - present, Remotion (Igor Schulz)
// All Rights Reserved
// {fmt} support for ranges, containers and types tuple interface.
#include "fmt/ranges.h"
/// Check if 'if constexpr' is supported.
#if (__cplusplus > 201402L) || \
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
#include "gtest.h"
#include <vector>
#include <array>
#include <map>
#include <string>
TEST(RangesTest, FormatVector) {
std::vector<int32_t> iv{1, 2, 3, 5, 7, 11};
auto ivf = fmt::format("{}", iv);
EXPECT_EQ("{1, 2, 3, 5, 7, 11}", ivf);
}
TEST(RangesTest, FormatVector2) {
std::vector<std::vector<int32_t>> ivv{{1, 2}, {3, 5}, {7, 11}};
auto ivf = fmt::format("{}", ivv);
EXPECT_EQ("{{1, 2}, {3, 5}, {7, 11}}", ivf);
}
TEST(RangesTest, FormatMap) {
std::map<std::string, int32_t> simap{{"one", 1}, {"two", 2}};
EXPECT_EQ("{(\"one\", 1), (\"two\", 2)}", fmt::format("{}", simap));
}
TEST(RangesTest, FormatPair) {
std::pair<int64_t, float> pa1{42, 3.14159265358979f};
EXPECT_EQ("(42, 3.14159)", fmt::format("{}", pa1));
}
TEST(RangesTest, FormatTuple) {
std::tuple<int64_t, float, std::string, char> tu1{42, 3.14159265358979f,
"this is tuple", 'i'};
EXPECT_EQ("(42, 3.14159, \"this is tuple\", 'i')", fmt::format("{}", tu1));
}
struct my_struct {
int32_t i;
std::string str; // can throw
template <std::size_t N>
decltype(auto) get() const noexcept {
if constexpr (N == 0)
return i;
else if constexpr (N == 1)
return fmt::string_view{str};
}
};
template <std::size_t N>
decltype(auto) get(const my_struct& s) noexcept {
return s.get<N>();
}
namespace std {
template <>
struct tuple_size<my_struct> : std::integral_constant<std::size_t, 2> {};
template <std::size_t N>
struct tuple_element<N, my_struct> {
using type = decltype(std::declval<my_struct>().get<N>());
};
} // namespace std
TEST(RangesTest, FormatStruct) {
my_struct mst{13, "my struct"};
EXPECT_EQ("(13, \"my struct\")", fmt::format("{}", mst));
}
#endif // (__cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >
// 201402L && _MSC_VER >= 1910)

View File

@@ -1,84 +0,0 @@
/*
Tests of string utilities
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#include "fmt/string.h"
#include "gtest/gtest.h"
using fmt::internal::StringBuffer;
TEST(StringBufferTest, Empty) {
StringBuffer<char> buffer;
EXPECT_EQ(0u, buffer.size());
EXPECT_EQ(0u, buffer.capacity());
std::string data;
// std::string may have initial capacity.
std::size_t capacity = data.capacity();
buffer.move_to(data);
EXPECT_EQ("", data);
EXPECT_EQ(capacity, data.capacity());
}
TEST(StringBufferTest, Reserve) {
StringBuffer<char> buffer;
std::size_t capacity = std::string().capacity() + 10;
buffer.reserve(capacity);
EXPECT_EQ(0u, buffer.size());
EXPECT_EQ(capacity, buffer.capacity());
std::string data;
buffer.move_to(data);
EXPECT_EQ("", data);
}
TEST(StringBufferTest, Resize) {
StringBuffer<char> buffer;
std::size_t size = std::string().capacity() + 10;
buffer.resize(size);
EXPECT_EQ(size, buffer.size());
EXPECT_EQ(size, buffer.capacity());
std::string data;
buffer.move_to(data);
EXPECT_EQ(size, data.size());
}
TEST(StringBufferTest, MoveTo) {
StringBuffer<char> buffer;
std::size_t size = std::string().capacity() + 10;
buffer.resize(size);
const char *p = &buffer[0];
std::string data;
buffer.move_to(data);
EXPECT_EQ(p, &data[0]);
EXPECT_EQ(0u, buffer.size());
EXPECT_EQ(0u, buffer.capacity());
}
TEST(StringWriterTest, MoveTo) {
fmt::StringWriter out;
out << "The answer is " << 42 << "\n";
std::string s;
out.move_to(s);
EXPECT_EQ("The answer is 42\n", s);
EXPECT_EQ(0u, out.size());
}
TEST(StringWriterTest, WString) {
fmt::WStringWriter out;
out << "The answer is " << 42 << "\n";
std::wstring s;
out.move_to(s);
EXPECT_EQ(L"The answer is 42\n", s);
}
TEST(StringTest, ToString) {
EXPECT_EQ("42", fmt::to_string(42));
}
TEST(StringTest, ToWString) {
EXPECT_EQ(L"42", fmt::to_wstring(42));
}

View File

@@ -1,29 +1,9 @@
/*
Test version of FMT_ASSERT
Copyright (c) 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - test version of FMT_ASSERT
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_TEST_ASSERT_H
#define FMT_TEST_ASSERT_H

View File

@@ -1,32 +1,12 @@
/*
Test main function.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - test main function.
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include <cstdlib>
#include <gtest/gtest.h>
#include "gtest.h"
#ifdef _WIN32
# include <windows.h>

View File

@@ -1,16 +1,15 @@
/*
Time formatting tests
// Formatting library for C++ - time formatting tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#ifdef WIN32
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "gmock/gmock.h"
#include "gmock.h"
#include "fmt/time.h"
TEST(TimeTest, Format) {
@@ -27,7 +26,7 @@ TEST(TimeTest, GrowBuffer) {
for (int i = 0; i < 30; ++i)
s += "%c";
s += "}\n";
std::time_t t = std::time(0);
std::time_t t = std::time(nullptr);
fmt::format(s, *std::localtime(&t));
}
@@ -35,7 +34,7 @@ TEST(TimeTest, EmptyResult) {
EXPECT_EQ("", fmt::format("{}", std::tm()));
}
bool EqualTime(const std::tm &lhs, const std::tm &rhs) {
static bool EqualTime(const std::tm &lhs, const std::tm &rhs) {
return lhs.tm_sec == rhs.tm_sec &&
lhs.tm_min == rhs.tm_min &&
lhs.tm_hour == rhs.tm_hour &&
@@ -48,13 +47,13 @@ bool EqualTime(const std::tm &lhs, const std::tm &rhs) {
}
TEST(TimeTest, LocalTime) {
std::time_t t = std::time(0);
std::time_t t = std::time(nullptr);
std::tm tm = *std::localtime(&t);
EXPECT_TRUE(EqualTime(tm, fmt::localtime(t)));
}
TEST(TimeTest, GMTime) {
std::time_t t = std::time(0);
std::time_t t = std::time(nullptr);
std::tm tm = *std::gmtime(&t);
EXPECT_TRUE(EqualTime(tm, fmt::gmtime(t)));
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,29 +1,9 @@
/*
Test utilities.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - test utilities
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "util.h"
#include <cstring>
@@ -52,12 +32,12 @@ std::string get_system_error(int error_code) {
const char *const FILE_CONTENT = "Don't panic!";
fmt::BufferedFile open_buffered_file(FILE **fp) {
fmt::File read_end, write_end;
fmt::File::pipe(read_end, write_end);
fmt::buffered_file open_buffered_file(FILE **fp) {
fmt::file read_end, write_end;
fmt::file::pipe(read_end, write_end);
write_end.write(FILE_CONTENT, std::strlen(FILE_CONTENT));
write_end.close();
fmt::BufferedFile f = read_end.fdopen("r");
fmt::buffered_file f = read_end.fdopen("r");
if (fp)
*fp = f.get();
return f;

View File

@@ -1,29 +1,9 @@
/*
Test utilities.
Copyright (c) 2012-2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Formatting library for C++ - test utilities
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include <cstdarg>
#include <cstdio>
@@ -55,7 +35,7 @@ std::string get_system_error(int error_code);
extern const char *const FILE_CONTENT;
// Opens a buffered file for reading.
fmt::BufferedFile open_buffered_file(FILE **fp = 0);
fmt::buffered_file open_buffered_file(FILE **fp = nullptr);
inline FILE *safe_fopen(const char *filename, const char *mode) {
#if defined(_WIN32) && !defined(__MINGW32__)