Compare commits

...

2368 Commits

Author SHA1 Message Date
e57ca2e368 Update version 2023-08-12 07:18:59 -07:00
4c56612c67 Update changelog 2023-08-12 07:18:12 -07:00
e1acd5f4d9 Bump version 2023-08-12 06:52:15 -07:00
6ffee2f752 Handle new rst nodes 2023-08-12 06:51:40 -07:00
ee475d6409 Update changelog 2023-08-07 15:12:34 -07:00
ecc9141259 Update changelog 2023-08-07 14:41:53 -07:00
d424862319 Fix fixed precision handling during rounding in long double 2023-08-07 13:56:53 -07:00
3c1b3337de Update changelog 2023-08-07 11:39:30 -07:00
35fb69ebe0 Update changelog 2023-08-07 10:30:52 -07:00
f92be35c09 Update changelog 2023-08-07 09:44:43 -07:00
7a2f6ac210 Fix a comment 2023-08-07 09:33:45 -07:00
744ff55549 Fix docs 2023-08-07 08:40:41 -07:00
70ae48b005 Update changelog 2023-08-07 08:38:17 -07:00
ebb10347c4 Merge branch 'master' of github.com:fmtlib/fmt 2023-08-07 08:18:13 -07:00
1005720169 Clarify that visit_format_arg is deprecated 2023-08-07 08:17:55 -07:00
aeb6ad4dd0 Added formatter for bit_reference-like types (#3570)
* Add test for std::vector<bool>::reference

Co-authored-by: Felix <felix-antoine.constantin@polymtl.ca>
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

* Add test for std::bitset<N>::reference

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

* Add test for const std::bitset<N>::reference and const std::vector<bool>::reference

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

* Add bit_reference-like formatter

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

* Use std::addressof

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

---------

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
Co-authored-by: Felix <felix-antoine.constantin@polymtl.ca>
2023-08-06 11:36:30 -07:00
96d1fa22d4 Update changelog 2023-08-05 10:00:27 -07:00
8a4bec5cf5 fix ambiguous formatter lookup for flat_set (#3561) 2023-07-31 09:26:33 -07:00
eacd51c249 cmake: fix FMT_PKGCONFIG_DIR path (#3563) 2023-07-31 08:11:56 -07:00
757564f5cd add missing inline specifier (#3552) 2023-07-27 12:12:00 -07:00
f4214ae8dd Use the U literal for unsigned integer constants. (#3549)
Fix MSVC Error C2398 Element '1': conversion from 'int' to 'const uint32_t' requires a narrowing conversion.
2023-07-27 11:43:00 -07:00
aecf80d304 Update a comment 2023-07-26 15:10:12 -07:00
503d49286d expose detail::throw_format_error (#3551)
This enables to only #include <fmt/core.h> when defining formatters.
2023-07-26 13:21:38 -07:00
4f46cb82f3 Remove std::copy usage. (#3550) 2023-07-26 07:27:01 -07:00
3dec65b7fd Use replacement character in path 2023-07-22 09:07:28 -07:00
dbabb305c3 Turn off error-producing NVCC workaround when using c++20 (#3544) 2023-07-21 11:29:15 -07:00
ac0ab8eff3 Improve path formatter 2023-07-20 17:49:12 -07:00
40f35d6f04 Cleanup std formatters 2023-07-20 16:26:27 -07:00
31c2c5679e Cleanup formatters 2023-07-20 15:57:43 -07:00
b2728a3170 Improve path formatter 2023-07-20 15:25:35 -07:00
77e0b0e228 Cleanup chrono formatter 2023-07-20 15:00:59 -07:00
e475859042 Fix overspecified tests 2023-07-20 14:09:22 -07:00
436c131d4c Optimize compiled format_to_n 2023-07-20 12:35:01 -07:00
388bc296b7 Fix fixed formatting of small long doubles 2023-07-20 12:06:05 -07:00
95e1ea5737 Clarify requirement on compiled formatter 2023-07-20 10:24:02 -07:00
fb97cb2318 Suppress a bogus stringop-overflow warning 2023-07-20 09:53:54 -07:00
dd5a9691f9 Clarify that data is not null-terminated 2023-07-20 07:36:30 -07:00
72dc4491ea Fix format_string_checker initialisation order (#3542)
Linter (clang-tidy) complains about uninitialised fields in
format_string_checker since types_ is passed to context_ before being
initialised. Fixes #3541.
2023-07-20 07:30:45 -07:00
9bea6ec04a Don't use deprecated checked_array_iterator 2023-07-20 07:12:06 -07:00
661b23edeb Call parse on empty specs at compile time 2023-07-15 22:20:29 -07:00
8e87d3a8be Fix include 2023-07-15 09:02:19 -07:00
a474916560 Update CMakeLists.txt (#3523) 2023-07-05 06:38:38 -07:00
de4705f84d Trying to improve errors in the unformattable case (#3478) 2023-07-01 06:46:04 -07:00
e4c8cfe38e README: Add link to merged clang-tidy check (#3515)
A much-improved version of the main clang-tidy-fmt check for converting
printf and fprintf has landed in upstream LLVM. It converts to
std::print by default, but can be configured to convert to fmt::print
instead. It makes more sense for the README to point to that version
instead now.
2023-06-30 15:49:36 -07:00
606f85f8b2 Workaround brain-damaged conversions 2023-06-26 16:06:24 -07:00
a331dbfb65 Fix type in assert message. (#3508)
Reviewed all strings in the file and found no other typos.
2023-06-26 11:35:29 -07:00
13156e54bf Revert "add ability to build Apple framework using CMAKE_FRAMEWORK" (#3496)
This reverts commit ae25f7968e.

Co-authored-by: Petr Manek <1252039-petrmanek@users.noreply.gitlab.com>
2023-06-18 20:41:07 -07:00
9158bea1e1 Remove old grisu tests 2023-06-18 18:15:09 +03:00
dd17f89a16 Fix for issue #3492 (#3493)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2023-06-16 02:20:40 -07:00
1daae555b3 Optimize format string compilation 2023-06-15 10:28:23 +03:00
6ad301235f Optimize code unit output in compiled format 2023-06-14 21:13:26 +03:00
8732ad8773 Update docs 2023-06-13 19:24:18 +03:00
5afb1821a9 Update docs 2023-06-13 18:58:15 +03:00
a81135f2c8 Fix a link 2023-06-13 18:39:00 +03:00
dfc34821ad Update docs 2023-06-13 18:33:36 +03:00
0765e7284c Update docs 2023-06-13 18:12:27 +03:00
977d887a4e Suppress a bogus warning 2023-06-13 14:01:46 +03:00
c86fe0b8d3 Give basic_memory_buffer allocator [[no_unique_address]] (#3485)
This allows stateless allocators to take up no space while still avoiding the empty base class optimization.
2023-06-13 01:22:19 -07:00
5dbe0ff954 Bump actions/checkout from 3.5.2 to 3.5.3 (#3486)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.2 to 3.5.3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](8e5e7e5ab8...c85c95e3d7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-12 22:46:54 -07:00
de0757b578 Use FMT_TRY and FMT_CATCH in std.h (#3482)
This naked try-catch block prevents compilation when exceptions are disabled.
2023-06-10 21:28:13 -07:00
8fe893c0ac Update README.rst 2023-06-06 19:56:53 -07:00
0f823df46a Remove detail namespace hack 2023-06-04 15:19:50 -07:00
60fd9941c0 Use correct Char type in std::filesystem::path (#3476)
Godbolt repro:
https://godbolt.org/z/o4bjG6ddo

Co-authored-by: Hans-Martin B. Jensen <haje@eposaudio.com>
2023-06-02 14:12:57 -07:00
8abfc145be Fix MSVC warning in std::chrono::time_point formatter (#3475)
* Fix MSVC warning in std::chrono::time_point formatter

The condition is constexpr causing MSVC level 4 warning:
warning C4127: conditional expression is constant

Changed the code to eliminate the warning

* Use detail::const_check

* Review: revert else condition

---------

Co-authored-by: Hans-Martin B. Jensen <haje@eposaudio.com>
2023-06-02 08:40:34 -07:00
686b3353aa Simplify typeid check 2023-06-01 09:32:44 -07:00
b2106f3639 Tweak comments 2023-05-31 09:52:44 -07:00
35547d6003 Use const_check to silence MSVC warning
The condition is constexpr, so the compiler warns if a runtime check
is used as there's no need to generate code for it.
2023-05-31 09:25:53 -07:00
179c7e5a66 Use typeid() only if it's available
On MSVC it is always available, otherwise it depends on whether
RTTI is enabled.
2023-05-31 09:25:53 -07:00
61fb3a15ff Add VxWorks7 user space and kernel space support (#3467) 2023-05-31 06:35:07 -07:00
bd393456ed Remove FMT_*_DETAIL_NAMESPACE 2023-05-28 07:33:26 -07:00
6be36af0d4 Remove udl_formatter 2023-05-27 17:16:36 -07:00
2a35eeed8a Remove unused data 2023-05-27 10:47:17 -07:00
256a826d63 Consolidate formatters 2023-05-27 09:19:50 -07:00
6369af37d3 Simplify formatters 2023-05-27 09:19:50 -07:00
0b8404918e Remove get_cached_power 2023-05-27 09:19:50 -07:00
171a020c82 Pass correct Char to base format_as formatter (#3457) 2023-05-24 14:50:47 -07:00
d8f04e3995 Simplify ceil 2023-05-24 11:51:34 -07:00
5e988f8dfa Remove is_constant_evaluated() check
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2023-05-24 09:07:12 -07:00
19b17618a9 Make constexpr ceil
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2023-05-24 09:07:12 -07:00
c684a06d51 New CI: macOS 13, Xcode 14.3, C++ 20
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2023-05-24 09:07:12 -07:00
abdb7fdf88 Update api.rst 2023-05-24 06:30:48 -07:00
8b09fe2a0a Fix example for user-defined types in documentation for 10.0.0 (#3461)
* Fix example for user-defined types in documentation for 10.0.0

* Fix the fix
2023-05-24 06:25:51 -07:00
adad18a74d Update ChangeLog.rst 2023-05-23 12:46:26 -07:00
858e528abd Use dragon in constexpr 2023-05-23 06:30:09 -07:00
a54cb108d4 CMake: Do not fail on unknown compiler features (#3453)
If CMake does not know much about a compiler, `target_compile_features` will fail. Issue a warning instead.
2023-05-22 14:17:32 -07:00
ef55d4f52e Suppress a bogus gcc warning 2023-05-22 11:27:20 -07:00
70b6a6fa44 Update README.rst (#3454)
Fixed grammar and punctuation issues.
2023-05-22 10:35:24 -07:00
6fe895410d Remove invalid_arg_index 2023-05-21 19:57:17 -07:00
d0652d225f Create dependabot.yml (#3452)
Signed-off-by: Joyce <joycebrum@google.com>
2023-05-21 06:41:30 -07:00
de8d0171a2 Simplify FMT_FORMAT_AS 2023-05-20 18:28:01 -07:00
7401fe046a Hash pin Github Workflows (#3451)
* hash pin doc.yml

Signed-off-by: Joyce <joycebrum@google.com>

* hash pin linux.yml

Signed-off-by: Joyce <joycebrum@google.com>

* hash pin macos.yml

Signed-off-by: Joyce <joycebrum@google.com>

* hash pin windows.yml

Signed-off-by: Joyce <joycebrum@google.com>

* hash pin github owned cifuzz.yml

Signed-off-by: Joyce <joycebrum@google.com>

---------

Signed-off-by: Joyce <joycebrum@google.com>
2023-05-20 06:33:37 -07:00
08ef0d0842 fix formatter<char*> (#3432) 2023-05-20 06:32:21 -07:00
d60b907f87 Replace mod_inv_25 by explicit value (#3450) 2023-05-18 11:26:19 -07:00
4ce086f731 remove code duplication (#3448)
* remove code duplication

* new interface for remove_trailing_zeros(uint32_t& n, int s = 0)

---------

Co-authored-by: Florimond Collette <4939681+florimondcollette@users.noreply.github.com>
2023-05-18 08:27:57 -07:00
821f8cdb45 Detemplatize printf more 2023-05-17 12:34:12 -07:00
0bf6ed7e1d Cleanup printf 2023-05-17 10:53:25 -07:00
e40e04face Detemplatize printf_arg_formatter 2023-05-17 10:05:46 -07:00
0a1c27281a Detemplatize basic_printf_context 2023-05-17 09:29:20 -07:00
2f605cc896 Deprecate wide printf 2023-05-17 08:58:55 -07:00
1d54499ac0 Apply coding conventions 2023-05-17 08:21:13 -07:00
3c6053c535 Cleanup basic_printf_context 2023-05-17 07:57:53 -07:00
4a392adaa7 Remove basic_printf_parse_context 2023-05-17 07:47:42 -07:00
b14913fae5 FMT_MODULE_EXPORT -> FMT_EXPORT 2023-05-17 07:38:06 -07:00
2117df299c format-inl.h: address implicit int to bool conversion (#3446) 2023-05-17 06:39:20 -07:00
616a493786 Revert Char* formatter removal 2023-05-17 06:11:11 -07:00
9a034b0d55 Always assert in FMT_THROW (#3439) 2023-05-17 06:04:36 -07:00
e0fc0e85e3 Remove unneeded FMT_API 2023-05-16 17:25:20 -07:00
552c43aba9 Improve long formatters 2023-05-14 07:07:36 -07:00
d6846f4ac8 Clarify why byte formatter is in core 2023-05-13 08:04:53 -07:00
aeedac5884 Remove unneeded specialization 2023-05-13 07:46:47 -07:00
eaa6307691 Make hex float test more stable (#3434)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2023-05-13 06:34:33 -07:00
e82bf41a1a Update README.rst 2023-05-12 16:24:47 -07:00
e077396f5a Update docs 2023-05-12 16:10:38 -07:00
861facad0a Fix a typo 2023-05-12 16:08:55 -07:00
75bfe57614 Improve docs 2023-05-12 12:57:01 -07:00
697e76ba30 Don't call init_named_args unnecessarily 2023-05-12 11:53:22 -07:00
a425e0ff3b Cleanup xchar API 2023-05-12 07:05:14 -07:00
c36dd825ba Remove unnecessary forwarding 2023-05-12 06:45:49 -07:00
130b8fcdb9 Reduce template instantiations 2023-05-11 20:18:34 -07:00
a47e8419be Cleanup the core API 2023-05-11 19:07:56 -07:00
ea49c91cd1 Cleanup argument construction 2023-05-11 18:43:39 -07:00
d7592ad8bf Fix time_point formatting for durations with certain ratios (#3430)
* Fix time_point formatting

* Add timestamps_ratios tests
2023-05-11 15:25:21 -07:00
ebfb2e6779 Remove unused alias 2023-05-11 10:51:32 -07:00
5780269d57 Improve API safety 2023-05-11 10:19:56 -07:00
b471192160 Fix a comment 2023-05-11 09:39:53 -07:00
8f18e72df5 Improve API safety 2023-05-11 06:32:58 -07:00
93d7cb12f1 Fix formatting 2023-05-10 16:29:47 -07:00
0e4278717b Remove unused macro 2023-05-10 16:27:16 -07:00
93a30a0746 unicode_to_utf8 -> to_utf8 since both sides of conversion are Unicode 2023-05-10 16:26:02 -07:00
a08196b149 Update ChangeLog.rst 2023-05-10 09:49:39 -07:00
0398ba42ca Update ChangeLog.rst 2023-05-10 09:39:04 -07:00
a0b8a92e3d Update version 2023-05-09 15:55:39 -07:00
5cf2342aa2 Bump version 2023-05-09 15:37:01 -07:00
fe9d39d7cb Update changelog 2023-05-09 14:27:48 -07:00
4c98561979 Update changelog 2023-05-09 14:25:56 -07:00
403b271ed7 Update changelog 2023-05-09 14:20:59 -07:00
2c991e1af6 Update changelog 2023-05-08 14:43:16 -07:00
c984df9815 Remove an unused function from internal class 2023-05-08 13:35:23 -07:00
fbf21ed224 Update changelog 2023-05-08 13:34:29 -07:00
575583144e Update changelog 2023-05-08 11:37:33 -07:00
e7f6888c7a Update changelog 2023-05-08 09:49:39 -07:00
39db2dfd06 Update changelog 2023-05-08 09:41:57 -07:00
9b7829e264 Update changelog 2023-05-08 09:15:07 -07:00
1e0ce567ef Fix formatting of paths containing invalid Unicode 2023-05-07 10:05:15 -07:00
dde8cf3bb7 Unification utf16/utf32 to utf8 conversion
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2023-05-06 08:32:51 -07:00
e84b00e014 Workaround to error: variable 'n' set but not used [-Werror,-Wunused-but-set-variable]
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2023-05-06 08:32:51 -07:00
b12ffea4fb Add filesystem_error test back 2023-05-06 07:49:46 -07:00
f61f15cc5b Suppress a false positive in gcc 2023-05-06 06:54:30 -07:00
192df93d7b modules missing pieces (#3399)
- don't export names from `detail`
- put more headers into the global module fragment
- support MSYS2 and Clang
2023-05-05 10:21:18 -07:00
d8973bf16b Add FMT_STRING for format_to() call (#3413) 2023-05-03 07:58:40 -07:00
d7a8e50cb5 Improve module testing (#3397)
* use the standard `test-main.cc` component instead of injected test infrastructure sources
 * undo now obsolete commit `00235d8a` from July 2021
 * Clang cannot import user-defined literals as it seems -> disable test
 * Clang emits duplicate, non-mergeable copies of `detail::buffer`'s vtable, causing linker errors -> disable test
2023-05-03 07:56:24 -07:00
02cae7e48a Improve handling of Unicode in paths 2023-04-30 09:58:59 -07:00
53162142b2 Remove .bazelrc mention from Bazel related readme (#3411) 2023-04-29 16:25:00 -07:00
5bcf0d7f97 Bazel support (#3406)
* Bazel support: Remove not needed .bazelrc file

* Bump tested Bazel version

* Apply buildifier to format Bazel build files

* Add note about Bzlmod
2023-04-29 07:45:49 -07:00
f8c9fabd94 Fix spelling (#3404) 2023-04-25 11:47:37 -07:00
62ff4e1dbd Remove foonathan from maintainer list (#3402) 2023-04-23 13:35:05 -07:00
f449ca0525 Name vfprintf clashes with the identically named declaration in 'stdio.h' if that happens to be #included into the same TU. Fix this by using qualified name lookup instead of unqualified lookup that also enables ADL. (#3400) 2023-04-23 07:10:57 -07:00
eafcd3c8e1 Optionally attach declarations to the global module rather than module fmt (#3387)
This allows coexistence with TUs that use {fmt} through #include without duplicating declarations, definitions, linker symbols, and object code.
2023-04-23 06:04:36 -07:00
18154cc903 Simplify print 2023-04-22 14:03:40 -07:00
0de789cf29 Update changelog 2023-04-22 09:20:28 -07:00
c039389223 export names only once (#3392)
names declared to be exported at the point of introduction into a namespace *must not* be (re-)declared as exported later in the TU, e.g. when they are redeclared, defined, or specialized. [module.export]/6

Drive-by fix found during module testing: add a missing `detail::` name qualification
2023-04-22 06:21:06 -07:00
93e81bb5d8 Fix C4365 (signed/unsigned mismatch) warning on 32-bit Windows (#3398) 2023-04-20 17:36:05 -07:00
e7d6eb6794 Update tests to use recommended MOCK_METHOD (#3395) 2023-04-20 13:16:21 -07:00
18e7a2532b Remove obsolete msvc workarounds (#3388)
This bug in the modules implementation is fixed since at least msvc 19.34, possibly even earlier like 19.32.
2023-04-19 17:09:51 -07:00
0489c19dcb fix and improve module (#3386)
* export public documented API
* don't export `namespace detail`
* add `std.h` into module
* add missing namespace qualification in `xchar.h`
* fix call to `detail::get_iterator` in `xchar.h`
* fix ambiguous overload of `detail::isfinite` in `chrono.h`
2023-04-18 06:47:01 -07:00
8ec94ac6a5 Use full path to pcm 2023-04-14 11:57:17 -07:00
d97d8cea67 Push module check to test 2023-04-14 11:42:01 -07:00
d8a2698e6c Fix compilation as a C++20 module with gcc 13 2023-04-14 09:49:07 -07:00
d9c19940a3 Update add_module_library 2023-04-13 17:13:52 -07:00
4b5ae0b0ef Remove unnecessary module support check 2023-04-13 16:53:45 -07:00
75f3b1c094 Use add_module_library 2023-04-12 09:10:34 -07:00
faf83406a9 Workaround cmake issue 2023-04-11 15:59:08 -07:00
165814d57a Add module support to CMake 2023-04-11 14:38:34 -07:00
33f7150778 Fix error C2668 on msvc (#3378) 2023-04-11 06:27:28 -07:00
c98e5a08a4 Fix modular build on clang 2023-04-10 12:07:25 -07:00
119c6bd16f Move the modules check 2023-04-10 09:28:00 -07:00
77eeb71830 Remove unused headers 2023-04-10 09:08:19 -07:00
13bf99f9db Enable modules in clang 16 2023-04-10 08:44:43 -07:00
1d0257e4c0 FMT_MODULE_EXPORT_* -> FMT_EXPORT_* 2023-04-10 08:33:39 -07:00
4613d48fd3 FMT_EXPORT -> FMT_LIB_EXPORT 2023-04-10 08:24:23 -07:00
4a4a2a2bd6 Fix diagnostics 2023-04-09 09:30:20 -07:00
fce74caa15 Disable problematic implicit conversions 2023-04-09 09:08:46 -07:00
02bf4d1c1c Disable to_string_view ADL 2023-04-09 08:49:05 -07:00
466e0650ec Remove problematic workaround 2023-04-09 08:04:11 -07:00
029caa8ea2 Update changelog 2023-04-09 07:01:06 -07:00
e406ddbfaf Remove broken part of the config 2023-04-08 08:46:43 -07:00
9095679536 Update changelog 2023-04-08 08:39:17 -07:00
7f46cb75b8 ranges: Fix extra semi (#3374) 2023-04-06 08:31:07 -07:00
4e3f381058 Update changelog 2023-04-02 07:13:42 -07:00
d3c10f5167 fix compilation for MSDOS (#3369) 2023-04-01 13:40:53 -07:00
ab956f600f Update changelog 2023-04-01 08:04:47 -07:00
97aedeab48 Workaround a double-double hexfloat format (#3366)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2023-04-01 07:19:23 -07:00
bce8d4ed08 Remove stray comment 2023-03-27 11:04:00 -07:00
a91c7b286d Cleanup the core API 2023-03-26 21:07:26 -07:00
19c074e477 Remove deprecated fallback formatter 2023-03-26 08:45:06 -07:00
41cfc739fe Generalize format_as 2023-03-26 07:37:51 -07:00
f6276a2c2b Force use a signed char (On ARM char is unsigned by default) (#3362)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2023-03-22 11:34:59 -07:00
6002ddf825 Remove a deprecated option 2023-03-19 12:17:43 -07:00
6549ffde8e Improve format_as safety 2023-03-19 12:09:54 -07:00
d9bc5f1320 Fix code causing spurious Wstringop-overflow warning
See #2989, #3054, and others
2023-03-18 09:29:54 -07:00
9c5cd998d1 Remove unused functions 2023-03-18 08:40:16 -07:00
93bfa05382 %T is %H:%M:%S (#3349) 2023-03-18 07:16:22 -07:00
d8e1c4265a fix case of variant which is valueless by exception (#3347)
Co-authored-by: theomegacarrot <theomegacarrot@gmail.com>
2023-03-18 07:07:06 -07:00
e1720c0e51 Fix CUDA nvcc warning fmt/include/fmt/core.h(295): warning #1675-D: unrecognized GCC pragma (#3352) 2023-03-17 11:35:35 -07:00
7f882918eb write_floating_seconds: Fall back to ::round (#3343)
On some toolchains, `std::round` is not available.

Fixes #3342
2023-03-12 09:34:19 -07:00
cbc7b8d5c1 Cleanup dead variable (#3338) 2023-03-10 09:17:43 -08:00
050293646f Path is not escaped twice in the debug mode (#3321)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2023-03-05 08:01:06 -08:00
3daf33837c Enable consteval for Xcode 14.0.1 and later (#3331)
Co-authored-by: Cloyce D. Spradling <cloyce_spradling@apple.com>
2023-03-04 09:22:43 -08:00
e0748e61dd Fix recursion check in range formatting 2023-03-04 08:20:32 -08:00
b94e1016fa chore: set permission to cifuzz.yml (#3328)
Signed-off-by: Joyce <joycebrum@google.com>
2023-03-01 07:58:59 -08:00
98699719f8 Make # handling consistent with std::format 2023-02-26 10:15:16 -08:00
48dfbcaa95 Improve license and PR template wording 2023-02-26 09:08:53 -08:00
c644c753d7 Add '🐙 userver framework' to the projects 2023-02-26 08:42:55 -08:00
73b7cee7fb Fix for issue #3325 (#3326)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2023-02-26 06:59:41 -08:00
5b8302079d Add optional support (#3303) 2023-02-25 06:45:56 -08:00
3a69529e8b Fix various typos (#3312)
Found via `codespell -q 3 -S ./test/gtest -L "fo,pres,seh,wronly"`
2023-02-21 15:14:41 -08:00
76f520835f Call element parse in tuple parse 2023-02-20 12:54:20 -08:00
507c3042d8 class -> typename 2023-02-18 10:23:42 -08:00
1741e90dec Always call parse in range formatter 2023-02-18 09:58:37 -08:00
d646fd0daf Minor cleanup 2023-02-16 11:21:08 -08:00
b5c2f74f45 change sopen_s to wsopen_s (fmtlib#3234) (#3293) 2023-02-16 11:17:55 -08:00
e03753c4ac Add ubuntu mirrors (#3302)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2023-02-12 07:46:50 -08:00
6e6eb63770 [msvc] fix warning about non-inline variable 2023-02-11 09:45:13 -08:00
3c5464ba1c Fix OpenBSD build error (#3295) 2023-02-11 08:46:28 -08:00
655046d24f Fix container adaptor formatting 2023-02-10 09:45:37 -08:00
581c6292c9 Add formatters for container adapters (#3279) 2023-02-08 17:25:41 -08:00
7718eeeacc Implement glibc ext for sec, min, and hour (#3271) 2023-02-08 09:22:58 -08:00
44e0eea94e Use FMT_HAS_INCLUDE and apply clang-format 2023-02-08 07:19:10 -08:00
99070899b7 Fix errors setting of FMT_USE_FLOAT128 (#3259) 2023-02-08 07:15:02 -08:00
05e3a9233a Allowing formatting non-copyable ranges. (#3290) 2023-01-27 12:29:57 -08:00
70db193f09 Visual Studio 2022: fmt/format-inl.h(1145,60): warning C4310: cast truncates constant value #3287 (#3288) 2023-01-26 11:46:30 -08:00
a2c05a10ec Workaround a bug in MSVC <= 19.22 2023-01-25 10:34:28 +13:00
cae9bf45b9 Simplify apidoc comments 2023-01-25 09:32:03 +13:00
87c066a35b Implement println (#3267) 2023-01-24 12:30:00 -08:00
9409b2e4d8 Workaround for incompatibility between libstdc++ consteval-based std::is_constant_evaluated() implementation and clang-14 (#3281)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2023-01-22 11:29:34 -08:00
f89cd276f7 Refactor countl_zero fallback (#3276) 2023-01-17 15:04:34 -08:00
240b728d81 Report an error on overflow 2023-01-18 11:52:33 +13:00
dfbb952b2c Fix empty spec for time point (#3275) 2023-01-16 11:48:00 -08:00
39971eb336 Fix localized format for float-point numbers (#3272) 2023-01-15 11:47:24 -08:00
0f42c17d85 Implement a new formatting algorithm for small given precision (#3269)
Implement the formatting algorithm for small given precision discussed in https://github.com/fmtlib/fmt/issues/3262 and https://github.com/fmtlib/fmt/pull/2750
2023-01-14 11:30:20 -08:00
bfc0924eac Bugfix for fmt::printf on Power9 architecture with the XL compiler (#3256) 2023-01-13 11:36:00 -08:00
676c2a107e Fix negative subsec for time_point (#3261) 2023-01-11 11:36:50 -08:00
2c80cedc39 Fix standard default installation target presence (#3264) 2023-01-10 17:56:00 -08:00
dda53082be Support fill, align & width for time point (#3260) 2023-01-09 11:25:31 -08:00
2622cd23e6 Simplify arg_mapper 2023-01-03 16:35:21 -08:00
9e4a54fa6e Disable remaining implicit conversions 2023-01-03 12:08:42 -08:00
9ce6480676 Disble deprecated implicit enum conversions 2023-01-03 10:24:31 -08:00
9121f9b1d3 Enable format_as for classes 2023-01-03 08:58:23 -08:00
b7535365b2 Enable format_as for non-integral types 2023-01-02 13:37:13 -08:00
09ed1ddb9c Cleanup tests 2023-01-02 09:58:12 -08:00
0ec65d99aa Merge parse_presentation_type into parse_format_specs 2023-01-02 09:19:32 -08:00
71e4e02722 Cleanup vprintf 2023-01-02 08:37:00 -08:00
aad546baa5 Simplify presentation type parsing 2023-01-01 16:14:17 -08:00
14a69fcc54 Use parse_align 2023-01-01 10:44:55 -08:00
bf34ffd33f Refactor format string parsing 2023-01-01 10:21:47 -08:00
6056e07125 Simplify symbols 2022-12-30 19:35:05 -08:00
aa99b86409 Minor cleanup 2022-12-30 18:51:15 -08:00
6ade2eb4e5 Inline all_int_set 2022-12-30 17:05:08 -08:00
caa6974942 Simplify parse functions 2022-12-30 16:34:36 -08:00
a73a9b6a84 Refactor format string checks 2022-12-30 16:03:41 -08:00
72785a3aba Cleanup write 2022-12-30 13:53:55 -08:00
0c3dd5ddd7 Remove redundant check 2022-12-30 12:55:19 -08:00
739b600f40 Remove iterator shenanigans 2022-12-30 12:37:22 -08:00
3710c4d38f Link to dragonbox 2022-12-30 12:07:55 -08:00
a05ba44df8 Simplify format string parsing 2022-12-30 11:23:42 -08:00
ffb9b1d13c Improve handling of signed types 2022-12-30 10:31:39 -08:00
32190859ec Fix handling of char 2022-12-30 09:11:42 -08:00
8fe4d97d5e Reduce template instantiations 2022-12-30 08:44:23 -08:00
7e5a959564 Fix build with MSVC C++20 modules (#3254)
When using fmt with C++20 modules under MSVC, it can end up requiring certain things to have storage that would not otherwise have needed to. Since I didn't see anything that was already doing detection for `inline constexpr` variable support, I've just moved the entire thing into the only function where it's used.
2022-12-28 19:58:57 -08:00
9e60304869 Clarify that unused args are allowed 2022-12-28 06:58:04 -08:00
7ad48c1f65 Cleanup core.h 2022-12-26 09:14:15 -08:00
a921a596e7 Cleanup core.h 2022-12-26 07:46:31 -08:00
3e762fdf5c Use ignore_unused 2022-12-26 06:57:21 -08:00
79981a2528 Cleanup ranges formatting 2022-12-25 20:05:20 -08:00
bd12aaa98e Simplify format string parsing 2022-12-25 12:31:38 -08:00
b8f36207c9 Simplify format string parsing 2022-12-25 11:47:43 -08:00
d907786f04 Move anchor to where it belongs 2022-12-25 10:58:54 -08:00
f2355bbe5e Fix docs 2022-12-25 10:25:35 -08:00
f398c94761 Fix docs 2022-12-25 10:24:36 -08:00
4841784e82 Simplify C99 strftime detection conditions
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-12-25 10:16:19 -08:00
cb72c23e9e Improve timezone tests
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-12-25 10:16:19 -08:00
583f2d8209 Set timezone for chrono tests
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-12-25 10:16:19 -08:00
32c4390704 Minor cleanup 2022-12-25 08:59:25 -08:00
3a5e19fbf5 Minor cleanup 2022-12-25 08:42:16 -08:00
dfb857ebef Refactor format spec parsing 2022-12-25 07:25:32 -08:00
9ea9b6bcb1 Cleanup arg id parsing 2022-12-24 16:33:57 -08:00
2b0ff62a7f Remove unused template arg from format_string_checker 2022-12-24 15:46:34 -08:00
d1745084e0 Simplify parse context 2022-12-24 15:20:24 -08:00
407e7b7b6d basic_format_specs -> format_specs 2022-12-24 14:34:50 -08:00
3cf9794755 Cleanup format string parsing 2022-12-24 13:47:20 -08:00
934c8e5f76 Refactor precision parsing 2022-12-24 13:29:23 -08:00
fc96938345 Remove empty semicolon 2022-12-24 09:54:55 -08:00
f0ab112c34 Cleanup parsing 2022-12-24 09:40:35 -08:00
9660e5b956 Remove redundant tests 2022-12-24 07:28:13 -08:00
a585571e90 Ignore 0 character with align 2022-12-23 19:36:05 -08:00
840ec8569d Cleanup width handlers 2022-12-23 19:18:35 -08:00
1dadeb8a33 Refactor width parsing 2022-12-23 18:29:59 -08:00
275b4b3417 Remove obsolete parse-benchmark 2022-12-23 12:50:08 -08:00
e004f1d699 Fix for issue #3241
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-12-23 12:26:20 -08:00
bde1a6070d Simplify fill and alignment parsing 2022-12-23 10:52:56 -08:00
040dc2a5d4 small typo in syntax.rst
0x1e was misread as 0x13, it looks like
2022-12-23 10:29:14 -08:00
6a186bcd66 Localize FMT_USE_LOCAL_TIME 2022-12-21 14:52:52 -08:00
8c56919bd2 Check chrono spec starts with % 2022-12-21 14:40:30 -08:00
115001a3b1 Formatting of system clocks ought to be to UTC, not to local time.
This improves standards conformance of fmt.
2022-12-21 14:23:02 -08:00
b90895412f Fix formatting of named arguments with locale 2022-12-15 09:59:40 -08:00
d072f1dc69 Fix for issue #3228
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-12-14 13:49:36 -08:00
3999fd193a Workaround an ADL issue 2022-12-11 09:32:17 -08:00
c06e0b4ede Extract timezone offset from timezone conversion functions
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-12-10 10:13:53 -08:00
1bf302a4ea Implement %Ez, %Oz for chrono formatter
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-12-10 10:13:53 -08:00
f1733afd49 Pin godbolt example to specific version 2022-12-10 09:35:55 -08:00
f61dcccc6e Update README.rst 2022-12-06 11:52:37 -08:00
f9bcbdcbcf Update README.rst 2022-12-06 11:51:59 -08:00
1a854b4aa5 Clarify what mod_inv_5 is 2022-12-04 08:36:03 -08:00
62ceb181b1 fix #3105 - Compile-time error when mixing named argument with automatic indexing 2022-12-04 08:13:26 -08:00
b0c8263cb2 include/fmt/core.h: copy constructors removal 2022-11-30 16:44:42 -08:00
d24be2e95c Add countl_zero function
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-11-30 12:25:01 -08:00
8d50d814db Fix a chrono formatting issue found by fuzzing 2022-11-30 11:04:51 -08:00
115ca96e0e Bump tested CMake version to 3.25
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-11-30 08:09:32 -08:00
886491625d Remove workaround for GTest bug
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-11-30 07:16:37 -08:00
74c51ff37e Skip only strptime dependent test in scan-test
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-11-27 08:59:30 -08:00
69ffedfe52 Use target_compile_features to specify C++ standard requirement 2022-11-26 11:03:17 -08:00
fae6f7e081 Optimize range formatter 2022-11-26 08:50:46 -08:00
a69e43c9d7 Update benchmark results 2022-11-25 09:52:02 -08:00
91c024ed33 Rename leading_v -> leading_xdigit
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-11-25 09:08:40 -08:00
649aa102d6 CI linux: add CIFuzz Github action
Signed-off-by: David Korczynski <david@adalogics.com>
2022-11-24 08:22:51 -08:00
31364732dc Replace snprintf-based hex float formatter with internal implementation
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-11-24 07:15:46 -08:00
74d55a4938 Add missing operators
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-11-24 07:15:46 -08:00
8276f1a204 Fix warning: the implicit by-copy capture of "this" is deprecated (EDG frontend)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-11-22 10:51:00 -08:00
81ebe70b9b Fix warning: a class type that is not trivially copyable passed through ellipsis (EDG frontend)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-11-22 10:51:00 -08:00
3160847ebd Enable C++17 tests on macOS
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-11-18 08:22:07 -08:00
6a95f8c7eb Add missing env CTEST_OUTPUT_ON_FAILURE
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-11-18 08:22:07 -08:00
c7980542d3 Skip the scan-test if strptime isn't defined (#3184)
cygwin and embedded systems. By default newlib doesn't provide strptime
in time.h because it was added in a later X/Open versions. Issue: #3178
2022-11-16 09:42:01 -08:00
7df30f91ae Format unique_ptr with custom deleter (#3177)
* Format unique_ptr with custom deleter

Added deleter type to fmt::ptr unique_ptr overload. Deleter type is
part of the unique_ptr type.

* Review: apply clang-format

Co-authored-by: Hans-Martin B. Jensen <haje@eposaudio.com>
2022-11-13 21:54:32 -08:00
d2e89c8b08 Document more chrono specs 2022-11-08 19:35:34 -10:00
bd19593204 Document more chrono specs 2022-11-08 16:22:23 -10:00
fd0d0ec8df Document more chrono specs 2022-11-08 14:57:57 -10:00
8e93434edd Update README.rst 2022-11-08 11:21:16 -08:00
fc07217d85 Make utf-8 detection compatible with gbk 2022-11-02 15:42:47 -07:00
cb7373b469 Replace format with FMT_STRING. (#3162)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-11-02 13:17:16 -07:00
795ed8abf5 Add precision modifier for seconds in chrono format (#3148)
Co-authored-by: Stepan Ponomarev <stepan.ponomarev@itiviti.com>
2022-11-02 11:58:51 -07:00
66d71a1b35 Fixing formatting of range of range of char. (#3158) 2022-11-02 11:04:54 -07:00
80f8d34427 fmt::ostream - aggregate buffer instead of inheriting it (#3139)
Some MSVC-specific behavior:
When class fmt::ostream inherits detail::buffer - the last gets implicitly exported when fmt is built as a shared library.
Unless os.h is included, the compiler assumes detail::buffer is not externally exported and instantiates a local copy of it, which causes ODR violation.
With aggregation - there is no extra exporting of detail::buffer symbols.
2022-10-23 07:21:36 -07:00
64965bdc96 Add locale getter in tm_writer (#3147)
* Add locale getter in tm_writer

* Apply clang-format

Co-authored-by: Stepan Ponomarev <stepan.ponomarev@itiviti.com>
2022-10-20 10:22:03 -07:00
e1ffa7655d Fix warning: conditional expression is constant. (#3150)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-10-20 07:49:53 -07:00
8c19bf3f2f Mention MariaDB amongst the projects that use fmt (#3145) 2022-10-17 13:33:05 -07:00
f67dbc9811 Remove duplicate implementation (#3144)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-10-17 11:15:28 -07:00
cd7202e039 Fix overflow error (#3143)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-10-16 14:04:55 -07:00
51d3685efe Remove duplicate template parameter. (#3142)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-10-14 16:34:24 -07:00
9254cfa6f0 Support formatting of subseconds (#3115)
* Timestamp formatting shall print also subseconds, fixed a bug for fractional durations
2022-10-12 14:33:53 -07:00
cfb34a0607 Avoid using uint as a type name (#3137)
Sometime `uint` is defined as a global type by the project's code directly or by some 3rdparty libraries (e.g. Qt or OpenCV).
Some versions of MSVC (e.g. v16.11.15) gives a type shadowing warning:
```
3rdparty\fmtlib\fmt\include\fmt/format.h(3251): warning C4459: declaration of 'uint' hides global declaration
opencv2/core/hal/interface.h(45): note: see declaration of 'uint'
```
This also causes a compilation failure when `/WX` is used.
2022-10-12 10:53:47 -07:00
5ad7b71381 Fix options for C++20 experimental module in CMake (#3134)
* Fix options for C++20 experimental module in CMake

* Replace `FMT_CAN_MODULE` by `FMT_MODULE` in test/CMakeLists.txt
2022-10-12 08:23:12 -07:00
d2c47c0df2 Fix broken condition (#3129)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-10-07 13:46:45 -07:00
491c32cbd9 Workaround gcc bug 103879 2022-10-05 21:12:38 -07:00
662adf4f33 Move formatter<std::error_code> from fmt/os.h to fmt/std.h (#3125)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-10-01 17:46:09 -07:00
ad91cab374 Normalization of stdlib inline namespace names (#3119)
* Normalization of stdlib inline namespace names

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

* Remove all subnamespaces with names matching "__*" mask

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-09-29 09:52:38 -07:00
0ccaed3a6c Set CMAKE_RUNTIME_OUTPUT_DIRECTORY relative to CMAKE_CURRENT_BINARY_DIR instead of CMAKE_BINARY_DIR (#3120)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-09-28 16:51:23 -07:00
ad719619cc Support formatting of std time_point with utc_clock (#3110) 2022-09-28 07:31:53 -07:00
6e0a5f7fba Update CI to Ubuntu 20.04 and to newer versions of actions 2022-09-27 15:06:12 -07:00
48f525d025 Add basic_format_string::get() 2022-09-22 19:50:04 -07:00
0b5cb18b71 Use buffering in to_string to avoid bloat 2022-09-21 17:11:43 -07:00
4c4f99a583 Update a godbolt link 2022-09-21 12:05:57 -07:00
3272a7a3ce Update an example 2022-09-21 12:03:18 -07:00
a48e3355a6 Improve docs 2022-09-18 08:44:04 -07:00
afcf424294 Update docs 2022-09-16 15:27:18 -07:00
ac85afaab6 Simplify format_error 2022-09-16 14:25:14 -07:00
3178bb9a26 Update docs 2022-09-16 10:29:53 -07:00
cf58f64c54 Update docs 2022-09-16 10:28:00 -07:00
e4e0ae3918 Use fmt/core.h in examples 2022-09-15 20:41:32 -07:00
d65acc4e6c Improve docs 2022-09-14 10:59:50 -07:00
c9f790b061 Update docs 2022-09-14 10:58:52 -07:00
6b8144a5ac Update locale docs 2022-09-14 06:38:29 -07:00
2d66ad5d33 Suppress -Wshadow
Solves:
/fmt/include/fmt/ostream.h:89:18: warning: declaration of 'fbuf' shadows a previous local [-Wshadow]
   89 |   else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
      |                  ^~~~
C:/GIT/ok-mimot/libs/3rdParty/fmt/include/fmt/ostream.h:87:13: note: shadowed declaration is here
   87 |   if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
      |             ^~~~
2022-09-13 11:14:30 -07:00
042af53324 Suppress -Wfloat-equal
Only NaN and Inf are not less than Inf and the check for NaN is done
before.

Solves:
.../fmt/include/fmt/format.h:2509:43: warning: comparing floating-point with '==' or '!=' is unsafe [-Wfloat-equal]
 2509 |     return !detail::isnan(value) && value != inf && value != -inf;
2022-09-13 11:14:30 -07:00
192859c2b5 Optimize writing to buffers via back_insert_iterator 2022-09-12 15:32:12 -07:00
e2f6d7665b fix gcc <= 7.1 compile errors 2022-09-12 10:43:16 -07:00
61844b6b67 Fix build error on GCC-9
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-09-12 07:02:29 -07:00
7a752e75ff New CI: GCC-9
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-09-12 07:02:29 -07:00
94ceb38a09 Improve locale API 2022-09-11 09:33:31 -07:00
58c4c012fa Disable slow windows build and simplify write_loc 2022-09-11 08:35:09 -07:00
c3494ae364 Refactor float localization 2022-09-11 07:47:27 -07:00
8ae56161c8 Fix compilation with FMT_ENFORCE_COMPILE_STRING and FMT_WERROR (#3091) 2022-09-10 18:05:10 -07:00
76705fc2ee Update doc 2022-09-10 15:06:09 -07:00
21c2137e77 Add class name output to formatter for std::exception (#3076)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-09-10 08:04:00 -07:00
ecffca6726 Don't parse '}' as fill 2022-09-07 17:33:31 -07:00
3176e0fad7 Add locale overload for formatted_size (#3084) (#3087)
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-09-07 14:15:12 -07:00
1feb430faa Fix intellisense on Windows (#3082)
__INTELLISENSE__ is 1 on vs2022 and clang, causing FMT_HAS_INCLUDE, FMT_USE_FCNTL, etc to be 0.
That results in VS and VSCode having a lot of linter errors while code compiles just fine.
2022-09-05 11:50:06 -07:00
b98ffb7dbd Improve locale handling 2022-09-04 21:07:30 -07:00
bac53951b8 Add starts_with to basic_string_view. (#3080)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-09-04 11:41:16 -07:00
d59b89e9cd More locale 2022-09-04 11:23:45 -07:00
58a5563a9f Implement grouping 2022-09-04 09:01:26 -07:00
1b94271ff6 Add support for UTF-8 digit separators 2022-09-03 11:01:05 -07:00
768d79a839 Implement format_facet 2022-09-03 09:42:36 -07:00
91ecb38a34 Localize negative integers 2022-09-03 07:01:11 -07:00
aec3bb5d0a Workaround C complex.h idiocy 2022-09-03 06:35:55 -07:00
29c6000137 Simplify is_variant_like_ check, fix compile error before GCC 11 (#3072)
Co-authored-by: Vladislav Shchapov <vladislav@shchapov.ru>

Co-authored-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-09-02 21:08:07 -07:00
fec5515c55 num_format_facet -> format_facet 2022-09-02 18:55:08 -07:00
f187274d36 Add loc_value 2022-09-02 13:45:23 -07:00
fc5e59fe4a Don't use stringstream 2022-09-02 13:05:26 -07:00
d6a8704605 Improve locale support 2022-09-02 11:52:19 -07:00
56c72a671c Reduce locale dependency 2022-09-02 10:22:11 -07:00
4191477b98 Add formatter for std::exception (#3062)
Co-authored-by: fekir <federico.kircheis@gmail.com>
Co-authored-by: Alexey Ochapov <alexez@alexez.com>
Co-authored-by: Vladislav Shchapov <vladislav@shchapov.ru>

Co-authored-by: fekir <federico.kircheis@gmail.com>
Co-authored-by: Alexey Ochapov <alexez@alexez.com>
Co-authored-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-09-02 08:33:37 -07:00
75383a87f9 Inline trivial functions 2022-09-01 18:25:23 -07:00
48327a82e3 Make format.h compile faster 2022-09-01 17:06:47 -07:00
b79ed4105a Remove unnecessary type_identity 2022-09-01 16:29:08 -07:00
64e29893cf Improve locale support 2022-09-01 14:48:43 -07:00
0b0f7cfbfc hip workaround 2022-09-01 09:18:53 -07:00
40e414d823 Fix compilation error with gcc-7.2.0
Without the added line, the gcc-7.2.0 compiler will give the following error:
```
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:1240:8: error: uninitialized variable 'buffer' in 'constexpr' function
   Char buffer[digits10<UInt>() + 1];
        ^~~~~~
```
See https://godbolt.org/z/fh7TMs9qs
2022-08-30 10:55:57 -07:00
33b4c33c5b Requires FMT_CONSTEXPR20 support
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-08-29 13:33:48 -07:00
a07411c2b9 Disable compile-time checks for dynamic width/precision test for LCC and compiler without std::is_constant_evaluated()
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-08-29 13:33:48 -07:00
797d82b21a Disable non-type template args for LCC
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-08-29 13:33:48 -07:00
a553521d6d Disable "GCC optimize" pragma for LCC
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-08-29 13:33:48 -07:00
a33701196a Update version 2022-08-27 08:57:10 -07:00
1f575fd5c9 Bump version 2022-08-27 08:55:39 -07:00
c7635288f7 Fix docs, take 2 2022-08-27 08:28:07 -07:00
c8ed78e315 Fix docs 2022-08-27 08:01:47 -07:00
e07cfb2068 Update changelog 2022-08-27 07:55:06 -07:00
1dc7af5693 Fix markup 2022-08-27 07:52:58 -07:00
f7d21c3a1a Update changelog 2022-08-27 07:51:24 -07:00
a55bcb24bd Update changelog 2022-08-27 07:13:36 -07:00
30cb2b3122 Remove appveyor config 2022-08-27 06:52:25 -07:00
cf8d3c3229 Update changelog 2022-08-26 16:17:42 -07:00
3c3cb6f6b1 Update changelog 2022-08-26 16:00:24 -07:00
91481f255c Detemplatize code_point_length_impl 2022-08-26 15:45:00 -07:00
f98048b621 Fix bugs in utf8 decoder (#3056)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-08-26 15:37:15 -07:00
4a8e2949bb Fix formatting of ranges of code unit types
Thanks Nicole Mazzuca.
2022-08-26 13:48:58 -07:00
3a3b0709e2 Disable bogus -Wstringop-overflow on GCC 11 (#3054)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-08-24 12:37:34 -07:00
e724bbea16 Fix wchar_t corner cases 2022-08-24 12:23:10 -07:00
665d9779ec Disable non-type template args for nvhpc (#3053) 2022-08-24 10:56:45 -07:00
13d07c6a3d Apply doc fixes retroactively 2022-08-24 09:16:12 -07:00
391f922acc Improve error reporting in format string compilation 2022-08-24 09:05:15 -07:00
dc59d3df3f Fix a warning in gtest 2022-08-24 07:18:14 -07:00
489dabbd31 Fix decoder on broken utf8 sequences. (#3044)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-08-24 07:13:27 -07:00
541cd21838 Fix locale name (thanks Mikhail Paulyshka) 2022-08-20 08:06:20 -07:00
1f95c34381 Fix sign handling with large code units 2022-08-20 07:46:58 -07:00
779449fd99 Belarusify test 2022-08-20 07:37:15 -07:00
fbb568bce0 nvhpc/22.3: workaround for c++17 mode. (#3043) 2022-08-18 11:30:40 -07:00
36c23bd5fd Prepare for deprecating FindPythonInterp module. (#3040)
* Prepare for deprecating FindPythonInterp module.

Since FindPythonInterp module is deprecated after CMake 3.12, it is better to start using the new FindPython module.

* Add the proper punctuation in comments.
2022-08-17 14:18:39 -07:00
9ff0f3a7d6 Fix docs 2022-08-16 11:31:11 -07:00
fd41110d38 Add MinGW to CI 2022-08-14 08:40:38 -07:00
fc23cfbf4e Fix testsuite on MinGW + MSVCRT
Fixes #2952. The testsuite indirectly called strftime() with conversion
specifiers defined only in C99. In MSVCRT this function conforms only to
C89. Only in the updated UCRT this functon provides the functionality of
C99.
2022-08-14 08:40:38 -07:00
fd93b633b8 Constexpr formatted_size (#3026)
* Constexpr formatted_size

* Add C++20 tests for gcc 9 and 10

* Adjust unit test to require __cpp_lib_bit_cast
2022-08-10 09:35:30 -07:00
7fb8d33f9d Fix compile-time width/precision type check 2022-08-09 16:10:02 -07:00
8bd02e93b2 Reduce conditional compilation 2022-08-09 09:05:01 -07:00
d9c1c7353a Use is_utf8() in print(std::ostream&, ...)
This patch concludes the Unicode support for print(ostream&, ...)
2022-08-09 09:05:01 -07:00
682e097bee Remove -Wl,--as-needed linker option
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-08-07 06:51:41 -07:00
b9087ee587 Suppress unused typedef warning 2022-08-05 15:27:01 -07:00
df56fdf883 Clarify docs for compile-time checks 2022-08-05 07:00:34 -07:00
90c48b8525 Remove double code execution
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-08-05 06:15:59 -07:00
5a8b7cd742 Add comment
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-08-05 06:15:59 -07:00
36a25d75b4 Reuse detail::string_literal in the chrono formatter
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-08-05 06:15:59 -07:00
6c9304b2c2 Replace ParseContext with basic_format_parse_context
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-08-05 06:15:59 -07:00
24ab9dd19e Remove duplicate method
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-08-05 06:15:59 -07:00
a95dc17017 Remove unused condition
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-08-05 06:15:59 -07:00
5f774c0aed I shouldn't be there 2022-08-02 16:35:50 -07:00
6567df7f24 Update README.rst 2022-08-02 06:50:09 -07:00
6c6b1fbf6e Workaround a bug in MSVC
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-08-02 06:46:02 -07:00
9beddd08f9 Improve CI on Windows 2022-08-02 06:46:02 -07:00
6452e3c9eb Fix a typo in example 2022-08-02 06:26:19 -07:00
756822ba39 Fix Unicode handling for ostream under Windows with libc++. (#3001)
Also replaces the SFIANE tricks applied in
ce7ecdb7af with conditional compilation.
The code was too complicated along with the other trick to access private
data members.
2022-07-30 06:49:21 -07:00
0b2862a1e4 Range formatter (#2983)
* Implement range_formatter and format_kind

* Attempted gcc 4.8 fix

* gcc 4.8 interprets inaccessible as a hard error (instead of... not available)

* Attempting to delete set_debug_format.

* clang-format

* Different implementation of FMT_STATICALLY_WIDEN

* Renaming copy_str_range to copy_str.

* I guess I need a definition

* Forgot to delete these.

* Other PR comments.
2022-07-29 13:55:16 -07:00
258000064d Add fmt:: namespace to doc (#3009)
Otherwise as-is the example does not compile on Visual Studio due to the conflict with std::format_to: 
https://gcc.godbolt.org/z/qe4jEvvqY
2022-07-29 13:10:09 -07:00
e9ca7ea472 Suppress a bogus warning 2022-07-28 07:12:49 -07:00
81f1cc74a7 Improve Unicode handling when writing to an ostream on Windows (#2994)
* Refactor detail::print() by splitting into two functions.

The part with SetConsoleW is a separate function, without fwrite().

* Make Unicode handing when writing to std::ostream more robust.

Calls to print(ostream&) in the special Unicode case on Windows fallback
to writing via ostream::write instead of fwrite().

* Fix Unicode handling when writing to an ostream on GCC on Windows

* Add TODO note about detail::is_utf8()

* Fix warning -Wundef

* Fix for non-Windows OSs

* Fix building as DLL on Windows

* Refactor

* Suppress warning
2022-07-23 08:03:31 -07:00
bbcb129e02 Reduce filesize of the tests on MinGW (#2995)
This patch removes the workaround applied here
1acfd07f1e.
MinGW is not tested on Appveyor anymore.
2022-07-22 20:11:33 -07:00
48e0a59222 Implement compile-time checks for dynamic width/precision type 2022-07-22 17:00:40 -07:00
bc5c7c50fd Fixes IBM XLC behavior with uint128 fallback (#2985)
* Fixes IBM XLC behavior with uint128 fallback

* Replace legacy xlc with clang-based xlc

* simplify xlc intrinsics handling

Co-authored-by: Federico Busato <fbusato@nvidia.com>
2022-07-22 13:49:17 -07:00
00adc7120d Add a regression test for here be dragons 2022-07-22 11:08:00 -07:00
c48be439f1 Add additional search paths for doxygen on Windows
`find_program(DOXYGEN doxygen)` didn't find the executable automatically even if I installed Doxygen on Windows. Therefore, I added some additional search paths.
2022-07-19 08:59:18 -07:00
371f9c71ca Fix even in format_dragon 2022-07-19 08:36:34 -07:00
91abfcd6cf Suppress an msvc warning 2022-07-16 08:57:09 -07:00
deeab54b40 Remove unused include 2022-07-15 20:11:35 -07:00
688a627d6c Remove unused constants. 2022-07-14 15:25:35 -07:00
9bb1605f10 Remove some branches 2022-07-14 15:25:35 -07:00
8061d9afbe Simplify Dragonbox implementation 2022-07-14 15:25:35 -07:00
d82e1a108d Make sure the correct fmod overload is called 2022-07-13 12:42:03 -07:00
defa04e730 Fix for EDG frontend (Intel, NVHPC compilers) (#2982)
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-07-13 11:34:43 -07:00
92d36e82c4 The n specifier for ranges (#2981)
* The n specifier for ranges.

* Flipping flag polarity.
2022-07-12 10:08:38 -07:00
0db43cf7fe Pointless comparison warnings (#2971)
Co-authored-by: Federico Busato <fbusato@nvidia.com>
2022-07-11 12:29:39 -07:00
05be7a0764 Use FMT_USE_FLOAT128 instead of __SIZEOF_FLOAT128__ 2022-07-10 08:54:34 -07:00
2a1b3ac629 Fix large shift in uint128_fallback 2022-07-10 08:27:21 -07:00
e1d3d3a326 Exclude recursive ranges from the formatter specialization for ranges (#2974)
* 2954: Add test case

* Eliminate extra-test and merge it into existing std-test instead. Add conditionals for filesystem::path testing that does not run into the ambiguity problem.

* #2968: Introduce additional compile-time predicate to detect recursive ranges and reject them in formatter specialization for ranges. In addition, introduce additional wrapper traits for the individual logical operands of the complete range constraints

* #2968: Eliminate preprocessor condition that enables the formatter specialization for std::filesystem::path

* #2968: Eliminate preprocessor condition that enables the test for the formatter specialization for std::filesystem::path

* Use own bool_constant, which is available for all C++ versions

* Reintroduce previous workaround but restrict to VS 2015 for now

* Comma fix

* - Rename is_not_recursive_range to is_nonrecursive_range and add comment that explains it being depending on is_range being true
- Merge has_fallback_formatter_delayed into is_formattable_delayed and add comment that explains it being depending on is_not_recursive_range being true
- Replace disjunction in formatter specialization by has_fallback_formatter_delayed
- Get rid of unneeded detail:: prefixes within namespace detail
2022-07-10 06:26:23 -07:00
b761f1279e Improve forward using the idea from Jonathan Müller 2022-07-07 16:48:17 -07:00
cc1926942f Inline std::forward 2022-07-07 14:41:54 -07:00
d5e9166f54 Fixed typo in changelog example. 2022-07-05 19:07:39 -07:00
b31d1a75a0 Add xchar support for fmt::streamed().
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-07-05 19:07:06 -07:00
c4ee726532 Update version 2022-07-04 09:50:06 -07:00
fa2eb2d2e3 Bump version 2022-07-04 09:37:29 -07:00
35f72bf210 Bump version 2022-07-04 09:10:55 -07:00
d22f00d7e4 Update changelog 2022-07-04 09:01:56 -07:00
4e8d215606 Update changelog 2022-07-04 08:56:18 -07:00
84eecb6561 Prune CI configs 2022-07-04 08:51:35 -07:00
55727e3b21 More compile-time checks 2022-07-04 08:25:27 -07:00
1010b7f148 Update docs 2022-07-04 08:18:44 -07:00
2ac51fc448 Update changelog 2022-07-04 08:13:27 -07:00
831132293b Workaround for Microsoft Visual Studio 2022 Internal compiler error.
D:\a\fmt\fmt\test\compile-test.cc(362,3): fatal error C1001: Internal compiler error. [D:\a\fmt\build\test\compile-test.vcxproj]
(compiler file 'D:\a\_work\1\s\src\vctools\Compiler\CxxFE\sl\p1\c\constexpr\constexpr.cpp', line 8635)

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-07-04 07:18:21 -07:00
115e00e0b9 Replace __cplusplus with FMT_CPLUSPLUS.
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-07-04 07:18:21 -07:00
94114b05ca New CI: Microsoft Visual Studio 2022.
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-07-04 07:18:21 -07:00
d2a2320820 Fix partial specialization problem for filesystem for Visual Studio (#2957)
* #2954: Provide std::conjunction and std::disjunction substitutes

* #2954: Use conjunction and disjunction substitute to make formatter specializations for ranges and maps more robust (especially for Visual Studio compiler family)

* #2954: As workaround for older MSVC compilers split formatter<std::filesystem::path> partial template specialization into two explicit specialization.

* 2954: Add test case

* Provide simplified implementations of conjunction and disjunction

* Remove workaround explicit specializations if the partial specialization would cause an ambiguity error

* Eliminate extra-test and merge it into existing std-test instead. Add conditionals for filesystem::path testing that does not run into the ambiguity problem.
2022-07-03 11:06:54 -07:00
0c06c81da8 Deprecated implicit conversion of enums to ints for consistency with scoped enums 2022-07-03 09:02:22 -07:00
c12b4c0cf1 New CI: GCC-8 C++17, Clang-8 C++17.
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-07-02 08:34:52 -07:00
99bb5b1d17 Fix std::variant, std::filesystem::path tests on GCC-8, Clang-7,8.
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-07-02 08:34:52 -07:00
e29c2bc60e Update docs 2022-06-30 08:13:34 -07:00
c65e4286bf Update changelog 2022-06-29 09:02:08 -07:00
69c24e47e8 Update changelog 2022-06-28 11:00:56 -07:00
6a775e9560 Add support for 'std::variant' in C++17 (#2941)
Add support for 'std::variant' in C++17.

For C++17, if all the alternatives of a variant are formattable
the variant is now also formattable. In addition 'std::monostate'
is now formattable.

Moves implementation into 'std.h', and tests into 'std-test.cc'.

Avoid fold-expression since MSVC was crashing.

Add section for 'fmt/std.h' in API-docs.
2022-06-26 07:28:01 -07:00
51535866d0 Update docs 2022-06-25 09:13:29 -07:00
3ef5caa9fe Update docs 2022-06-25 09:11:10 -07:00
dccd3e6742 Fix docs 2022-06-25 09:04:31 -07:00
9cb02aaaad Fix UDLs 2022-06-25 08:52:10 -07:00
e6d478f8e8 Update changelog and docs 2022-06-25 08:33:57 -07:00
2d931b1497 Add fmt::streamed 2022-06-24 09:26:24 -07:00
0506a5733d Update changelog 2022-06-24 09:04:56 -07:00
e8bd2a804d Fix enable_ifs for map formatter (#2944) 2022-06-23 08:24:11 -07:00
7c56e11ecf Update changelog 2022-06-23 07:40:56 -07:00
69a20db081 Update changelog and fix an apidoc comment 2022-06-22 08:32:46 -07:00
7a2a97c882 Update changelog 2022-06-22 07:31:34 -07:00
5682338891 Fix is_formattable for tuple-like types. (#2940) 2022-06-19 08:25:58 -07:00
f0de128449 Remove /source-charset:utf-8 compile option.
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-06-19 07:37:39 -07:00
eaa8efb950 Fix ofstream handling in msvc 2022-06-16 15:02:33 -07:00
fb991e9d3b Update changelog 2022-06-12 12:17:39 -07:00
8e47cfd1cd fix -Wsign-conversion warning 2022-06-11 12:31:33 -07:00
2471875867 Make the tests pass on a CHERI system. 2022-06-10 07:02:03 -07:00
b135f1c014 Refactor handling of argument types 2022-06-09 17:03:33 -07:00
f61a1e8132 Add format_arg_types 2022-06-09 15:50:30 -07:00
48b7e3dafb Added a FMT_STRING wrapper for system_error() call.
This enables the use of FMT_ENFORCE_COMPILE_STRING on MSVC 2019.
2022-06-07 07:00:57 -07:00
4bb3af7a6b Improve compile-time checks 2022-06-05 13:58:04 -07:00
d02c582b96 Fix 'duplicate symbol' error.
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-06-05 07:17:25 -07:00
b59d8c3a23 Make std::filesystem::path formatter utf-8 compatible.
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-06-04 10:10:21 -07:00
232e21d51f Add utf-8 test for std::filesystem::path formatter.
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-06-04 10:10:21 -07:00
8644654190 Docs: add comment about empty format context range 2022-06-02 08:40:29 -07:00
ba50c19e82 use qualified call to avoid ADL conflict with std::format_to 2022-06-01 15:57:15 -07:00
9d60395953 Fix compilation on ppc64 2022-05-31 13:53:15 -07:00
a2681aabcb Debug ppc failure 2022-05-31 11:30:22 -07:00
bfc5767368 Add support for std.h in Bazel build 2022-05-30 16:52:25 -07:00
798d09bb70 Debug ppc failure 2022-05-30 13:06:34 -07:00
8c7cf51395 Cleanup 2022-05-30 08:21:01 -07:00
cdfacb4345 Cleanup parse_format_string 2022-05-30 07:30:11 -07:00
926ddd0631 Move compile string to detail 2022-05-30 07:06:36 -07:00
cb682f36f4 Move to_string_view to detail 2022-05-29 22:51:31 -07:00
156744ad47 Simplify fmt::runtime 2022-05-29 21:18:52 -07:00
d9c7166cf0 bi_iterator -> base 2022-05-29 21:01:57 -07:00
11316b29af chore: Set permissions for GitHub actions
Restrict the GitHub token permissions only to the required ones; this way, even if the attackers will succeed in compromising your workflow, they won’t be able to do much.

- Included permissions for the action. https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions

https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions

https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs

[Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/)

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>
2022-05-29 19:12:52 -07:00
fe6eb792d5 Cleanup check_format_string 2022-05-29 19:01:06 -07:00
054b1d9808 Remove unused include 2022-05-29 18:24:10 -07:00
e927149f8e Cleanup macros 2022-05-29 17:23:02 -07:00
1761e2666a Remove FMT_CONSTEXPR_DECL 2022-05-29 16:42:58 -07:00
d6b568a6cc Cleanup string_view checks 2022-05-29 16:30:39 -07:00
c83a5d42bb FMT_MSC_VER -> FMT_MSC_VERSION 2022-05-29 15:39:08 -07:00
27cd68c301 Cleanup macros 2022-05-29 14:45:59 -07:00
08be4abb30 Remove FMT_NVCOMPILER_VERSION 2022-05-29 13:54:31 -07:00
661b192545 Remove FMT_HEADER_ONLY_CONSTEXPR20 2022-05-29 13:22:45 -07:00
d1026fa5d2 Remove extern format_float 2022-05-29 13:11:19 -07:00
7e63b600b6 Make to_string work with __float128 2022-05-29 12:23:57 -07:00
b2ea212cd1 Update README.rst 2022-05-29 11:44:09 -07:00
c2fcdc54e2 Move format_float to format.h for __float128 2022-05-29 11:30:33 -07:00
2b9037a190 Move basic_fp to format.h for compile-time formatting 2022-05-29 07:32:52 -07:00
542785ccbf Get rid of detail::bits 2022-05-29 07:10:36 -07:00
65dd2ea52c Use write_escaped_string to std::filesystem::path.
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-05-28 07:48:02 -07:00
9860f67cde Improve xchar support for std formatters.
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-05-28 07:48:02 -07:00
03b1b2838e Improve std::filesystem::path formatter.
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-05-28 07:48:02 -07:00
4f9311e689 Fix definition of error_handler::on_error 2022-05-27 10:49:19 -07:00
652fea45a9 Visual Studio 2022: fmt/format.h(1526,27): warning C4127: conditional expression is constant #2908 2022-05-27 10:38:13 -07:00
1f9eae7e31 Add xchar support for write_escaped_string.
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
2022-05-27 08:36:38 -07:00
90b68783ff Skip cmake targets inclusion if fmt::fmt already exists (#2907) 2022-05-27 08:35:40 -07:00
ce246aaf74 Remove deprecated APIs 2022-05-22 07:10:09 -07:00
edeb3d8091 Remove deprecated APIs 2022-05-21 19:57:38 -07:00
496aff7c33 Remove deprecated APIs 2022-05-21 15:12:38 -07:00
f5cdf7cb04 Simplify snprintf_float 2022-05-21 12:34:21 -07:00
440512f08d Remove deprecated APIs 2022-05-21 12:20:31 -07:00
621eb80bbb Remove deprecated APIs 2022-05-21 11:34:07 -07:00
5c7d315ded Remove locale.h 2022-05-21 08:19:09 -07:00
c6324009ba Add initial double-double support 2022-05-21 07:32:54 -07:00
147e8ca580 Fix Windows max mix-up (#2903) 2022-05-18 16:35:26 -07:00
6bf039d750 Add std:🧵:id formatter 2022-05-17 16:37:19 -07:00
9730fb0156 Fix path formatter 2022-05-17 14:29:49 -07:00
f0903ad9df Add a path formatter 2022-05-16 17:32:25 -07:00
8833f386e4 Merge branch 'master' of github.com:fmtlib/fmt 2022-05-15 09:51:38 -07:00
5ab9d39253 Namespace-qualify format_to to avoid conflict with std::format_to 2022-05-15 09:51:20 -07:00
af5644c274 Update README.rst 2022-05-15 06:29:15 -07:00
3e28dc021c VS2022 17.2: C4189: 'zero': local variable is initialized but not referenced #2891 (#2892)
VS2022 17.2: C4189: 'zero': local variable is initialized but not referenced #2891

Co-authored-by: Ivan Shynkarenka <Ivan_Shynkarenka@epam.com>
2022-05-13 07:04:34 -07:00
f6f920a1a8 Tweak a comment and apply clang-format 2022-05-11 14:40:26 -07:00
ae963e444f Implement constexpr isfinite to avoid producing NaN 2022-05-11 08:43:22 -07:00
358f5a7e50 Make precision computation consistent with width 2022-05-11 06:34:51 -07:00
f63afd161f Fixed all clang -Wsigned-enum-bitfield warnings (#2882)
Made enums involved in bitfields unsigned by specifying their underlying type as unsigned char.

Due to a bug, when specifying an underlying type, gcc < 9.3 warns about bitfields not being big enough to hold the enum, even though they are. So keep the plain enum for old gcc.

An example of the bug is here:

https://godbolt.org/z/58aEv8zEq
2022-05-09 11:03:51 -07:00
7e4ad40171 Add initial support for double-double 2022-04-24 07:43:02 -07:00
ffb5e6a732 Suppress a -Wliteral-range warning on Apple M1 (#2861) 2022-04-19 11:10:18 -07:00
5d804ee7fe Fix handling of subnormals in exotic FP 2022-04-17 08:56:35 -07:00
86e27ccb41 Suppress a warning 2022-04-12 09:30:29 -07:00
192f79aaae Fix handling of locale separators in FP formatting 2022-04-12 08:00:17 -07:00
395cf0f03e Fix detection of unformattable pointers 2022-04-12 06:45:46 -07:00
fc429d18b6 Avoid overhead on sensible platforms 2022-04-11 16:52:34 -07:00
ce7ecdb7af Replace conditional compilation with SFINAE 2022-04-11 12:16:05 -07:00
8751a03a04 Fix Unicode handling when writing to an ostream 2022-04-10 09:46:01 -07:00
c55175a589 Add an issue template 2022-04-08 07:53:42 -07:00
a935ac3e60 MSVC CMake generation optimization (#2852) 2022-04-08 06:27:23 -07:00
22d31b31f0 Add a __float128 test 2022-04-03 14:56:29 -07:00
f607e3e970 Add __float128 support 2022-04-03 12:58:06 -07:00
686de58886 Implement 128-bit constant mul in bigint 2022-04-03 07:24:18 -07:00
02eb215f2f Replace uint128_wrapper with uint128_fallback 2022-04-02 18:01:41 -07:00
b4dc7a1d34 Add 128-bit operations to bigint 2022-04-02 09:29:13 -07:00
ef54f9aa38 Suppress -Wfloat-equal 2022-04-01 12:18:22 -07:00
288c3b928b Remove dead code in ostream.h format_value 2022-03-29 10:21:19 -07:00
96930161f9 Implement 128-bit operator+= for uint128_fallback 2022-03-27 08:07:54 -07:00
b41890c1e5 Make arg_mapper SFINAE-friendly again 2022-03-27 07:10:15 -07:00
e2408f37c8 Check if formatter is not defined if there is format_as 2022-03-26 09:44:49 -07:00
db5b8993ac Fix formatting of std::byte via format_as 2022-03-26 09:01:30 -07:00
1c83eaf75e Fix incompatible between Jinja2 >= 3.1 and sphinx 3.3.0 2022-03-26 07:30:17 -07:00
5379063b54 Fixed clang -Wreserved-identifier warings
Created FMT_UNCHECKED_TYPE that resolves to special identifier _Unchecked_type for Microsoft, but to a dummy string otherwise. Using
_Unchecked_type is invalid because underscore + uppercase is a reserved identifier.
2022-03-24 07:33:43 -07:00
b591fc87dc Fixed all clang -Wreserved-id-macro warnings (on macOS at least)
Avoid defining various reserved identifiers (starting with underscore and capital letter).  Fortunately, they were all Windows-only, so it was easy to conditionalize them in Window-only preprocessor checks.
2022-03-24 07:33:43 -07:00
17dda58391 constexpr -> const for portability 2022-03-23 21:14:22 -07:00
7ffe87c0bc Fix docs 2022-03-22 19:13:01 -07:00
3c4273dd09 Simplify UDL 2022-03-22 17:43:37 -07:00
36d95c9fcc Fix docs 2022-03-22 17:31:31 -07:00
44abd1f483 Update signatures in docs and ostream.h 2022-03-22 16:05:30 -07:00
db745986f2 Workaround broken std::numeric_limits 2022-03-20 08:50:52 -07:00
8271e43e5e Improve __float128 support and use constexpr 2022-03-20 07:20:41 -07:00
3f9b7433a3 Improve __float128 support 2022-03-19 09:44:14 -07:00
71778e8b90 Specialize float_info for __float128 2022-03-19 08:39:16 -07:00
f024565c3f Improve exponent handling in Dragon 2022-03-19 08:23:32 -07:00
e7f31f5cdb Cleanup format_dragon 2022-03-18 16:03:19 -07:00
3c61799fbf Cleanup fuzzing mode 2022-03-18 12:01:52 -07:00
4e39e13085 Remove xchar.h include from ostream.h 2022-03-18 10:53:15 -07:00
ac0d9d5fe2 Issue #2816: also strip named-arg for the fallback formatter 2022-03-18 10:11:14 -07:00
4ad90578f7 Fix #2818: diagnose unformattable arguments in unpacked case 2022-03-18 10:11:14 -07:00
17ba99c1d2 Fix #2817: add compile-time checking to ostream overloads of fmt::print 2022-03-18 10:11:14 -07:00
3d19be282a Fix #2816: strip named argument wrappers for compile-time checking 2022-03-18 10:11:14 -07:00
c076a54a4d Move snprintf_float to format.h 2022-03-18 08:31:31 -07:00
0419d23882 Add FMT_USE_FLOAT128 2022-03-18 07:43:51 -07:00
cre
69396347af Update color.h (#2815)
fixed typo in comment
2022-03-17 10:55:02 -07:00
c51604a0e1 Reduce the number of configs 2022-03-15 18:20:59 -07:00
587dc9946d Remove windows-2016 env no longer suppported by GA 2022-03-15 18:16:13 -07:00
1f3d44b859 Update std::tm/chrono docs 2022-03-15 16:53:51 -07:00
bc654faf82 Add is_floating_point that works with __float128 2022-03-15 08:26:05 -07:00
26bffce66d Simplify basic_memory_buffer 2022-03-15 07:15:52 -07:00
ed18ca3eae Implement isnan 2022-03-14 20:37:46 -07:00
a204b8dde7 Add initial __float128 support 2022-03-14 19:34:41 -07:00
b6b003b073 Cleanup test 2022-03-14 15:48:38 -07:00
f2543b0a98 Add initial support for 128-bit floats 2022-03-14 14:00:15 -07:00
72f487562d Simplify float_info 2022-03-14 13:37:03 -07:00
f91f61cd13 Reuse num_significand_bits 2022-03-14 11:34:24 -07:00
9a1beab574 Workaround Windows API garbage 2022-03-11 17:31:39 -08:00
a8fe8becf4 Fix compilation error for ranges with ADL begin/end (#2807)
* Use `range_begin`/`end` to get formatted range iterators

* Add test for adl `begin`/`end`

* Apply clang-format

* Simplify tests
2022-03-11 11:36:39 -08:00
f6bcb25e16 Remove extra dot 2022-03-10 16:26:17 -08:00
b4a4189d0c Fix handling of implicit bit 2022-03-10 15:34:56 -08:00
32d477e5f1 Add styled in documentation (#2805) 2022-03-10 12:24:47 -08:00
0b7c045a2f Simplify _cf 2022-03-08 15:31:51 -08:00
c10fffecdc Make _cf visible in the doc build 2022-03-08 11:00:04 -08:00
dcfbe4a77a Document output_file default behavior correctly (#2803)
The documentation for output_file incorrectly says that opening an output file happens with `file::WRONLY | file::CREATE` by default, but this includes `file::TRUNC` is also included since 119f7dc3d.
2022-03-08 10:02:22 -08:00
8c9bc070f5 Implement styled arguments (#2793)
* Implement styled arguments

* Inherit from formatter<Arg> to get the underlying `parse` and `format`

* Move styled_arg definition into the previous detail block

* Change styled_arg ctor parameters names to avoid shadowing members

* Move const before auto

* Remove redundant constructor for styled_arg

* Use the iterator instead of the buffer in styled_arg::format

* Remove unnecessary `styled` overloads

* Remove defaulted text_style parameter in styled function
2022-03-08 09:50:14 -08:00
5bc39d363a Eliminate intel compiler warnings (#2802)
The intel compiler emits  `declaration hides parameter "loc" ..."  and similar warnings for "out" and "args" since the function arguments are the same as other visible symbols.  This is for intel-2021.3.0 20210609.
2022-03-07 15:34:33 -08:00
e3d688e79a Fix warning C4251: class fmt::v8::file needs to have dll-interface (#2797)
* Fix warning C4251: class fmt::v8::file needs to have dll-interface

* Add CMake target dependency between test-main and fmt
2022-03-07 12:09:48 -08:00
8d4f3e91b2 Update docs 2022-03-06 10:12:40 -08:00
0cef1f819e Fixing formatting of certain kinds of ranges of ranges. (#2787)
* Fixing formatting of certain kinds of ranges of ranges.

* Renaming const_range to range_type.
2022-03-04 16:21:00 -08:00
5c0d656401 Fix apt install 2022-03-03 15:50:25 -08:00
d416a995ea Update README.rst 2022-03-01 13:53:02 -08:00
3f67a12477 Update README.rst 2022-03-01 13:48:54 -08:00
cc57e35974 Update godbolt link in the readme (#2789) 2022-02-25 13:47:23 -08:00
86477f7ecc Fix size computation 2022-02-22 17:21:07 -08:00
0742606f19 Fix Conversion Warning (#2782)
With -Wconversion and 32 Bit I get a warning here with unsigned long
long converted to unsigned long.
2022-02-22 08:16:36 -08:00
1ba69fb5a1 Remove snprintf FP fallback 2022-02-21 08:01:55 -08:00
ea6f0bf0e5 Minor cleanup 2022-02-21 07:29:36 -08:00
1a18a2f3dd Fixing "C4127: conditional expression is constant" Visual Studio 2022 warning in pedantic mode (#2783) 2022-02-21 07:26:16 -08:00
4fcacea354 Parameterized fp on significand type 2022-02-21 07:25:13 -08:00
cf940ae82e Simplify to_decimal 2022-02-20 19:38:02 -08:00
70dc3de053 Update format.h
To prevent the following compiler message:
[...]/include/fmt/format.h:392:20: warning: conversion to 'long unsigned int' from 'int' may change the sign of the result [-Wsign-conversion]
  392 |     unsigned value[size];
      |                    ^~~~
2022-02-20 11:38:03 -08:00
cbc59ca893 Clear moved from memory buffer 2022-02-20 08:12:59 -08:00
ea3d326c63 Fix clang -Wliteral-range warning (#2779) 2022-02-19 10:52:33 -08:00
aad44f2839 Add fmt::enums::format_as 2022-02-19 08:03:42 -08:00
1319719a5e Add underlying_t 2022-02-19 07:57:43 -08:00
af5d8004fc Limit Dragonbox to supported FP formats 2022-02-19 07:14:18 -08:00
7b96420961 Remove unused include 2022-02-18 18:56:51 -08:00
a0b43bfae2 Add support for 96-bit long double 2022-02-18 18:01:49 -08:00
2c8cd2db34 Fix handling of zero precision 2022-02-18 12:38:30 -08:00
b6d56170fc Remove unnecessary inline 2022-02-18 07:41:55 -08:00
05432e570e Use consistent indentation 2022-02-18 07:38:42 -08:00
47da218cc3 Remove uintptr_fallback 2022-02-18 07:03:33 -08:00
4ddab8901c Merge accumulator into int128_fallback 2022-02-18 06:17:28 -08:00
d38f72aff2 Refactor fallback ints 2022-02-17 20:24:42 -08:00
15c2a3bacc int128_t -> int128_opt 2022-02-17 20:03:25 -08:00
532a69a639 Fix handling of 96-bit long double with -m32 2022-02-17 15:51:59 -08:00
d8e1dd4ab2 improve installing headers 2022-02-17 08:13:26 -08:00
ae25f7968e add ability to build Apple framework using CMAKE_FRAMEWORK 2022-02-17 08:13:26 -08:00
ce93a66dfb Implement a fallback uint128_t 2022-02-17 07:37:09 -08:00
6a13464059 Include 128-bit with other signed integers in specifier check 2022-02-16 16:57:06 -08:00
70de324aa8 Apply 2746 fix for NVidia compiler also (#2770) 2022-02-16 12:04:16 -08:00
a1ea3e015b Move built-in formatter specialization to core 2022-02-16 07:37:00 -08:00
161059dd98 Add support for extended precision FP 2022-02-16 06:07:04 -08:00
c4c6b42de7 Bump version 2022-02-15 13:36:59 -08:00
21785040c7 Fix markup 2022-02-15 13:28:53 -08:00
2b6f7fc7a3 Add partial support for extended precision FP 2022-02-15 07:22:41 -08:00
0a24a0714e Clz builtin may be not constexpr (Issue #2761) (#2762) 2022-02-14 18:19:06 -08:00
ba6f89c76e Update .bazelversion (#2766) 2022-02-14 06:08:46 -08:00
5594edaf67 Address https://github.com/fmtlib/fmt/issues/2763 (#2765) 2022-02-13 20:14:28 -08:00
10e3b83a75 Replace `make_args_checked with make_format_args` (#2760)
* Replace make_args_checked to make_format_args

* Deprecate legacy make_args_checked
2022-02-13 20:13:35 -08:00
c48353cb75 Update docs 2022-02-13 07:41:15 -08:00
083510f0f0 Add FMT_CONSTEXPR to rotr instead 2022-02-13 06:15:17 -08:00
dba99bc860 Revert adding constexpr to rotr to satisfy C++11 compilers 2022-02-13 06:15:17 -08:00
c04af4bfc7 Simplify remove_trailing_zeros 2022-02-13 06:15:17 -08:00
b348caa9e9 Remove some C-style casts for consistency 2022-02-13 06:15:17 -08:00
c8bd1e646e Simplify remove_trailing_zeros 2022-02-13 06:15:17 -08:00
9b23e9dcb8 Fix wrong comment/refer to a correct reference 2022-02-13 06:15:17 -08:00
69f2c550ab Remove std:: infront of uint32_t/64_t & add constexpr to rotr 2022-02-13 06:15:17 -08:00
9b62310f03 Fix some conversion issues 2022-02-13 06:15:17 -08:00
08d12f31d1 Fix typo 2022-02-13 06:15:17 -08:00
dbddb1d066 Remove literal separator to satisfy some compilers 2022-02-13 06:15:17 -08:00
7dbe3dcded Recover log10_2_significand 2022-02-13 06:15:17 -08:00
10642e6082 Optimize remove_trailing_zeros 2022-02-13 06:15:17 -08:00
7b4323e1e0 Add rotr 2022-02-13 06:15:17 -08:00
f1bd6f7731 Check r < deltai first, because that is the major branch chosen for short inputs 2022-02-13 06:15:17 -08:00
5d8eb6a1a0 Reflect the new paper
- Change constants appearing in log & division computations
  - Rename beta_minus_1 to beta
2022-02-13 06:15:17 -08:00
8e2e4d4034 Suppress a gcc warning 2022-02-12 09:26:48 -08:00
a44716f58e Workaround to Intel compiler (#2758) 2022-02-11 06:25:42 -08:00
c71b070168 Add missing const qualifier (#2755) 2022-02-10 10:51:32 -08:00
ecd6022c24 Update docs 2022-02-08 06:28:22 -08:00
afbcf1e8ea Remove legacy C locale wrapper 2022-02-05 12:37:21 -08:00
90325d0970 Fix stored type detection 2022-02-05 10:44:34 -08:00
e2ba01fcb0 Fix overload ambiguity in print 2022-02-05 08:35:19 -08:00
17b362f78c Simplify ostream opt-in API 2022-02-04 18:33:59 -08:00
a5a7e3a261 Update docs 2022-02-04 15:42:22 -08:00
f055ebbd25 Make ostream operators opt in to reduce the risk of ODR violations 2022-02-04 15:06:45 -08:00
8a21e328b8 Remove problematic constructibility check 2022-02-04 12:20:02 -08:00
31e743d06e Don't use ostream for types convertible to string_view 2022-02-04 11:00:00 -08:00
35c0286cd8 Simplify byte handling 2022-02-02 16:13:24 -08:00
c7173a36a1 Drop :: and fix formatting 2022-02-02 07:00:33 -08:00
3e8372b96e qualify unqualified calls to format in compile.h (#2742) 2022-02-01 18:41:19 -08:00
a34a97cc1d Supporting ? as a string presentation type (#2674)
* Supporting ? as a string presentation type.

* Supporting ? as a char presentation type.

* Adding iterator_category to counting_iterator.
2022-01-30 08:55:28 -08:00
ae1aaaee5f Fix access mode of files created (#2530) (#2733)
The previous fix for this in 4a85db1 was incomplete. The intent was to
mimic what `fopen()` is doing. As per standard[1] `fopen()` also sets
`S_IWGRP` and `S_IWOTH` and lets the umask handle the rest.

[1] https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/fopen.html
2022-01-28 17:12:49 -08:00
1557ab7644 Add format_as for enums 2022-01-28 06:38:02 -08:00
b00a1eac75 Fixes NVIDIA HPC compiler and Intel ICC compatibility (#2732)
* Fixes NVIDIA HPC compiler and Intel ICC compatibility

* Fixes NVIDIA HPC compiler and Intel ICC compatibility

* Rename FMT_NVHPC_VERSION to FMT_NVCOMPILER_VERSION

Co-authored-by: Federico Busato <fbusato@nvidia.com>
2022-01-26 15:53:04 -08:00
a7aecbfcaa Remove an old mingw workaround 2022-01-23 09:44:53 -08:00
dfcc730cbd Making target_compile_options PRIVATE, fix #2726, fix #2507 2022-01-23 09:36:11 -08:00
f7a809be6e Clarify the choice of magic numbers and compute the most magic one
https://github.com/fmtlib/fmt/pull/2713#discussion_r788349826
2022-01-23 08:58:58 -08:00
09fde7f4b8 Add fmt::underlying for enum classes 2022-01-22 08:06:22 -08:00
0014024a2c Don't rely on transitive includes 2022-01-21 15:03:28 -08:00
c28500556a FMT_NOEXCEPT -> noexcept 2022-01-20 16:55:47 -08:00
6240d02011 Improve comments 2022-01-19 17:03:44 -08:00
925b744ae8 Improve comments 2022-01-19 17:03:44 -08:00
22b14ff252 Simplify cache recovery 2022-01-19 17:03:44 -08:00
3dc26b44d3 Make a fallback path more compiler-friendly 2022-01-19 17:03:44 -08:00
2e4038bf51 Simplify lines with __builtin_addcll and friends 2022-01-19 17:03:44 -08:00
76336b4f63 Replace noexcept with FMT_NOEXCEPT 2022-01-19 17:03:44 -08:00
9181983483 Fix syntax errors 2022-01-19 17:03:44 -08:00
74097a149b Remove now-unused stuffs 2022-01-19 17:03:44 -08:00
21a1c53381 Fix typo 2022-01-19 17:03:44 -08:00
04eea0f0a8 Remove now-unused stuffs 2022-01-19 17:03:44 -08:00
35a468ed38 Simplify integer checks 2022-01-19 17:03:44 -08:00
1882a7a2c1 Replace Dragonbox cache which allows simpler cache recovery & integer checks 2022-01-19 17:03:44 -08:00
f4dd1b1b8b Simplify Dragonbox Step 3. 2022-01-19 17:03:44 -08:00
70561ed13e Minimize the usage of built-in 128-bit ints
It usually generates slower code than manual handling.
2022-01-19 17:03:44 -08:00
cdf1a3b530 Fix codecvt warning (#2408) (#2725) 2022-01-19 10:26:09 -08:00
b8b037e930 Fix -Wconversion warning (#2724)
* - try fixing the warning "chrono.h:1217:37: warning: conversion from 'std::make_unsigned<long long int>::type' {aka 'long long unsigned int'} to 'size_t' {aka 'unsigned int'} may change value [-Wconversion]" by casting int to size_t (occurs when cross-compiling to Raspberry Pi ARMv7)

* - remove call to to_unsigned() because using static_cast<size_t> is enough
2022-01-19 06:31:33 -08:00
5985f0a7d2 Fix overflow for chrono durations (#2722) 2022-01-17 12:14:59 -08:00
8f8a1a02d5 Fix handling of formattable types implicitly convertible to pointers 2022-01-14 13:42:01 -08:00
b02e5af52c fmt::join support FMT_COMPILE (#2720) 2022-01-14 09:58:49 -08:00
58fb782396 Improve docs 2022-01-13 14:57:17 -08:00
4fe6129d6c Fix FMT_NOEXCEPT definition 2022-01-13 10:20:32 -08:00
c056a009de Docs: Fix link to "Compile-time Format String Checks" section (#2712) 2022-01-12 16:07:56 -08:00
7c12118c19 Deprecate buffered_file::fileno 2022-01-12 10:54:44 -08:00
2a09d468da Use noexcept unconditionally 2022-01-12 09:42:29 -08:00
a126b4d888 Check if right shift is arithmetic 2022-01-11 08:23:30 -08:00
9ff91b18cd Simplify write_fractional_seconds 2022-01-09 15:08:46 -08:00
d9f045fba1 Fix a UB in chrono 2022-01-09 14:06:13 -08:00
c06bef7273 Adding comments for range formatting. (#2706)
* Adding comments for range formatting.

* Adding missing quotes
2022-01-08 16:37:21 -08:00
3c98f1a4cd Comment style 2022-01-08 09:52:39 -08:00
6e0f1399d7 Supporting nested format specs for ranges. (#2673)
* Supporting nested format specs for ranges.

* I dedicate this commit to Eric Niebler.

* clang-format

* PR comments.

* throw -> FMT_THROW

* Need to map every element too.

* Clarifying uncvref_type

* Trying to add a workaround for MSVC.
2022-01-08 09:48:26 -08:00
0102101acc Make colored print handle UTF-8 (#2701)
* Fix #2681 - Make detail::print handle UTF-8

* Okay, let's do this Windows-only

* drop extra \0

* yay we can throw!
2022-01-06 16:10:53 -08:00
4ac5269b4f Update ChangeLog.rst 2022-01-06 15:03:01 -08:00
b6f4ceaed0 Update version 2022-01-06 14:35:15 -08:00
15f812dae8 Update changelog 2022-01-06 14:13:01 -08:00
6884aab49b Update changelog 2022-01-06 12:38:33 -08:00
88ec4e7061 Bump version 2022-01-06 12:32:43 -08:00
dd3d2490ed Update changelog 2022-01-06 12:07:13 -08:00
739055ae7b Fix apidocs 2022-01-06 11:06:39 -08:00
dbbd711f46 Suppress a warning 2022-01-05 09:41:35 -08:00
98cbb6a43c Fix ABI compatiblity issue 2022-01-05 08:08:38 -08:00
214cf13f17 Fix endianness bug in write_digit2_separated (#2699)
* Fix endianness bug in write_digit2_separated

* Move endianness check to compile time if it possible

* Turn 8 into a constant
2022-01-04 14:23:42 -08:00
17a5c808da Restore FMT_API on error_handler::on_error() (#2696)
this fixes a breaking ABI change that was introduce in the upgrade from
8.0.1 to 8.1.0.

Fixes #2695.
2022-01-04 10:53:44 -08:00
fc1783fcc6 Avoid undefined symbols with mingw-w64 (#2692)
Fixes issue #2691
2022-01-03 15:29:29 -08:00
1b193e7b37 Deprecate more 2022-01-03 11:13:09 -08:00
8e59744b8d Switch to new github auth mechanism 2022-01-02 09:29:42 -08:00
7081a6aa34 Update version 2022-01-02 09:01:32 -08:00
64dc8fbada Bump version 2022-01-02 08:34:01 -08:00
fc8e3de7db Fix manage.py script 2022-01-02 08:22:25 -08:00
57bee9fcdd Fix formating 2022-01-02 08:09:55 -08:00
dce52e491e Update changelog 2022-01-02 08:02:45 -08:00
9405a47245 Update changelog 2022-01-02 07:57:36 -08:00
495b8bf12e Update changelog 2022-01-01 13:56:31 -08:00
e221166fab Update changelog 2022-01-01 11:34:04 -08:00
035cab8da3 Update changelog 2022-01-01 09:36:40 -08:00
89c6ed12bf Clarify in comments (for now) deprecated map functions 2022-01-01 09:29:50 -08:00
e462da828d Add some noexcept (#2684)
I got warnings from -Wnoexcept, fixed them.
2022-01-01 08:44:00 -08:00
79c66d66bd Update changelog 2021-12-29 15:33:30 -08:00
5d37f705f4 Update changelog 2021-12-29 15:31:03 -08:00
6bb370cec1 Update changelog 2021-12-29 15:26:11 -08:00
bb69201578 Fix tuple join 2021-12-29 14:46:45 -08:00
4fac7daaef Cleanup bit_cast 2021-12-29 12:14:51 -08:00
3617c2795a Update changelog 2021-12-29 08:25:12 -08:00
9c0c1bcdbd Simplify tuple formatting 2021-12-29 08:03:12 -08:00
187e8db1be Update changelog 2021-12-28 08:11:03 -08:00
c7f88180f6 add tests for format string compile-time checks 2021-12-27 20:55:06 -08:00
8a2c3fb88f add reverse tests to compile-error-test
to make sure that error tests do not fail because they become outdated
2021-12-27 20:55:06 -08:00
1164eda5af disable compile-error-test on Windows
since it takes too much time to complete, similar to other tests with additional
CMake invocation
2021-12-27 20:55:06 -08:00
4482f6f1f0 rewrite compile-error-test to use non-header-only library 2021-12-27 20:55:06 -08:00
796662a612 Escape range items convertible to std::string_view 2021-12-27 09:38:06 -08:00
33ee4cc516 Improve noexception test 2021-12-26 16:28:41 -08:00
3bbf2c673c Fix throw with exceptions disabled 2021-12-26 16:28:41 -08:00
074c9c52ef Update changelog 2021-12-26 08:36:29 -08:00
3110ec5a23 Update changelog 2021-12-26 08:19:32 -08:00
3014b3d770 Clarify that C strings must be null-terminated 2021-12-26 07:23:43 -08:00
eab2ea9fc2 Replace an assert with an exception 2021-12-26 07:05:45 -08:00
21ed92a6e9 Update changelog 2021-12-24 07:25:23 -08:00
04111dd1e4 Fix issue #2670 (#2671) 2021-12-23 12:38:48 -08:00
817788fbf0 remove incorrect C++20 check from test/CMakeLists.txt (#2663)
It disables entire branch of tests declaration unconditionally because CXX_STANDARD
is not defined there. But even we use CMAKE_CXX_STANDARD here, these tests should
not be disabled with standard >= C++20.
2021-12-23 12:32:03 -08:00
4511030af2 Minor code style tweaks for consistency 2021-12-23 11:55:58 -08:00
7812813a32 Don't explicitly delete copy ctor of dynamic_format_arg_store (#2664)
* Don't explicitly delete copy ctor of dynamic_format_arg_store

Explicitly deleting the copy ctor causes the move constructor to not be
implicitly generated. This behaviour is different than what was in
v8.0.1 and causes code that relied on the move ctor of
dynamic_format_arg_store to break.

* Add test for dynamic_format_arg_store's move ctor

* include <memory>, don't use make_unique
2021-12-23 11:34:16 -08:00
664cd6067d Remove std-format-test 2021-12-23 10:58:02 -08:00
784e2a7b42 Fix an overflow when formatting very large durations 2021-12-23 10:34:32 -08:00
fc2a376d8e Remove two expressions which had no effect (reported by LGTM)
Signed-off-by: Stefan Weil <sw@weilnetz.de>
2021-12-22 16:29:16 -08:00
c5aafd8f90 expose headers as SYSTEM depending on special configuration option 2021-12-19 08:29:51 -08:00
eaddd1e3cd Fix handling of byte 2021-12-19 06:46:24 -08:00
2d44577586 Try fixing byte regression 2021-12-18 08:51:21 -08:00
e46392ea2c deprecate _format UDL in code using FMT_DEPRECATED 2021-12-18 08:33:20 -08:00
c882790a2e Add a set formatter 2021-12-18 07:35:40 -08:00
121002d700 Add a map formatter 2021-12-18 07:12:53 -08:00
be51ee1ceb Disable broken copy ctor of dynamic_format_arg_store 2021-12-17 17:18:18 -08:00
659de779e6 Fix a UB in parse_format_specs when begin is null 2021-12-17 16:51:24 -08:00
51b14b6c0c remove commented out lines 2021-12-17 16:05:56 -08:00
223a0fa55d move gtest-specific check into gtest/CMakeLists.txt 2021-12-17 16:05:56 -08:00
ef72b471fc enable named arguments check in compile-time checks (#2649)
works only if all named arguments are UDL-based
2021-12-17 15:53:05 -08:00
82246b8766 fix throw with exceptions disabled (#2647) 2021-12-17 13:44:36 -08:00
35f60377aa Update ChangeLog.rst 2021-12-17 06:49:29 -08:00
3a951a66cb Avoid qualifying by inline namespace. Fixes #2642. (#2643) 2021-12-10 08:28:25 -08:00
e0136fc8bd Qualify calls to make_wformat_args. Fixes #2639. (#2641) 2021-12-10 06:36:42 -08:00
ac1b5f3da5 Refactor problematic trailing returns in arg_mapper 2021-12-09 18:08:30 -08:00
fd62fba985 Don't convert scoped enums to integers 2021-12-09 12:09:33 -08:00
c652f8243a Make header guard consistent with header name 2021-12-09 10:49:47 -08:00
a9c7b9b8f7 Clarify that _format is deprecated 2021-12-09 10:34:27 -08:00
e4f0564aa6 Disable is_streamable for string[_view] 2021-12-09 10:02:18 -08:00
91533d3c33 Minor tweaks to chrono subsecond formatting 2021-12-09 06:55:31 -08:00
0bbc9708f9 Implement c++20 std::chrono::duration subsecond formatting (#2623)
* Add support for subsecond printing for std::chrono::duration according to the c++20 standard

* Remove assert test that overflows intmax_t

* * Hopefully fix int64_t to int32_t conversion errors.
* Allow proper Duration::rep type to propagate via template argument deduction

* * Hopefully fix int64_t to int32_t conversion errors.
* Allow proper Duration::rep type to propagate via template argument deduction

* Fix sign conversion (-Wsign-conversion) warning treated as error in num_digits()

* Format chrono.h with clang-format

* Remove extra forward slash in doxygen style comment

Co-authored-by: Victor Zverovich <victor.zverovich@gmail.com>

* Apply all suggestions from GitHub, except for replacing the utility subsecond_helper class with a function

* * Move logic of handling subseconds from utility class to function with name write_fractional_seconds()
* Revert write(Rep value, int width) function to previous state

* Fix -Wshadow warning

* Remove unsued get_subseconds() function, its logic has been moved to write_fractional_seconds()

* Change comment from lowercase int to uppercase Int

* Simplify test check

* Integrate suggested changes

* Remove static from detail functions, they are no longer member functions of a class and static is unnecessary.
* Change comment from "amount" to "number"

Co-authored-by: Victor Zverovich <victor.zverovich@gmail.com>
2021-12-09 06:45:13 -08:00
9d5b9defde Enable tzset only on Windows desktop app (#2633) 2021-12-07 15:22:36 -08:00
215f21a038 Detect overflow on large precision 2021-12-05 07:26:58 -08:00
c240d98ffd Optimize tm formatting (Non C-locales and %Z) (#2617)
* Move fmt::detail::formatbuf to format.h

* Replace std::basic_ostringstream to std::basic_ostream with custom formatbuf

* Use tm.tm_zone
2021-12-04 11:02:31 -08:00
6ab73113fc Mark grow as FMT_CONSTEXPR20 (#2630)
resolves https://github.com/fmtlib/fmt/issues/2627
2021-12-03 07:13:30 -08:00
713c7c7c62 Cleanup os.cc 2021-12-01 06:47:41 -08:00
9b1807a8a2 fix int -> uint warning (#2611)
* fix int -> uint warning

* change unsigned int to mode_t

* undef + warn uint -> ushort loss presision

* fix mode_t

* mode_t in detail

Co-authored-by: Acretock <George.Goncharov@finch-xr.com>
2021-12-01 06:40:17 -08:00
ec3b097cb9 [doc] FMT_STRING supports C++14 and no-op in C++11 (#2620)
* FMT_STRING supports C++14 and no-op in C++11

* Move requirement to the end. Modify description.
2021-11-28 07:02:15 -08:00
c472a27818 Fix handling of very large precision in fixed format 2021-11-27 08:23:05 -08:00
201971e293 Make MSVC use [[nodiscard]] (#2615)
* Make MSVC use [[nodiscard]]
* Uniformly detect attributes for __cplusplus and _MSVC_LANG
2021-11-26 07:32:50 -08:00
acad8cfab1 Reformat all source code; no functional changes
Before adding the format checker, the mainline should be clean, to
avoid false failures.
2021-11-25 09:15:25 -08:00
491ba2dda5 Annotate fmt::format and fmt::formatted_size as [[nodiscard]]
This prevents accidentally writing fmt::format when fmt::print was
intended. Other than running tests, there's not a good use case for
discarding the formatted output.
2021-11-25 07:30:30 -08:00
5abe9e8266 Add platform-specific 'z' formatter 2021-11-25 06:52:39 -08:00
be3a3a5aed Use predefined formats for C-locale 2021-11-25 06:52:39 -08:00
a3ab36c803 Formatting of function pointers, member function pointers, member object pointers... (#2610) 2021-11-23 12:55:22 -08:00
19cac63fe4 Broken link in README.rst
Added src directory to link
2021-11-19 09:24:38 -08:00
43419a4ada Workaround a bug in gcc 2021-11-19 07:32:42 -08:00
c089f7d497 Simplify std::tm formatter 2021-11-14 07:16:22 -08:00
aa5517f6b9 Reuse tm_writer in chrono_formatter 2021-11-14 07:16:22 -08:00
50140be7ae Reuse tm_writer in weekday formatter 2021-11-14 07:16:22 -08:00
8b89454994 Improve consistency 2021-11-13 08:59:56 -08:00
5380ff4d88 Detect types convertible to unformattable pointers 2021-11-13 08:26:27 -08:00
094b66e81d changed locale retrieval way to a fancy one 2021-11-12 12:46:38 -08:00
b69ae4854c Reorder classes (#2591) 2021-11-10 17:09:23 -08:00
0b843af56b sped up chrono.h formatting for cases without providing locale (#2576) 2021-11-07 08:52:57 -08:00
12b1d8b14a Fix precision 0 with std::chrono::duration and added additional tests. (#2588) 2021-11-06 08:57:22 -07:00
e67f92c55c Cleanup warnings with nvhpc/21.9. (#2582)
* Cleanup warnings with nvhpc/21.9.

* Move __NVCOMPILER check.

* Be more explicit.

* Immediately executed lambda.

* Fix shadowing warning.
2021-11-05 12:17:11 -07:00
812733cc96 const qualify format function for systen_clock 2021-10-31 09:41:16 -07:00
028f227752 Handle implicit conversions in write 2021-10-31 08:58:54 -07:00
5b0aa638cf Minor grammar fix 2021-10-30 09:14:13 -07:00
6eaceb5f73 Fix incompatible between docutils 1.18.0 and sphinx 3.3.0 (#2575) 2021-10-30 09:12:36 -07:00
0697c5edb6 FMT_USE_FCNTL can be predefined (#2573)
'os.h' accepts a predefined FMT_USE_FCNTL override so using FMT with e.g. the NXP toolchain for ARM (e.g. for FreeRTOS) does not have a fcntl() call, but the detection routine does not detect this correctly.
2021-10-30 08:35:48 -07:00
1031eedf27 Replacing strftime with std::time_put (#2550)
* Fix unicode test

* Add xchar support to chrono formatter

* Replace strftime with std::time_put

* Add std::locale support to std::tm formatter

* Use predefined names and formats for C-locale

* Performance improvement

* Make locale-independent and C locale formats consistent among platforms
2021-10-30 08:25:45 -07:00
90034e4c4b Add FMT_ASSERT and validation of values of struct tm members (#2564)
Switch internal year calculations to long long
2021-10-27 13:29:07 -07:00
df40e94673 Upgrade module-test to msvc 16.11.5 and 17.0-pre5 (#2558) 2021-10-24 08:12:39 -07:00
e6d5059cbb Simplify js tag in basic-bootstrap theme (#2562)
When build the docs for debian package, it uses a sphinx building
helper, which does a sanity check for the output.

The sanity check complains missing data-url_root attribute in the
js tag. So this patch changes the js tag to use the same function like
the origin basic theme, which adds additional information like
data-url_root.

Ref: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=997437
2021-10-24 06:36:10 -07:00
3b6e409cd8 Enable consteval for msvc 17.0-pre5 (#2559) 2021-10-23 07:19:57 -07:00
249f03bbb7 do not detect LLVM based IBMXL compiler (on ppc) as clang (#2555) 2021-10-20 06:21:49 -07:00
7463c83205 Fix overflow for very bigger years (>2*10^9) (#2551) 2021-10-19 07:04:55 -07:00
1266c2b600 Fix handling of exotic character types 2021-10-17 09:07:48 -07:00
684e2fdc94 Minor cleanup 2021-10-17 06:33:27 -07:00
a1d586302f Minor cleanup 2021-10-17 06:07:03 -07:00
7a604cdd98 Cleanup 2021-10-16 15:03:57 -07:00
aeb54b0dd9 Fix bug on '%Y' and '%C' formats with negative years
Requested changes
2021-10-16 15:03:57 -07:00
f88c020fc0 Generalization of strftime/wcsftime function calls in tests 2021-10-16 15:03:57 -07:00
2eeddba756 Renaming, splitting of functions 2021-10-16 15:03:57 -07:00
2754546080 Fix errors in ISO week-base-year formatter 2021-10-16 15:03:57 -07:00
218cecb6d1 Fix error in test 2021-10-16 15:03:57 -07:00
e9f4453b0e Fix Microsoft Visual Studio 14.0 build 2021-10-16 15:03:57 -07:00
27c3674ce1 Improve performance 2021-10-16 15:03:57 -07:00
5dc3dd3d4a New tests 2021-10-16 15:03:57 -07:00
f8542cd988 Unified formatters for std::chrono::time_point<std::chrono::system_clock, Duration> and std::tm 2021-10-16 15:03:57 -07:00
4707373d33 Fix year formatter 2021-10-16 15:03:57 -07:00
79c00ad8f2 Improve ISO week-base-year formatter 2021-10-16 15:03:57 -07:00
fbaaa5906b Improve week of the year formatter 2021-10-16 15:03:57 -07:00
cde44ddb72 Improve year formatter 2021-10-16 15:03:57 -07:00
b04601b918 Switch from std::strftime/std::wcsftime to internal implementation for locale independent formats 2021-10-16 15:03:57 -07:00
d3d30a46f0 New tests 2021-10-16 15:03:57 -07:00
7911d8d3f5 Add format spec checker 2021-10-16 15:03:57 -07:00
fbbfc3b03c Reorder formatters 2021-10-16 15:03:57 -07:00
509eac9575 Workarounds for implementation-defined std::strftime behavior 2021-10-16 15:03:57 -07:00
85b38190d1 New tests for all C++11 std::strftime format specifiers 2021-10-16 15:03:57 -07:00
7aca36bca4 Extending fmt::join to support C++20-only ranges. (#2549) 2021-10-16 10:02:03 -07:00
f5371a75f4 locale.h -> format.h 2021-10-14 15:57:10 -07:00
febdef43f5 fix: add workaround for intel parameter pack bug 2021-10-14 10:44:24 -07:00
f56756986b fix: check to make sure both 'if constexpr' and return type deduction are available
fix: remaining ifdefs
2021-10-14 10:44:24 -07:00
dcd282bb26 Namespace qualify calls to get 2021-10-09 07:15:14 -07:00
9c14474d30 Include <bit> when using std::bit_cast 2021-10-09 06:11:36 -07:00
1e96e01766 Fix compiler flag check (#2540) 2021-10-09 06:05:05 -07:00
7e4bc94510 Speeding up write_significand() (#2499) 2021-10-09 05:27:38 -07:00
26c1ca4c3e Replaced default spec with equivalent one, which is potentially more optimizable (#2537) 2021-10-08 07:09:54 -07:00
1e865b3539 Fix docs 2021-10-03 07:05:31 -07:00
4a85db1ce1 Change default open mode to -rw-r--r-- (#2530) 2021-10-03 06:36:40 -07:00
0a985fd4c6 Move size_ initialization to initializer list (#2529) 2021-10-02 17:20:33 -07:00
012cc709d0 Workaround gcc _Pragma bug 59884 2021-10-02 15:41:47 -07:00
d6590e3bd2 Fix compiler check 2021-10-02 08:46:18 -07:00
134aec40f0 Fix search in docs 2021-10-02 07:58:08 -07:00
48a476ae0f Update example (#2522) 2021-10-02 07:33:33 -07:00
023c2018f7 Don't use strlen in constexpr 2021-10-02 07:17:05 -07:00
800d4c8ac8 Refactor Windows workarounds 2021-10-02 06:06:08 -07:00
32865aeaab changed detection of Intel Compiler Classic to distinguish MS-Windows (#2510)
* changed detection of Intel Compiler Classic to distinguish MS-Windows

* replaced !FMT_ICC_ON_WINDOWS by FMT_ICC_POSIX
removed #pragma manged

* replaced FMT_ICC_POSIX with FMT_ICC_INTRINSIC_BUG to be crystal clear about the macro's purpose
2021-10-02 05:43:41 -07:00
7b339795a1 Describe a better approach of how to use {fmt} as a depency in a Bazel project (#2516) 2021-10-02 05:36:43 -07:00
ae9bbe1169 Suppress warning C4127 in chrono.h (conditional expression is constant) (#2518) 2021-09-30 09:14:38 -07:00
927dbd134d Misplaced comma in README.rst (#2515) 2021-09-28 09:53:37 -07:00
2a9a77dd8c Remove misplaced comment 2021-09-26 18:01:39 -07:00
1aee4bc90a Refactor FP formatting 2021-09-26 14:37:33 -07:00
e1bd6cc913 Refactor FP formatting 2021-09-26 10:25:46 -07:00
027fcaf05e Replace use_grisu with fallback since Grisu is only one of multiple implemented algorithms 2021-09-26 08:44:05 -07:00
716d69f27e Refactor FP formatting 2021-09-26 08:27:18 -07:00
ff7e73af66 Always run grisu_gen_digits before fallback_format 2021-09-26 07:54:25 -07:00
2976e31ac9 Refactor format_float 2021-09-25 11:20:56 -07:00
807ee5ec31 Disable consteval in Apple clang 2021-09-25 05:55:05 -07:00
d9a731d486 Add basic support for Bazel (#2505) 2021-09-24 13:17:26 -07:00
9c57357e05 Add static to a table (#2509) 2021-09-24 06:25:08 -07:00
2742611cad Fix formatting 2021-09-18 11:09:24 -07:00
5092b198bc Document group_digits 2021-09-18 10:50:30 -07:00
b4d9d82e1d make FP formatting available to be used at compile-time (#2426)
* works only with FMT_HEADER_ONLY
* works only with float and double types (not long double)
2021-09-18 08:03:23 -07:00
d9fd695ac7 Fix wchar_t tm formatting 2021-09-15 07:33:24 -07:00
92614ecbf9 Optimize %T in tm formatting 2021-09-15 07:33:24 -07:00
aaeca12d89 Move FMT_MAYBE_UNUSED to format.h where it is used 2021-09-13 07:51:36 -07:00
3d0c7ae385 Move data to format.cc 2021-09-13 06:23:57 -07:00
04e3a79f76 Use memcpy in more cases in copy2 2021-09-12 12:23:45 -07:00
e47e99bb09 Simplify format_decimal (#2498)
* Add copy2() constexpr

* Removed redundant format_decimal implementation for constexpr context
2021-09-12 10:36:06 -07:00
9b6b0e403c Remove data 2021-09-12 09:46:00 -07:00
4d1c6034eb Deprecate basic_data 2021-09-12 09:37:23 -07:00
a3348eccdd Deprecate most of basic_data 2021-09-12 08:59:39 -07:00
3a04481485 Remove data::hex_digits 2021-09-11 17:54:40 -07:00
ad77331c04 Move log10_2_significand to format-inl.h 2021-09-11 09:36:23 -07:00
d9ebc4e821 Add a function to get sign char 2021-09-11 09:17:59 -07:00
c00eb4f4c6 Add missing inline 2021-09-10 09:01:18 -07:00
25af02f21a positive -> nonnegative (#2493) 2021-09-10 08:52:54 -07:00
67cb2dad37 Optimize %F in tm formatting 2021-09-10 07:48:50 -07:00
1aa98f8b93 Eliminate double copying in vformat_to_n (#2489) 2021-09-09 08:10:29 -07:00
a58c133821 Improve code_point_length codegen on older gcc 2021-09-07 19:34:13 -07:00
aeee70a815 Remove unnecessary cast 2021-09-07 10:53:43 -07:00
c771ba361c Fix build for the clang-10 / libstdc++-9 couple (#2491) 2021-09-07 08:52:34 -07:00
ab6e2272cc Clarify shifts encoding 2021-09-06 18:45:34 -07:00
e4728409e7 Use throw_format_error in more places to reduce bloat 2021-09-06 16:42:17 -07:00
e3ebf366a6 Inline padding shifts 2021-09-06 16:26:50 -07:00
894faf3fed Refactor presentation types 2021-09-06 13:32:33 -07:00
4eb97fa4e3 Reduce code bloat 2021-09-05 16:24:20 -07:00
6b55c83252 is_const_formattable -> has_const_formatter 2021-09-05 08:35:08 -07:00
2fe94ad7e3 Make specifiers support in tuple_join an opt-in 2021-09-05 07:34:06 -07:00
3940de5952 thousands -> group_digits 2021-09-05 06:47:18 -07:00
c4d0f96a6d Implement format specs in fmt::thousands 2021-09-04 06:56:51 -07:00
3b9c442689 Implement thousands separators without locales 2021-09-04 06:32:46 -07:00
08f98c7fac Simplify get_arg_index_by_name 2021-09-03 21:17:36 -07:00
a151f955a0 Remove FMT_OVERRIDE 2021-09-03 18:15:17 -07:00
42a225cbd9 Remove redundand final 2021-09-03 17:33:26 -07:00
bf20d19901 Simplify the core API 2021-09-03 16:57:33 -07:00
fc0884037e Move FMT_GCC_VISIBILITY_HIDDEN to format.h 2021-09-03 16:34:42 -07:00
1aeed2dbca Require inline namespaces 2021-09-03 15:59:23 -07:00
799bea4730 Remove FMT_HAS_GXX_CXX11 2021-09-03 15:49:40 -07:00
60cd5ea3f2 Add support for more formattable types in ranges 2021-09-03 14:55:41 -07:00
4fd9a00f35 Simplify ostream interface 2021-09-03 13:07:54 -07:00
5681563898 Cleanup ostream interface 2021-09-03 10:35:19 -07:00
20931baf1d Disable fallback_formatter for arrays 2021-09-03 08:59:36 -07:00
d58d19ba32 Fix an odr violation in ranges.h (#2483)
* Add a testcase demonstrating ODR violation in ranges.h

* Fix ODR violation in ranges.h

* Fix comments

Co-authored-by: Pierre-Antoine Lacaze <pa.lacaze@gmail.com>
2021-09-02 08:47:44 -07:00
ee0659f8b6 Fix formatting of abstract classes via ostream 2021-09-02 08:19:12 -07:00
8029bf955c Fix copy_str performance (#2477) 2021-09-02 07:25:26 -07:00
Max
2520f410c8 Workaround for #2478 (#2482)
_MSC_VER 1911 (Visual Studio 2017 15.3)
2021-09-02 07:13:30 -07:00
ee63f5f04e Workaround to MSVC bug (#2474) (#2476) 2021-08-31 07:54:42 -07:00
1aaf72fb6d Add an example to fmt::runtime 2021-08-29 12:10:40 -07:00
c1313c2057 Clarify that format_to[_n] do not append a terminating null 2021-08-29 12:07:35 -07:00
cb0f177c35 Improve docs 2021-08-29 11:30:35 -07:00
71677e5204 Improve docs 2021-08-29 11:21:38 -07:00
4db5723525 add fuzzers for chrono timepoint and localtime,gmtime (#2469)
* add fuzzers for chrono timepoint and localtime,gmtime

* reorder cases to improve throughput

mutating the first byte of the input now always results in picking
on of the two paths. Before, two of the four possible outcomes resulted
in doit() not being invoked.

* drop the localtime fuzzer

* inline aliases

* only fuzz std::chrono::system_clock
2021-08-29 06:58:23 -07:00
dc7f3ef2bb Fix header name 2021-08-28 20:34:45 -07:00
419ba86a91 Improve docs 2021-08-28 16:54:58 -07:00
6a5b4d5faf Document format_string 2021-08-28 16:51:48 -07:00
2599163b8a Document format_string 2021-08-28 15:20:56 -07:00
8ef22f7740 Update docs 2021-08-28 12:05:30 -07:00
c0c4d1adab Update docs 2021-08-28 11:52:13 -07:00
729a44e67d Depreate strtod and remove problematic tests 2021-08-28 09:20:36 -07:00
74c1118964 Apply force inline 2021-08-26 21:17:35 -07:00
596508a928 Cleanup 2021-08-26 20:56:28 -07:00
043e3b3429 Remove static_assert from arg_mapper 2021-08-26 20:45:01 -07:00
8b0cb944da Fix error reporting when mixing character types 2021-08-26 18:16:05 -07:00
117fc67077 CI: replace g++ C++20 build to test FP formatting at compile-time 2021-08-26 17:16:45 -07:00
c79a3841e8 make detail::fp and detail::bigit constexpr 2021-08-26 17:16:45 -07:00
5888de9f34 make detail::make_checked() constexpr 2021-08-26 17:16:45 -07:00
04b4b69b11 make detail::bit_cast() constexpr with C++20 2021-08-26 17:16:45 -07:00
fd34a3d246 make detail::basic_memory_buffer constexpr with C++20 2021-08-26 17:16:45 -07:00
6d597e39c3 Fix overload ambiguity in arg_mapper 2021-08-26 16:54:27 -07:00
b9ce56d936 Improve comments 2021-08-26 16:30:58 -07:00
f889e52a15 Improve error reporting 2021-08-26 15:47:44 -07:00
34caecd6b6 Use consistent initialization style 2021-08-23 10:10:56 -07:00
a44c8f651b reimplement formatter<tuple_join_view> (#2457)
* reimplement `formatter<tuple_join_view>`

1. completely reimplement `formatter<tuple_join_view<Char, T...>, Char>`
2. Add some tests

* use FMT_THROW
2021-08-23 09:51:19 -07:00
4b8bda25c0 Fix 2462
Signed-off-by: owent <admin@owent.net>
2021-08-23 06:31:10 -07:00
6b5e6119ee set clang in one place 2021-08-22 17:52:45 -07:00
7af1dc1d27 fix UB in fuzzer common (memcpy on nullptr) 2021-08-22 17:52:45 -07:00
e77686f7a8 clang format
using clang format 11
2021-08-22 17:52:45 -07:00
2207ea0b36 More escaping 2021-08-22 16:54:26 -07:00
a212ff757f Escape invalid code points 2021-08-22 15:51:33 -07:00
a76031e11d check -> is_printable 2021-08-22 13:23:38 -07:00
a7f280765c Improve naming 2021-08-22 12:44:00 -07:00
07d033ecb4 Fix is_printable 2021-08-22 10:37:18 -07:00
cdb4299acb Add Unicode support to is_printable 2021-08-22 09:11:35 -07:00
7df2c82a8a Rewrite printable.py codegen to emit C++ 2021-08-22 09:10:10 -07:00
6cf90d7cee Add script license and fix python version 2021-08-22 08:17:58 -07:00
2f1ad8ed3c Add printable codegen from Rust 2021-08-22 08:15:34 -07:00
371d8e2ee0 Escape Unicode 2021-08-22 07:55:59 -07:00
6397095ca4 More escaping 2021-08-21 16:36:25 -07:00
f69a572538 Don't overescape wide strings 2021-08-19 17:25:16 -07:00
11b07a56b2 We should escape 2021-08-19 14:50:59 -07:00
b559cfd4c0 Implement basic escaping 2021-08-19 14:12:26 -07:00
11d49491cb Handle global locale 2021-08-14 09:38:41 -07:00
6ea6cf9464 Add decimal separator support to float 2021-08-14 09:16:26 -07:00
9730a2af0a Update ChangeLog.rst 2021-08-13 10:07:48 -07:00
c2ed5f6863 Update ChangeLog.rst 2021-08-13 10:07:20 -07:00
7b66e72e2c Use builtin intrinsics on intel (#2450) 2021-08-11 06:22:02 -07:00
d57b2a6525 Suppress a warning 2021-08-08 09:18:46 -07:00
bdfbd794e3 Cleanup begin/end usage 2021-08-07 08:55:01 -07:00
111de881fa Don't copy non-const-iterable ranges 2021-08-07 07:34:02 -07:00
d6e882ed84 Undo the move because the doc is not a GH template 2021-08-06 11:22:33 -07:00
f488eed101 Resolve default constructor error in Xcode 7.2.1 and 8.2.1
Fix issue that produces the error 'default initialization of an object
of const type 'const detail::buffer_size' without a user-provided
default constructor'
2021-08-06 11:17:02 -07:00
652c3653bb Move CONTRIBUTING.md to .github 2021-08-06 10:56:05 -07:00
fb19faa31b Improves README with svg badge (#2446)
Looks much better now!
2021-08-05 06:50:15 -07:00
07211701f4 Disable the -Wstringop-overflow warning from GCC 7 (#2442) 2021-08-02 14:20:18 -07:00
bba0a9d962 Make flush public 2021-07-30 07:02:49 -07:00
f1794a8853 Switch to threadsafe death test style 2021-07-29 06:56:38 -07:00
brm
0544a2279b Exclude fallback functions when FMT_BUILTIN_CLZ(LL) is not defined (#2434) 2021-07-25 10:37:18 -07:00
5c222f0561 Add support for nonconst formattable types 2021-07-24 09:53:53 -07:00
3def950b84 Set FMT_CAN_MODULE=OFF for MSVC 19.29.30035+ 2021-07-23 09:35:09 -07:00
63fe2d5bd2 Add copy constructor for dynamic_format_arg_store, and test 2021-07-23 09:35:09 -07:00
561834650a Improve digit count 2021-07-18 09:14:56 -07:00
f20f50368f Replace throw with FMT_THROW (#2427)
Using `throw` results in compile errors with `-fno-exceptions`. gcc seems fine with it, but arm-gcc and clang would complain.
2021-07-18 07:08:24 -07:00
00235d8a99 fix module test odr violations (#2414) 2021-07-17 09:16:49 -07:00
2038bf6183 Update format_to usage 2021-07-13 07:56:24 -07:00
e41ac1f875 Don't use deprecated API in docs 2021-07-10 13:42:51 -07:00
8465869d7b Move ignore_unused to detail 2021-07-09 08:24:11 -07:00
3d53d1539d Warning removals in test code (#2399)
* Warning removals in test code.

Mostly 0 to nullptr and adding override to virtual function implementations.

* Fix module-test.
2021-07-09 08:05:02 -07:00
20e4ef8b4c Pass significand_size by value 2021-07-05 08:51:43 -07:00
c4a3c2342a Refactor locale handling 2021-07-05 08:25:12 -07:00
7a0d301753 Update README.rst 2021-07-04 07:03:20 -07:00
f2b03facd9 Include test sources to pick up functions and classes from the module rather than from the non-modular library which is baked into the test-main library. (#2356)
This averts linker problems:
 - strong ownership model: missing linker symbols
 - weak ownership model: duplicate linker symbols

Simplify `gtest-extra.cc` while at it.
2021-07-03 07:21:54 -07:00
02ad5e11da Add faint, blink, reverse and conceal to the emphases (#2394) 2021-07-02 20:03:55 -07:00
d141cdbeb0 Update version 2021-07-02 16:14:33 -07:00
cfc05e05f0 Bump version 2021-07-02 14:43:31 -07:00
8ea312633b Update changelog 2021-07-02 14:43:00 -07:00
e461f3dbbe Minor consitency and comment tweaks 2021-07-02 13:56:37 -07:00
54014e42e3 silence warning C4100 on MSVC 2019 when exceptions are disabled (#2397) 2021-07-02 13:51:49 -07:00
3e7a29cc92 Workaround clang/gcc incompatibility 2021-07-02 13:29:22 -07:00
00a57a9f8f Update changelog 2021-07-02 08:07:48 -07:00
1d7384530e Add missing presentation type checks for std::string (#2402) 2021-07-02 07:51:04 -07:00
889bbf27a2 Fix missing std::get overload in MSVC (#2407)
This replaces the `std::get` call with an unqualified equivalent to allow
it to be treated as a dependent call.

ranges.h needs std::get overloads from `<tuple>` but does not directly
include it. This causes compilation failures in MSVC with /permissive-.
On other platforms `<tuple>` is included as a dependency from other headers
(specifically from `<memory>`), but there is no such implicit dependency in
MSVC's STL.

Fixes #2401
2021-07-01 10:55:46 -07:00
5f8473914c Remove outdated apidoc 2021-07-01 07:56:53 -07:00
785908ee37 Fix warnings 2021-06-30 06:42:29 -07:00
fbb70eec5c suppress unused variable warnings (#2381)
* suppress unused variable warnings

An arguably better method for suppressing unused variable warnings.   The `(void)var` method does not work on many intel compiilers.
This is from Herb Sutter's blog post https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/

* Format to eliminate long lines

* Run clang-format
2021-06-30 06:33:30 -07:00
002bb759ff Remove unneeded num_result_bigits decrement
For what I see this seems unused?
2021-06-29 06:23:02 -07:00
a3f762c5aa [doc] Minor: fix `code`. 2021-06-29 06:21:15 -07:00
c3c27e5ab5 Fix MSVC warning C4819 2021-06-28 06:14:53 -07:00
c6b1f181aa Fix docs 2021-06-27 09:06:21 -07:00
94564b058e Fix docs 2021-06-27 08:55:16 -07:00
0fc73a2a85 Merge branch 'master' of github.com:fmtlib/fmt 2021-06-27 08:10:49 -07:00
3156fcf5f4 Switch to older breathe version 2021-06-27 08:10:37 -07:00
f85fb9fdff Adjust definition for FMT_HAS_INCLUDE
Adjust definition for FMT_HAS_INCLUDE

Remove check for `!FMT_MSC_VER`
2021-06-27 07:08:29 -07:00
0bc3d664e3 Fix docs 2021-06-27 06:41:54 -07:00
e5c46e13e8 Fix docs: breathe 18 and earlier corrupts trailing return type 2021-06-26 09:55:27 -07:00
49a3b58c8b Specify size for static data arrays 2021-06-26 06:55:24 -07:00
d0c8d45a2e apt update before install 2021-06-26 06:29:53 -07:00
c9a10631cb format: do not use udl_{arg,formatter} return types when UDL is not in use
The udl_{arg,formatter} structs are only defined when
FMT_USE_USER_DEFINED_LITERALS is set, so don't try to define things that
return that struct when it's not defined.
2021-06-26 06:25:16 -07:00
3bd806f12f Eliminate intel compiler warning
The intel compiler defines `__GNUC__`, but does not support the gcc `_Pragma`.  This PR filters out the intel compiler to avoid warnings about an unrecognized function.
2021-06-26 06:16:12 -07:00
fd16bcb20c Fix bug in cmake join function 2021-06-24 09:10:53 -07:00
5221242f6e Instruct msvc to report the _true_ value in __cplusplus and force _full_ C++ conformance
* do this  in _some_ tests to improve test coverage and catch possible problems due to that
 * fix invalid export of `static constexpr` constant
 * fix msvc warnings about unreachable code in high warning levels
2021-06-24 09:10:08 -07:00
31a5f0d399 Bump version in inline namespace 2021-06-22 14:47:59 -07:00
102a4d492a Bump version in inline namespace 2021-06-22 07:04:02 -07:00
f68508b6ce Update ChangeLog.rst 2021-06-21 18:37:56 -07:00
9e8b86fd2d Update version 2021-06-21 05:59:17 -07:00
92fec0f050 Bump version 2021-06-21 05:57:50 -07:00
4749cc930a Update changelog 2021-06-19 08:16:43 -07:00
78a0ba0a6a Improve conversion of paragraphs 2021-06-19 08:02:52 -07:00
7a39837d96 Use a working breathe version 2021-06-19 07:35:09 -07:00
55b6e92db5 Fix docs 2021-06-19 06:31:19 -07:00
69dc3a8535 Fix docs 2021-06-18 12:51:48 -07:00
27f4cdd586 Update changelog 2021-06-18 12:23:16 -07:00
70d61a0ae3 Update changelog 2021-06-18 08:32:43 -07:00
427b534054 Add no_value state to value 2021-06-15 07:53:28 -07:00
e421d52713 Simplify error handling in parse_nonnegative_int 2021-06-14 16:05:37 -07:00
a59678f376 Fix chrono_test.locale
UTF-8: https://datatracker.ietf.org/doc/html/rfc3629
2021-06-14 09:41:08 -07:00
c98254c3d7 Install locales into CI 2021-06-14 09:41:08 -07:00
c123a72844 Fix set locale error in chrono formatter 2021-06-14 09:41:08 -07:00
3c8fad126c Optimize parse_nonnegative_int 2021-06-13 19:20:44 -07:00
f28cf3302d adding a default format for std::chrono::time_point<std::chrono::syst… (#2345) 2021-06-11 10:52:39 -07:00
55010a9d3a Support non-char overloads (module) 2021-06-11 09:38:53 -07:00
0193e7c428 Support compile-time strings and compile-time format string compilation in module
Make just the necessary parts available for lookup from client context.
2021-06-11 09:38:53 -07:00
3423d75475 Remove the msvc workaround (#2351) 2021-06-11 06:20:25 -07:00
f6b5cc9f84 Fix chrono_test.weekday on legacy glibc 2021-06-10 16:17:10 -07:00
59a298f124 Enable enforce-checks-test for MSVC, too 2021-06-10 12:54:54 -07:00
36c2948225 Update docs 2021-06-08 08:25:50 -07:00
c9fe1fa5ba Remove unused flag 2021-06-08 08:00:37 -07:00
dccddc2bdb Apply clang-format 2021-06-07 08:49:47 -07:00
0e36681b8e Cleanup digit count 2021-06-07 07:42:22 -07:00
1de80f5b22 Workaround lack of static constexpr in constexpr functions 2021-06-07 07:27:56 -07:00
2039dce75f Detect consteval 2021-06-07 06:57:43 -07:00
d551b88a6d Move is_char specializations to xchar.h 2021-06-06 15:32:30 -07:00
16c3514d01 wchar-test -> xchar-test 2021-06-06 07:59:18 -07:00
206000a017 Workaround pathological conversion (#2343) 2021-06-06 07:18:44 -07:00
76ee490468 Move wchar/custom char overloads to xchar.h 2021-06-05 22:57:45 -07:00
e77b22d6da Deprecate memory buffer overload of format_to 2021-06-05 14:58:36 -07:00
07039f4b19 Update README.rst 2021-06-05 06:32:22 -07:00
4678192c88 Remove bsr2log10 2021-06-04 21:33:05 -07:00
7c3d3dfa29 Update thousands_sep_impl signature 2021-06-04 21:12:47 -07:00
ef826b86cb Fix docs 2021-06-04 20:34:58 -07:00
5223f552c8 Remove FMT_ALWAYS_INLINE 2021-06-04 20:29:54 -07:00
cfde93afe0 Add FMT_STATIC_CONSTEXPR 2021-06-04 16:50:09 -07:00
986a5a6c2c Fixed join_view formatter for wchar_t 2021-06-04 14:50:45 -07:00
7c8b35ff32 fix MSVC Win32 count_digits 2021-06-04 11:06:25 -07:00
3eeb084e71 Optimize count_digits 2021-06-04 09:14:58 -07:00
2ac0bfe59e Improve handling of thousands separator 2021-06-04 06:12:44 -07:00
024741b476 CI: set up multi-thread build for all platforms 2021-06-04 05:56:55 -07:00
f4c95f6dd9 Improve handling of thousands separator 2021-06-03 18:25:08 -07:00
d4fbeacc33 Fix docs build 2021-06-03 18:25:08 -07:00
0eef389ddb Code style 2021-06-03 18:25:08 -07:00
e27b1ce50c Fix docs 2021-06-03 09:32:12 -07:00
9f8b6daca2 Fix wheel installation 2021-06-03 09:10:07 -07:00
6060bcfc8a Fix docs 2021-06-03 09:03:00 -07:00
ff9673463c Fix docs 2021-06-03 08:43:41 -07:00
1085cc2178 Fix docs 2021-06-03 08:28:02 -07:00
11addaa16e Update docs 2021-06-03 06:24:17 -07:00
760ca5ccc0 Update docs 2021-06-02 19:45:42 -07:00
290d3f8b61 Cleanup ranges API 2021-06-02 17:06:02 -07:00
aa09e0f5dd Update docs 2021-06-02 16:25:21 -07:00
d142579e97 Cleanup the format API 2021-06-02 16:25:21 -07:00
f286139d22 Fix "undefined reference to `fmt::v7::detail::basic_data<void>::digits'"
Remove unused FMT_EXTERN_TEMPLATE_API
2021-06-02 14:33:17 -07:00
7b9d69b827 Add xchar.h to docs 2021-06-02 08:19:54 -07:00
cbd861f188 Update docs 2021-06-02 08:06:52 -07:00
faf972f039 Update docs 2021-06-02 07:46:26 -07:00
622d1c0423 Update changelog 2021-06-02 07:36:27 -07:00
634c948769 Update changelog 2021-06-02 07:13:06 -07:00
a04e3a2dc8 Comment 2021-06-01 20:47:16 -07:00
87876d5474 Cleanup the printf implementation 2021-06-01 20:32:56 -07:00
d338d66324 Cleanup the printf implementation 2021-06-01 19:30:46 -07:00
272660e704 Remove deprecated printf functions 2021-06-01 18:08:31 -07:00
5a95c5ae2c Update changelog 2021-06-01 17:47:23 -07:00
70e67ae018 Re-enable module testing
Prepare for compilation with gcc (modules branch).
2021-06-01 14:49:56 -07:00
ad97258915 Merge branch 'master' of github.com:fmtlib/fmt 2021-06-01 13:38:26 -07:00
ed2a6377e7 Workaround msvc constexpr issues 2021-06-01 13:32:44 -07:00
9976869549 fix custom types formatting at compile-time, add test 2021-06-01 11:16:05 -07:00
8c1b22ba6d Workaround a gcc 9.1 bug (#2334) 2021-06-01 06:43:30 -07:00
2dba1cfac1 Update changelog 2021-05-31 19:19:09 -07:00
d7ba6c3ea8 Use qualified name-lookup in module. (#2324)
Allow lookup of non-exported names from local classes in function templates.
2021-05-31 09:11:24 -07:00
bf9904ee4d Workaround msvc bugs 2021-05-31 08:25:05 -07:00
577bce9029 Apply clang-format 2021-05-31 08:09:10 -07:00
ba4c7f193b Swap parameter order to match #2327 (#2329) 2021-05-31 07:44:33 -07:00
e9e89b355b Update ChangeLog.rst 2021-05-31 07:43:29 -07:00
9bb406d78d Update changelog 2021-05-31 07:37:10 -07:00
11a14db286 Update format_to taking a buffer and remove undocumented vformat_to overload 2021-05-30 07:57:51 -07:00
832ec098fc Fix argument order in locale overload of vformat_to (#2327) 2021-05-30 06:42:09 -07:00
486a80e8ef Move wchar_t overloads to xchar.h 2021-05-30 06:41:39 -07:00
19d45f4b31 Update changelog 2021-05-29 16:56:33 -07:00
5a2b88f6e9 Reduce binary size 2021-05-29 16:45:43 -07:00
00a39ad5f8 Enable Char types other than char (#2323) 2021-05-29 11:42:16 -07:00
ff37e41625 wchar.h -> xchar.h because it handles other code unit types too 2021-05-29 09:37:17 -07:00
0901176fe4 arg_join -> join_view 2021-05-29 08:47:16 -07:00
a9a9018191 Move wmemory_buffer to wchar.h 2021-05-29 08:26:04 -07:00
4a7801c3ec Update changelog 2021-05-29 08:14:25 -07:00
517578f80e Update changelog 2021-05-29 07:48:59 -07:00
85442ed045 Update changelog 2021-05-29 07:43:21 -07:00
6a12b13a85 Update changelog 2021-05-29 07:39:35 -07:00
1cfe3c7382 Update ChangeLog.rst 2021-05-29 07:30:47 -07:00
c06014792b Update changelog 2021-05-29 07:30:07 -07:00
6fe04871f4 Update changelog 2021-05-29 07:20:29 -07:00
9d67988aed FMT_DEPRECATED_WCHAR -> FMT_DEPRECATED_INCLUDE_WCHAR 2021-05-29 06:41:07 -07:00
765b451edd Update changelog 2021-05-29 06:15:49 -07:00
17c993c753 Fixed compilation with CMake < 3.7 (#2321) 2021-05-28 20:24:31 -07:00
dde6937319 Update changelog 2021-05-28 16:20:46 -07:00
272b0f36b3 More module tests (#2309)
core.h, format.h, args.h, chrono.h, color.h, printf.h, os.h
2021-05-28 15:49:39 -07:00
126c8cb46b Export os.h API, too (#2318) 2021-05-28 09:27:45 -07:00
98b9ff47a1 Align hex floats right as default (#2317) 2021-05-28 09:21:01 -07:00
ece4b4b33a Update changelog 2021-05-28 06:53:33 -07:00
a70a4ae053 Ignore zero-padding for non-finite floating points (#2310)
* Ignore zero-padding for non-finite floating points

* keep width for non-finite formatting with 0-padding

* clang-format

* preserve alignment

* align code-style
2021-05-27 14:13:05 -07:00
7612f18dc8 Update changelog 2021-05-27 07:06:13 -07:00
b9f2c27661 Update changelog 2021-05-26 21:12:03 -07:00
4e21baff43 Simplify get_units 2021-05-26 18:26:00 -07:00
683ef11ab9 Update changelog 2021-05-26 18:25:21 -07:00
ca466374bd qualify make_format_args (#2315)
Co-authored-by: John Melas <john@jmelas.gr>
2021-05-26 06:42:02 -07:00
5a2a185682 Make buffers non-movable 2021-05-25 17:30:17 -07:00
ee52a6dc40 add fmt::print() overload to support compiled format (#2304) 2021-05-25 14:54:56 -07:00
82607efb57 Fixed int conversion warning (#2313)
* Fixed int conversion warning

Compiler warns about conversion from int to size_t, thus added explicit cast.

* now using detail::to_unsigned for the cast
2021-05-25 08:13:39 -07:00
35a2c2a743 Refactor chrono formatting 2021-05-25 06:57:47 -07:00
b955e7a6b2 Refactor chrono formatting 2021-05-24 15:33:33 -07:00
883d9595c5 Support alternative locale names in tests 2021-05-24 14:09:19 -07:00
1f308a3cea Update integer presentation types documentation.
Documents that the 'c' type is a valid type for integer types. Since
boolean uses the same types as integer its documentation is
automatically updated.
2021-05-24 10:55:08 -07:00
1cd9899cf3 Add initial support for weekday formatting 2021-05-24 10:21:34 -07:00
069131dc25 Add unicode-test 2021-05-24 06:20:51 -07:00
dd8f38fcbb Cleanup printf API 2021-05-23 20:30:26 -07:00
a216f2562d Remove undocumented and obsolete vprintf overload 2021-05-23 20:15:02 -07:00
0c0926395d Add is_exotic_char trait 2021-05-23 19:50:17 -07:00
bc13c6de39 Update README.rst 2021-05-23 07:45:33 -07:00
8ec0b9e33b Do *not* export namespace detail 2021-05-23 06:49:07 -07:00
b99c2bd345 Remove deprecated locale.h from module interface unit 2021-05-23 06:17:25 -07:00
c04a24399a Update changelog 2021-05-22 20:55:56 -07:00
b099a56f9f Update changelog 2021-05-22 16:12:38 -07:00
703005c8ba Deprecate locale.h 2021-05-22 10:21:17 -07:00
51f0178625 Cleanup the format API 2021-05-22 07:09:09 -07:00
5d59dcf66e Remove deprecated aliases / undeprecate has_formatter 2021-05-22 06:53:34 -07:00
c242dd402c Move cerrno include to where it is used 2021-05-22 06:18:40 -07:00
2216e0b779 Update changelog 2021-05-22 06:04:33 -07:00
1c83a49be9 Simplify buffer extraction 2021-05-21 20:15:56 -07:00
2617384d8e Improve buffer extraction 2021-05-21 19:44:49 -07:00
34b8acaef7 More wchar_t-specific API to wchar.h 2021-05-21 18:24:39 -07:00
6326c18906 Improve code style consistency 2021-05-21 17:29:15 -07:00
5c4b0c86fb Add missing Allocator template argument for basic_memory_buffer in format_to
Remove deduced default template arguments in format_to and moves the
SFINAE check to a non-deduced template parameter.
2021-05-21 12:13:46 -07:00
00149c0b6a Move detail::null to chrono where it is used 2021-05-21 09:16:45 -07:00
c5c968cb22 Improve binary size 2021-05-21 08:50:35 -07:00
128cbdeb2f cmake: hide private symbols by default 2021-05-21 08:25:08 -07:00
18af1dc460 Fix binary size regression caused by b268f88 2021-05-20 18:33:45 -07:00
d1e6f0f8c6 Fix binary size regression caused by b268f88 2021-05-20 18:00:19 -07:00
5a0d99fa0b Add a test for the module 2021-05-20 10:26:31 -07:00
6e2e6b796f Restore support for wchar_t overloads in module 2021-05-20 10:03:58 -07:00
24b677d053 Improve symbol sizes 2021-05-20 07:21:20 -07:00
63271a51c4 Fix ADL issues 2021-05-20 06:31:43 -07:00
61b4c923d7 Reduce code bloat 2021-05-20 05:51:45 -07:00
2a2e4c5801 addressing nits. 2021-05-19 16:09:49 -07:00
be48f4d657 Avoid unwanted sign extensions from MSVC in is_utf8.
Microsoft's constexpr evaluator treats the type of micro[0] and micro[1] as
plain char, and so sign extends before comparing them to ints.
The normal compiler, including the optimizer, does not fail in this way,
so this is merely a "future proof" change in case someone uses is_utf8()
in a constant expression.
2021-05-19 16:09:49 -07:00
13e652939b export missed symbols
Enable `-fvisibility=hidden` and `-fvisibility-inlines-hidden` by default in CI builds to ensure all public symbols are exported correctly.
2021-05-19 16:03:45 -07:00
71fb113818 fix compile error on msvc preview 4 (16.10) involving lookup clash /w STL 2021-05-19 13:17:20 -07:00
08d22503bb Remove outdated comments 2021-05-19 11:47:21 -07:00
56f518a98f Update signatures 2021-05-19 09:45:33 -07:00
b7f2933744 Update signatures 2021-05-19 09:39:32 -07:00
7483dfc652 Update signatures 2021-05-19 09:36:12 -07:00
95c358f721 Improve separation between code unit types 2021-05-19 09:06:57 -07:00
39c3c4ec22 Simplify the core API 2021-05-19 08:32:57 -07:00
e9c1c415b8 Improve compile-time checks 2021-05-19 07:57:57 -07:00
21d93bfd33 Move generic format functions to format.h 2021-05-18 19:01:43 -07:00
9a92eb4158 Move more wchar overloads to wchar.h 2021-05-18 05:53:25 -07:00
0dd91e20d5 Add wchar.h for wide char overloads 2021-05-17 21:59:10 -07:00
ce14eafc24 Simplify format string checks 2021-05-17 19:25:50 -07:00
8d70c0edab Refactor the format API 2021-05-17 18:25:36 -07:00
813ac49543 More API cleanups 2021-05-17 07:58:13 -07:00
4ab01fb198 Cleanup printf API 2021-05-17 07:19:50 -07:00
d5036b11b1 Remove deprecated APIs 2021-05-17 06:59:46 -07:00
2581946231 Cleanup the core API 2021-05-16 13:02:01 -07:00
b35db4e006 Improve handling of 128-bit ints 2021-05-16 11:43:44 -07:00
d35f1ad5c1 Cleanup core 2021-05-16 10:02:33 -07:00
8f1902c05a Move format string checks to core.h 2021-05-16 07:08:49 -07:00
6469b9037c Silence msvc warning about an unused named parameter
Warning C4100 may cause compile failures under strict warning regimes.
2021-05-16 06:14:30 -07:00
7d4c92fb00 Update ChangeLog.rst 2021-05-15 17:19:27 -07:00
0763d8cadf Fix Visual Studio warning 2021-05-15 17:13:15 -07:00
5466373a11 Do *not* export namespace detail
Introduce `FMT_BEGIN_DETAIL_NAMESPACE` and `FMT_END_DETAIL_NAMESPACE` for `namespace detail` sections embedded in that part of the code that contains all declarations that are exported from the module, i.e. which is enclosed by `FMT_MODULE_EXPORT_BEGIN` and `FMT_MODULE_EXPORT_END`. Given a correct implementation of C++20 modules, neither the name `fmt::detail` nor any of its contents will become visible outside of the module.
2021-05-15 12:08:42 -07:00
588bdb5404 Simplify get_arg_index_by_name 2021-05-15 06:47:43 -07:00
54f22a3eef add support for statically named arguments with FMT_STRING 2021-05-14 16:31:10 -07:00
ea94d6d93c Prevent ambiguity in name lookup
Unqualified calls to 'make_format_args' may find the same name by ADL in <format> if this C++20 header happens to be directly or indirectly included in a translation unit. Do a qualified lookup instead.
2021-05-14 07:10:02 -07:00
57280762b6 Move specs checker to core.h 2021-05-13 19:33:09 -07:00
ced3037523 Move dynamic specs to core.h 2021-05-13 19:01:21 -07:00
dd2bc998ab Move specs to core.h 2021-05-13 18:48:15 -07:00
08da1adcf6 Remove unused headers 2021-05-13 17:58:15 -07:00
3be0cc2087 Fix handling of 128-bit ints 2021-05-13 17:53:23 -07:00
9648bdce30 add missing header 2021-05-13 05:39:18 -07:00
d1aebdbde0 Inline format_to 2021-05-12 18:07:59 -07:00
8f0fadfaaa Cleanup docs 2021-05-11 20:20:03 -07:00
02896dabee Avoid use after move (#2278) 2021-05-11 16:58:07 -07:00
0036a1d195 Fix issue #2274. 2021-05-10 15:57:23 -07:00
2a9b314627 Replace fmt::error_code to std::error_code 2021-05-09 12:26:19 -07:00
2165bef4ca Update README.rst 2021-05-09 09:35:44 -07:00
4862930845 Optimize format string compilation 2021-05-09 09:15:55 -07:00
3207a8bbbf Get rid of unnecessary recursion to enable inlining 2021-05-09 07:54:13 -07:00
6214f15a0c Optimize standard formatter specialization 2021-05-09 07:11:35 -07:00
cd2c78fb8a Use write directly in formatter specializations 2021-05-09 07:07:51 -07:00
4211d86539 Add a formatter specialization for std::error_code. 2021-05-09 06:29:39 -07:00
39f28424ca Cleanup tests 2021-05-07 21:27:58 -07:00
84feeb0f36 Remove redundant comments and put common case check first 2021-05-07 17:14:29 -07:00
2665afb515 Cleanup add-subdirectory-test 2021-05-07 16:42:02 -07:00
d0abe7c246 Make chrono formatting locale-independent by default 2021-05-07 16:14:10 -07:00
50fb0b5eae Fix formatting 2021-05-07 08:52:49 -07:00
16f2ef91ab Replace fmt::system_error with std::system_error 2021-05-07 08:33:39 -07:00
4b885c8633 Replace windows_error with system_error 2021-05-07 06:19:03 -07:00
5238055f40 Move esoteric char type support to format.h 2021-05-06 09:02:00 -07:00
9ac088f376 Add fmtlog to projects 2021-05-06 08:39:36 -07:00
849c9f6168 Move is_name_start to core 2021-05-06 08:12:24 -07:00
23892caf53 Move more parsing to core 2021-05-06 07:37:40 -07:00
8e6390c32c Move FMT_STRING to core 2021-05-06 07:19:41 -07:00
51a33713fc Move parsing to core 2021-05-06 07:01:29 -07:00
9c3af11a92 Cleanup tests 2021-05-05 18:31:41 -07:00
9d7b53cb9b Remove redundant formatter specialization for byte 2021-05-05 08:14:12 -07:00
f0095ccd34 Add support for ranges of types without formatters to join (#2262) 2021-05-05 07:43:46 -07:00
4f0eadfce4 Exclude fallback from is_formattable 2021-05-05 06:29:51 -07:00
400b953fbb Use [] instead of {} in ranges for consistency with Python format 2021-05-04 21:04:21 -07:00
38bcc04a11 Drop range limit and cleanup tests 2021-05-04 20:53:56 -07:00
c738c3431f Cleanup tests 2021-05-04 17:23:13 -07:00
ed7c4320f6 Cleanup tests 2021-05-02 09:28:38 -07:00
9155e2de4c Cleanup tests 2021-05-01 17:11:45 -07:00
38127d9ec0 Cleanup tests 2021-04-30 15:50:03 -07:00
c9c0e5077d Cleanup tests 2021-04-30 06:42:38 -07:00
ccf4ccde23 Cleanup tests and format string compilation 2021-04-29 19:50:04 -07:00
e96a92f869 Cleanup tests and format string compilation 2021-04-29 16:21:08 -07:00
fd43e4dcbc gtest: fix std::is_trivially_copy_constructible for GCC 4.8 & 4.9 properly
`std::is_pod<T>` was deprecated in C++20

original (pre `is_pod`) error on GCC 4.8:
```
/fmt/test/gtest/gtest.h: In static member function 'static constexpr bool testing::internal::MatcherBase<T>::IsInlined()':
/fmt/test/gtest/gtest.h:6512:12: error: 'is_trivially_copy_constructible' was not declared in this scope
            std::is_trivially_copy_constructible<M>::value &&
            ^
/fmt/test/gtest/gtest.h:6512:45: error: expected primary-expression before '>' token
            std::is_trivially_copy_constructible<M>::value &&
                                                  ^
/fmt/test/gtest/gtest.h:6512:46: error: '::value' has not been declared
            std::is_trivially_copy_constructible<M>::value &&
                                                   ^
```
2021-04-29 07:11:49 -07:00
3d51ccdaae gtest: remove obsolete GTEST_LANG_CXX11 compile definition setting 2021-04-29 07:11:49 -07:00
833377ff1e gtest: add .clang-format file into test/gtest directory to prevent formatting there 2021-04-29 07:11:49 -07:00
53ca0cbe75 gtest: move GTest/GMock files to separate directory, update GTest/GMock usages
* all GTest/GMock files moved to `test/gtest` directory
* `CMakeLists.txt` created in `test/gtest` from `CMakeLists.txt` in `test`
* GTest/GMock target in CMake renamed to `gtest` (was `gmock`)
* CMake `gtest` target updated to export includes as "gtest/gtest.h" or "gmock/gmock.h" only
* includes in tests updated: "gtest.h" -> "gtest/gtest.h", "gmock.h" -> "gmock/gmock.h"
* removed duplications of `target_include_directories` for GTest/GMock directories (CMake manages them)
2021-04-29 07:11:49 -07:00
342973b349 Make wchar_t overloads usable in module
Bring ''detail::find()' into scope.
2021-04-28 09:37:57 -07:00
355be4b13f Make FMT_COMPILE fallback on runtime without if constexpr (#2261) 2021-04-28 09:11:47 -07:00
0cd0fb9184 C++17: std::char_traits<>::{compare,length} is constexpr - v2 2021-04-28 07:05:32 -07:00
d1a6e5603f Keep defaulted destructors inline
applies to exception classes in case of msvc only
2021-04-28 06:17:26 -07:00
84a36b99bf Move data to functions 2021-04-27 17:21:32 -07:00
ab7c33ede0 Suppress checked iterator warnings 2021-04-27 13:54:39 -07:00
77258f6069 fix FMT_CONSTEXPR_CHAR_TRAITS check for MSVC 2021-04-26 16:35:32 -07:00
d23e315ea2 CI windows: add MSVC C++20 build 2021-04-26 16:35:32 -07:00
f085c3d7a0 use proper check for non-type template parameters 2021-04-26 16:35:32 -07:00
69bdc20a3c Workaround missing std::system on iOS, take 2 2021-04-26 06:21:44 -07:00
847aac4315 Follow naming conventions in tests 2021-04-25 21:26:30 -07:00
39818e7979 Cleanup core-test 2021-04-25 17:59:23 -07:00
0e6f989b0d __THROW warning fix for e2k (#2253) 2021-04-25 08:51:37 -07:00
1678ed6235 simplify field::format() and spec_field::format(), fix typo 2021-04-25 07:53:49 -07:00
ca821982ee use named arg with static name in compile-time API
to get arg index by name at compile-time
2021-04-25 07:53:49 -07:00
ce6e7d8620 use fixed_string to create named arg class with static name for _a literal 2021-04-25 07:53:49 -07:00
fc56af14c2 move fixed_string from compile.h to format.h 2021-04-25 07:53:49 -07:00
bb006f9735 Replace TYPED_TEST_CASE with TYPED_TEST_SUITE 2021-04-24 17:46:49 -07:00
6956b10b2d Fix gcc 4.8 build 2021-04-24 11:04:34 -07:00
b4f9a05894 Update gtest 2021-04-24 11:03:40 -07:00
8f9ddf452d Remove deprecated posix.h 2021-04-24 07:03:11 -07:00
dacd1356e4 Add module interface unit 2021-04-24 06:39:57 -07:00
d3c523e0d2 Export printf-related contexts from printf.h 2021-04-24 06:39:57 -07:00
2c25df089f Export replacement type_traits, too 2021-04-24 06:39:57 -07:00
553022dc56 Don't use std::system on iOS (#2248) 2021-04-24 06:17:05 -07:00
8a040d187a Cleanup core-test 2021-04-23 20:07:48 -07:00
064cac2bf9 Bump version 2021-04-23 16:05:03 -07:00
5b2c740ad8 Remove deprecated APIs 2021-04-23 15:27:25 -07:00
b9ab5c8836 Remove printf.h dependency on ostream.h 2021-04-23 10:42:57 -07:00
c47f211296 Simplify data handling 2021-04-23 06:52:10 -07:00
54d3b1710e Move more data out of basic_data 2021-04-23 06:45:23 -07:00
128f007b25 C++17: std::char_traits<>::{compare,length} is constexpr. (#2246) 2021-04-23 06:11:34 -07:00
841aad95b4 Move data out of basic_data 2021-04-22 15:29:42 -07:00
1d4199f46b fix udl_compiled_string with non-byte chars (e.g. wchar) (#2242) 2021-04-19 08:29:35 -07:00
c5d4fcb119 Appending a space to guarantee non-empty strftime() result. (#2244) 2021-04-18 19:13:51 -07:00
6271406233 Fix a warning (#2233) 2021-04-16 15:58:17 -07:00
52bd62c72f Create separate dllexport marking points for clang and msvc. (#2229)
* add FMT_INSTANTIATION_DEF_API for msvc

This should fix https://github.com/fmtlib/fmt/issues/2228

To fix difference dllexport requirements
msvc:  dllexport at template instantiation definition in format.cc
clang: dllexport at template instantiation declaration (extern template) in format.h
2021-04-16 12:34:18 -07:00
f4bbc54cc4 Tag official API for module export (#2235)
* functions
 * classes
 * UDLs
 * other declarations

Export everything in namespace 'fmt' from core.h and format.h
2021-04-16 11:04:55 -07:00
d8910af80d Use qualified name lookup rather than ADL. (#2239)
Name lookup within exported templates cannot find non-exported entities by ADL when instantiation takes place outside the module.
2021-04-16 09:38:25 -07:00
9260114162 Ranges wide strings support (#2236)
* Ranges copy wchar_t

* arg_join formatter not working for wide strings

* Added ranges wide string tests

Co-authored-by: Cristi <cristi@emailaddressmanager.com>
2021-04-16 06:25:35 -07:00
24c9751558 Try to suppress MVSC warn of narrowing (#2230) 2021-04-13 07:30:43 -07:00
a1c6bfd77b Add a link to llvm diff 2021-04-12 10:05:14 -07:00
42eccac454 Fix clang warning about ignoring __declspec(dllexport) on basic_data<void> template instantitation definition (#2220) 2021-04-12 09:31:44 -07:00
aec504344a Update README.rst 2021-04-10 08:48:11 -07:00
0b41145443 Update README.rst 2021-04-10 08:31:47 -07:00
00f3d16b12 Update docs 2021-04-10 08:07:16 -07:00
99c2f7a349 Allow including fmt/core.h in the header-only mode 2021-04-10 07:44:36 -07:00
b441532396 CI linux: add clang++-11 C++20 (with LLVM libc++) build
* find-package-test fixed by passing CXX_FLAGS, i.e. -stdlib=libc++
 * std::array usage in compile-test.cc replaced with plain array, because
   <array> header was not included
2021-04-10 07:20:05 -07:00
1dbadb6527 CI linux: add clang++-11 C++20 build 2021-04-10 07:20:05 -07:00
09dbad47e1 CI linux: add missing build_type
for g++-8 C++14, g++10 C++17, g++10 C++20
2021-04-10 07:20:05 -07:00
e2facffe4d CI linux: remove excessive clang++-9 include 2021-04-10 07:20:05 -07:00
273d8865e3 Suppress redef warning of _CRT_SECURE_NO_WARNINGS if any. (#2218) 2021-04-08 11:56:35 -07:00
5a8bf1f6a3 Workaround hexfloat inconsistency on windows (#2205) 2021-04-07 11:20:08 -07:00
78776ee4e2 Fix a conditional expression is constant warning #2210 (#2211) 2021-04-07 10:42:11 -07:00
266107f57c constexpr uint128_wrapper (#2215)
* constexpr uint128_wrapper

* change FMT_CONSTEXPR to constexpr

* clang format

Co-authored-by: Jake Staahl <jstaahl@snapchat.com>
2021-04-06 22:07:01 -07:00
2e0d64cf2f specify size for prefixes static data 2021-04-06 17:07:14 -07:00
95da484727 Fix a link 2021-04-03 09:14:52 -07:00
06b3a1000c Add support for time points with arbitrary durations (#2208) 2021-04-02 11:17:14 -07:00
dac42f52b2 Inline fallback is_constant_evaluated 2021-04-01 10:42:09 -07:00
7c43f8b896 Don't use strlen at compile time (#2205) 2021-04-01 10:04:21 -07:00
c62e4c30f4 Make buffer_appender default-constructible when back_insert_iterator is 2021-04-01 09:52:44 -07:00
0d6b70d96b Install gcc 8 2021-04-01 09:19:36 -07:00
15c10b0c66 Add speech synthesis support 2021-04-01 09:19:36 -07:00
308510eb4f "Use" fwrite result (workaround for warn_unused_result)
Fixes #2185
2021-03-31 08:31:35 -07:00
afe23e7f10 Don't call fileno on NULL file in tests (#2196) 2021-03-30 10:41:12 -07:00
b49af043d7 Remove noexcept from file's move assignment 2021-03-30 09:51:25 -07:00
14848875bf Fix: fmt::ostream cannot be moved while holding buffered data #2197 (#2198)
* Add a test case: move ostream while holding data

* Fix moving ostream while holding data

Co-authored-by: Junliang HU <jlhu@cse.cuhk.edu.hk>
2021-03-30 08:43:26 -07:00
7d8c34018e Update pull_request_template.md 2021-03-30 08:42:11 -07:00
b966afcc7a Remove formattable 2021-03-28 14:21:12 -07:00
ec5315a987 Use strlen when possible in fallback basic_string_view 2021-03-28 08:01:55 -07:00
4f8778bab9 Inline basic_format_args's ctor 2021-03-28 07:32:17 -07:00
e2d87548f8 user-defined constructor
user-defined constructor added to prevent Intel compilers
warnings. According to the standard, objects need to have a
user-defined constructor if instances are delcared const.
2021-03-28 06:56:14 -07:00
f7151d384b Extra flag to prevent Intel compiler with Clang front-end warning of 'unknown attribute no_sanitize' 2021-03-28 06:56:14 -07:00
0fb8ef8f79 Inline trivial argument handling functions 2021-03-27 19:05:39 -07:00
1b23e25f95 Simplify formattability check 2021-03-27 18:57:18 -07:00
35c71ff536 Only use -Og with optimizations disabled 2021-03-27 11:35:01 -07:00
243d8bebd1 Enable minimal optimizations in debug mode 2021-03-27 08:40:07 -07:00
9b34681d97 Work around xl compiler bug when nvcc preprocesses this file (#2190) 2021-03-27 06:05:49 -07:00
4dc7170d21 Fix C++17 builds: (#2192)
- Fix C++17 Visual Studio builds.
- Use C++17 for `windows-2019` builds.
- Removed options for unsupported compiler (MSVC11).
- Removed options, not needed after enabling C++11+ features in gmock/gtest.
2021-03-26 06:19:43 -07:00
9cb347b4b2 Simplify argument formatters 2021-03-21 09:31:46 -07:00
0f85a4683a add default cases (#2186)
Adding default case for switch statements where the compilation
flag -Wswitch-default is present on the command line when spdlog
is included in external projects.

Signed-off-by: Ryan Sherlock <ryan.m.sherlock@gmail.com>
2021-03-19 16:56:52 -07:00
417e1cee9e Stop using deprecated UDL templates 2021-03-19 08:34:55 -07:00
f7e900e12e Simplify UDL definitions 2021-03-19 08:10:58 -07:00
d9661c8f3b Mark grouping as deprecated 2021-03-19 07:54:57 -07:00
14a2a64df4 Fix handling of formattable types with to_string_view (#2181) 2021-03-19 06:43:38 -07:00
6ae402fd0b Fix handling of types with to_string_view and formatter specialization (#2180) 2021-03-18 11:25:43 -07:00
a6408a3b09 Add args-test 2021-03-18 09:04:17 -07:00
1147782c79 Fix an ambiguous call to check caused by ADL (#2184) 2021-03-17 20:59:36 -07:00
VZ
2f3f3862fa Fix harmless MSVS warning about using undefined _MANAGED symbol (#2183)
Since the changes of 1305cbeb (Fix MSVC2019 error C2049 when compiling
with /clr (#1897), 2020-09-23), compiling fmt with MSVS 2019 resulted in

fmt\include\fmt\core.h(180,32): warning C4668: '_MANAGED' is not defined
as a preprocessor macro, replacing with '0' for '#if/#elif'.

when the (disabled by default) warning C4668 was enabled.

Fix this simply by checking if _MANAGED is defined before testing it.
2021-03-17 11:21:50 -07:00
d0bded5988 Fix MSVC /clr builds (#2179) 2021-03-15 08:17:28 -07:00
8308f52c2a Fix dynamic_format_arg_store::push_back comment 2021-03-15 07:10:28 -07:00
6151d0dc1e Fix the comment 2021-03-14 09:26:18 -07:00
5a1127b726 Don't wrap named arg in cref and clarify docs 2021-03-14 09:08:08 -07:00
b8ff3c1820 optimize append (#2164) 2021-03-13 07:21:23 -08:00
c8d8b88223 fix GCC 7,8,9 warning about unused but set parameter (#2177) 2021-03-13 06:36:53 -08:00
d28101878a Document ostream support limitation 2021-03-12 15:49:22 -08:00
bac14ef985 Simplify integer spec checking 2021-03-12 15:02:01 -08:00
8f9db3fcb8 Make ubsan happy on empty format specs (#2175) 2021-03-12 09:13:47 -08:00
af567538a0 Bitpack integral prefixes 2021-03-11 21:22:33 -08:00
cdf877d4b1 Workaround missed optimization opportunity 2021-03-11 16:44:59 -08:00
eef4ba9c02 Optimize integer formatting without padding 2021-03-11 15:47:58 -08:00
a1ea8a82c3 Unbloat my heart 2021-03-11 08:27:53 -08:00
a457e16360 Simplify integer formatter 2021-03-11 08:14:03 -08:00
05bc87a66f Optimize padding 2021-03-10 17:59:36 -08:00
605b603735 Optimize count_digits for powers of 2 2021-03-10 14:48:07 -08:00
85ba271639 Implement 128-bit count_digits in terms of count_digits_fallback 2021-03-10 12:57:46 -08:00
d9835737f0 spec -> specs 2021-03-10 12:51:03 -08:00
f9e0e90441 Apply clang-format 2021-03-10 12:08:02 -08:00
60f5d24411 Simplify arg_formatter 2021-03-10 09:35:48 -08:00
30e1302e73 Simplify on_format_specs 2021-03-10 08:46:16 -08:00
87c5cd46ac Optimize parsing of argument ids 2021-03-10 07:04:04 -08:00
6a9016ea60 fix formatted_size with "compiled format" as argument (#2161) 2021-03-07 06:44:36 -08:00
6e1fc01752 Move detail::truncating_iterator to fmt/compile.h 2021-03-06 08:35:36 -08:00
e718ec3e93 Make truncating_iterator an output_iterator (#2158) 2021-03-04 15:53:08 -08:00
772aeca338 Don't include <cassert>. (#2148) (#2152)
* Don't include <cassert>. (#2148)

This commit replaces use of the assert() macro in format-inl.h with
FMT_ASSERT(). This allows us to drop the cassert include.

* FMT_GCC_VERSION is not defined when we include test-assert.h, use __GCC__ instead.

* Don't explicitly suppress GCC's -Wterminate in tests' FMT_ASSERT.

Throwing from a separate function is enough to silence the warning, no need to
explicitly suppress it.

* Remove messages from assertions added in 2f699d2.

* Correct formatting around throw_assertion_failure().
2021-03-04 07:28:04 -08:00
684b5b0e40 Fix fallback to runtime API from compile-time API (#2143)
* fix fallback to the runtime API, add FMT_ENABLE_FALLBACK_TO_RUNTIME_API define, add test

* remove `FMT_ENABLE_FALLBACK_TO_RUNTIME_API`

* pass format string to format_to() inside format_to_n() in compile-time API

instead of compiling it inside format_to_n(), to eliminate code duplication
2021-03-04 07:20:57 -08:00
d8b9254301 use simplified void_t for all compilers other than gcc 4.x (#2160) 2021-03-02 14:42:27 -08:00
835b910e7d Add an is_formattable trait 2021-02-28 15:25:33 -08:00
578874033a Revert "Optimize handling of integer constants" (#2147)
This reverts commit 2797588be1.
2021-02-25 05:58:58 -08:00
640acba850 Print x.what() of FMT_THROW when exception is disabled (#2145)
Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
2021-02-24 06:29:04 -08:00
d8e1c9f175 fix fmt::get for some GCC versions and legacy Clang (#2144)
fixes https://github.com/fmtlib/fmt/issues/2140

- some GCC versions decay function pointers to `const void*`, exactly like
  MSVC does
- legacy Clang (prior to 7.0) treats function pointers also as `const T*`
  pointers, but unable to convert them
2021-02-23 07:18:30 -08:00
2797588be1 Optimize handling of integer constants 2021-02-21 11:11:57 -08:00
e8eff3b8fd Fix FMT_STATIC_THOUSANDS_SEPARATOR (#2142) 2021-02-21 07:42:12 -08:00
ab0f7d7fdc use const& for arguments 2021-02-20 11:50:12 -08:00
29cc8282b1 update chrono duration formatter (constness), use it in compile-test for specs checks 2021-02-20 11:50:12 -08:00
3f69af3aaf update wording in the error inside arg_id_handler, use FMT_ASSERT instead of throw 2021-02-20 11:50:12 -08:00
499047e132 fix incorrect indexing mode for named args, update tests 2021-02-20 11:50:12 -08:00
78c67157c1 prepare tests, fix incorrect handling of named args with simple {} replacement fields 2021-02-20 11:50:12 -08:00
b31bc2dc9f simplify try_format_argument(), make manual_indexing_id() a variable 2021-02-20 11:50:12 -08:00
95e1aa2dc5 add support for manual indexing and named fields, add tests 2021-02-20 11:50:12 -08:00
7e72673d87 Improve width estimation (#2033) 2021-02-13 09:30:29 -08:00
13b117b5bc Improve code point computation 2021-02-13 08:46:19 -08:00
ee0fed639c Fix handling of the + flag with locales (#2133) 2021-02-13 07:08:01 -08:00
c5979d564e Fix fmt::localtime formatting not working in wide-char string contexts 2021-02-13 06:53:30 -08:00
e6ef927e6b fmt::ptr: Support function pointers (#2131)
Passing a function pointer to fmt::ptr results in:

 In file included from /home/mac/git/fmt/test/gmock/gmock.h:238,
                  from /home/mac/git/fmt/test/format-test.cc:31:
 .../fmt/test/format-test.cc: In member function ‘virtual void FormatterTest_FormatPointer_Test::TestBody()’:
 .../fmt/test/format-test.cc:1486:56: error: no matching function for call to ‘ptr(void (&)(int, double, std::__cxx11::string))’
              format("{}", fmt::ptr(function_pointer_test)));

with GCC and Clang. Let's add an overload to support that usage.

Unfortunately, MSVC would
consider the overload to be ambiguous for unknown reasons:

 D:\a\fmt\fmt\test\format-test.cc(1485,1): error C2668: 'fmt::v7::ptr': ambiguous call to overloaded function [D:\a\fmt\build\test\format-test.vcxproj]
 D:\a\fmt\fmt\include\fmt/format.h(3742,60): message : could be 'const void *fmt::v7::ptr<void,int,double,std::string>(T (__cdecl *)(int,double,std::string))' [D:\a\fmt\build\test\format-test.vcxproj]
           with
           [
               T=void
           ]
 D:\a\fmt\fmt\include\fmt/format.h(3735,42): message : or       'const void *fmt::v7::ptr<void(int,double,std::string)>(T (__cdecl *))' [D:\a\fmt\build\test\format-test.vcxproj]
           with
           [
               T=void (int,double,std::string)
           ]
 D:\a\fmt\fmt\test\format-test.cc(1486,1): message : while trying to match the argument list '(overloaded-function)' [D:\a\fmt\build\test\format-test.vcxproj]

but luckily this means that the overload is unnecessary in that case
anyway, so we can just make it conditional.
2021-02-09 07:35:16 -08:00
58aa04573f Fix ordering of install commands for CMake (#2122)
the library itself needs to be installed before
the fmt-targets.cmake file is installed,
otherwise the installed targets file doesn't
actually point to the library using
IMPORTED_LOCATION
2021-01-30 09:03:55 -08:00
1980ca8c4e fix #2118: FMT_COMPILE did not work with tm formatter (#2119)
Co-authored-by: summivox <summivox@github.com>
2021-01-30 08:44:49 -08:00
2a25e2bf4d Make ranges-test available with C++11 (#2114)
* make ranges-test available with C++11, fix problem with some gcc versions

* potentially fix build for MSVC 19.10, a bit reorganizing in test
2021-01-30 07:42:58 -08:00
b0b56b4379 fix #2116 (FMT_COMPILE requires exceptions enabled) (#2117)
Co-authored-by: summivox <summivox@github.com>
2021-01-28 06:58:49 -08:00
373262f9fb Update docs 2021-01-24 09:11:44 -08:00
ce519e939b Fix exception propagation from iterators (#2097) 2021-01-23 17:27:24 -08:00
acef0bb51a use gcc-10.2 instead of gcc-10.1 on CI, also fix one problem (#2110)
the problem was not detected by test because of wrong gcc-10 minor version on CI
2021-01-23 07:52:41 -08:00
8bf28e6bb1 Add support for s format specifier to bool (#2094) (#2109) 2021-01-23 07:32:41 -08:00
9c418bc468 Update README.rst 2021-01-21 07:45:34 -08:00
456efa4666 add missing detail namespace (#2107)
Co-authored-by: Walter Gray <walter.gray@getcruise.com>
2021-01-19 17:44:15 -08:00
80dc7cceb8 Fixed format.h(1465): warning C4702: unreachable code (#2106)
* Fixed format.h(1465): warning C4702: unreachable code

* Fixed format.h(1416): warning C4702: unreachable code
2021-01-19 17:13:10 -08:00
7fd535c6ae Cleanup 'L' handling 2021-01-18 07:57:38 -08:00
b4b8917caf Update docs 2021-01-17 09:36:06 -08:00
e4f2cf455e Make 'L' a modifier 2021-01-17 09:28:46 -08:00
6972b5f3d2 Add build variable: FMT_MASTER_PROJECT (#2100) 2021-01-16 16:56:49 -08:00
ac35208115 Install fmt/args.h (#2096) 2021-01-16 08:13:38 -08:00
532e846b86 Fix width computation in float formatter 2021-01-15 11:07:55 -08:00
f8c2f8480a Fix handling of width when formatting int as char 2021-01-14 08:41:17 -08:00
0fe0b15e71 Fix handling of # in width computation 2021-01-13 16:48:07 -08:00
061e364b25 Document output_file 2021-01-09 07:18:56 -08:00
018688da2a Correct a typo on syntax.rst (documentation) (#2081) 2020-12-31 16:23:42 -08:00
9ec5592bb5 Fix writing to stdout when redirected to NUL on Windows (#2080) 2020-12-30 13:23:37 -08:00
cdc5ef6710 Remove fallback to inline specifier from FMT_CONSTEXPR(20) macro (#2075) 2020-12-30 06:23:20 -08:00
c9dd1eb97d Don't change charset 2020-12-27 07:44:02 -08:00
d09b5c1453 Fix std::byte formatting with compile-time API (#2072)
* add test for byte formatting with `FMT_COMPILE`

* fix byte formatting with `FMT_COMPILE`, use `__cpp_lib_byte` macro

* use is not custom mapped type check

* workaround MSVC bug
2020-12-27 07:23:28 -08:00
bbd6ed5bc5 Add support of most format_specs for formatting at compile-time (#2056) 2020-12-25 06:40:03 -08:00
a750bf3ac6 Update api.rst 2020-12-24 07:09:49 -08:00
1256541d7a Fix formatting 2020-12-24 07:07:15 -08:00
4fa4c9248f Add tests for FMT_ENFORCE_COMPILE_STRING, fix several errors (#2038) 2020-12-24 06:40:46 -08:00
aa89e380d9 add cwchar to format.h for std::fputws (#2073) 2020-12-23 07:02:25 -08:00
5a37e182de Disable warning about format string (#2067)
Reported by MinGW/GCC 10
2020-12-21 08:43:30 -08:00
fa43fd1444 Forward arguments to work with views (#2068) 2020-12-20 07:14:54 -08:00
3551f5d118 Workaround a gcc 10 -Warray-bounds bug (#2065) 2020-12-19 09:34:43 -08:00
e737672614 Remove an old mingw workaround (#2059) 2020-12-10 06:36:04 -08:00
25a41b80fc Fix a link to Android.mk (#2057) 2020-12-09 08:04:58 -08:00
9293f7072e Suppress gcc warning on privates-only class (#2053)
Since gcc 9 it warns about is_streamable to have only private methods.
Add explicit default ctor instead of suppression
2020-12-09 06:55:17 -08:00
c20874c28f Reenable support for fallback formatter in join (#2040) (#2050) 2020-12-08 08:56:53 -08:00
5de0bc1d4f Add UDL as replacement for FMT_COMPILE (#2043) 2020-12-07 15:53:11 -08:00
a6fafe2f01 docs: use https for some links (#2051) 2020-12-05 06:41:38 -08:00
33f9a6d360 Fix handling of enums in to_string (#2036) 2020-12-03 15:18:33 -08:00
aabe0a8473 simplify tests by reordering arguments of EXPECT_EQ (#2044) 2020-12-03 14:21:23 -08:00
1f4a76d2c8 Add a missing include (#2047) 2020-12-03 14:17:09 -08:00
4a6eadbde0 Make std::byte formattabe (#1981) 2020-12-03 08:59:07 -08:00
683a74501f fix formatting with empty compiled format string (#2042) 2020-12-02 07:14:57 -08:00
f43416e1d7 Add a link to contents from index 2020-12-02 06:30:09 -08:00
5a493560f5 Move some code from core.h to format.h where it is used 2020-11-29 09:45:15 -08:00
9ed0a98178 Fix docs build 2020-11-29 09:33:09 -08:00
dac753b81e Basics of formatting at compile-time based on compile-time API (#2019) 2020-11-29 08:59:11 -08:00
119f7dc3d6 Truncate file by default 2020-11-27 08:15:14 -08:00
22a68d1613 Don't emit trailing zeros by default 2020-11-27 07:45:54 -08:00
d0110b7e35 Update README.rst 2020-11-26 19:51:31 -08:00
3f4839ce3d Merge branch 'release' of github.com:fmtlib/fmt 2020-11-25 06:41:05 -08:00
7bdf0628b1 Update version 2020-11-24 17:15:02 -08:00
fc1355114d Update changelog 2020-11-24 17:14:00 -08:00
926233bde8 Fix test 2020-11-24 14:54:15 -08:00
0683fa7d1d Bump version 2020-11-24 08:36:21 -08:00
6ce207b9a5 Fix formatting 2020-11-24 08:29:17 -08:00
07b1c1a15f Update changelog 2020-11-24 08:24:14 -08:00
58992761cf Reintroduce ostream support to range formatters (#2014) 2020-11-24 08:22:29 -08:00
b8957f50c3 Fix an overflow in format_to_n (#2029) 2020-11-24 08:22:12 -08:00
df66516ed3 Workaround an issue with mixing std versions in gcc (#2017) 2020-11-24 08:21:10 -08:00
a57baa69a5 Fix more linkage errors (#2011) 2020-11-24 08:17:31 -08:00
85534a1397 Fix linkage errors when linking with a shared library (#2011) 2020-11-24 08:15:59 -08:00
a2fa5d6288 Update changelog 2020-11-23 10:35:07 -08:00
cd3003683d Fix more linkage errors (#2011) 2020-11-23 10:34:27 -08:00
d1ef29d679 Fix initialization of iterator_buffer (#1996) 2020-11-23 10:28:35 -08:00
5f41bb0f77 clang-format 2020-11-23 10:23:54 -08:00
a58a6b27c3 Add a newline 2020-11-21 16:52:40 -08:00
a036cc97b7 Reintroduce ostream support to range formatters (#2014) 2020-11-21 16:31:22 -08:00
38c7def47a Update clang version to 3.4 since there are ICEs on earlier ones 2020-11-19 10:37:43 -08:00
5533641319 🆕 [CI] Test with C++14 in Windows 2019 (#2020)
Problem:
- Both Windows builds test C++14

Solution:
- Use C++11 for `windows-2016` builds and C++14 for `windows-2019`
  builds.

Co-authored-by: Jonathan Gopel <jgopel@quantlab.com>
2020-11-19 06:04:16 -08:00
55dfdd9299 Update README.rst 2020-11-18 07:33:38 -08:00
2c734c9bca Fix an overflow in format_to_n (#2029) 2020-11-18 06:50:43 -08:00
6cdd1be93e Update build.gradle for latest AGP (#2026)
* update build.gradle for latest AGP

* bump Android Gradle Plugin version to 4.1.1
* ignore .cxx which was externalNativeBuild in old versions

Use variable 'rootDir' instead of using relative path.

* build.gradle copies AAR files to libs/
2020-11-17 06:31:06 -08:00
bcc20b29df Implement compile-time checks by default 2020-11-15 17:24:36 -08:00
befd7d4a2f Always use FMT_STRING internally where possible [Issue #2002] (#2006)
Co-authored-by: Walter Gray <walter.gray@getcruise.com>
2020-11-15 05:19:06 -08:00
f8640d4050 Add more standards 2020-11-14 12:02:46 -08:00
f81c14aa1e Workaround an issue with mixing std versions in gcc (#2017) 2020-11-14 11:41:51 -08:00
5555651ce0 Fix more linkage errors (#2011) 2020-11-14 06:06:10 -08:00
b268f8815d detail::write in one more place relevant to printf with long argument… (#2016) 2020-11-13 12:14:16 -08:00
aa9b09a9e3 🐛 Cannot call non-constexpr function in constexpr context (#2010)
Problem:
- gcc-8 gives the following error when compiling this function on all
  standards:
    test/std-format-test.cc: In member function 'constexpr auto std::formatter<S>::parse(std::format_parse_context&)':
    test/std-format-test.cc:112:17: error: call to non-'constexpr' function 'int isdigit(int)'
        if (!isdigit(c) || (++iter, get_char()) != '}')
         ~~~~~~~^~~

Solution:
- Write a `constexpr` version of `isdigit` for use in this function.

Co-authored-by: Jonathan Gopel <jgopel@quantlab.com>
2020-11-12 10:10:52 -08:00
986fa00406 Printf get container (#1982)
* eliminate one case where basic_print_context would copy a string into a fmt::basic_memory_buffer character by character instead of using fmt::basic_memory_buffer::append

* use detail::write instead of re-implementing it

* use to_unsigned to avoid signedness conversion warnings
2020-11-12 08:37:04 -08:00
7abc3c01e0 Suppress a useless warning (#2004) 2020-11-12 08:18:28 -08:00
6d14f78115 Fix linkage errors when linking with a shared library (#2011) 2020-11-12 06:11:17 -08:00
9534b9fe69 Refactor warning suppression 2020-11-12 05:45:36 -08:00
60dc273513 Simplify on_text 2020-11-11 15:13:44 -08:00
b5dac0f0f8 Reduce <algorithm> usage (#1998) 2020-11-11 09:12:15 -08:00
a07627b1f8 🐛 Implicit sign conversion warning in clang in c++17 and 20 modes (#2009)
Problem:
- On Apple clang version 11.0.3 (clang-1103.0.32.62) in C++17 and C++20
  mode, clang 11.0.0 in C++17 and C++20 mode, and clang 9.0.1 in C++17
  mode, the following error is generated:

    In file included from test/compile-test.cc:16:
    include/fmt/compile.h:518:25: error: implicit conversion changes signedness: 'long' to 'unsigned long' [-Werror,-Wsign-conversion]
      return {f, pos + (end - str.data()) + 1, ctx.next_arg_id()};
                     ~  ~~~~^~~~~~~~~~~~
    include/fmt/compile.h:538:31: note: in instantiation of function template specialization
          'fmt::v7::detail::parse_specs<int, char>' requested here
          constexpr auto result = parse_specs<id_type>(str, POS + 2, ID);
                                  ^
    include/fmt/compile.h:569:17: note: in instantiation of function template specialization
          'fmt::v7::detail::compile_format_string<fmt::v7::detail::type_list<int>, 0, 0, FMT_COMPILE_STRING>' requested here
            detail::compile_format_string<detail::type_list<Args...>, 0, 0>(
                    ^
    include/fmt/compile.h:648:37: note: in instantiation of function template specialization
          'fmt::v7::detail::compile<int, FMT_COMPILE_STRING, 0>' requested here
      constexpr auto compiled = detail::compile<Args...>(S());
                                        ^
    test/compile-test.cc:140:24: note: in instantiation of function template specialization
          'fmt::v7::format<FMT_COMPILE_STRING, int, 0>' requested here
      EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42));
                           ^
    In file included from test/compile-test.cc:16:
    include/fmt/compile.h:518:25: error: implicit conversion changes signedness: 'long' to 'unsigned long' [-Werror,-Wsign-conversion]
      return {f, pos + (end - str.data()) + 1, ctx.next_arg_id()};
                     ~  ~~~~^~~~~~~~~~~~
    include/fmt/compile.h:538:31: note: in instantiation of function template specialization
          'fmt::v7::detail::parse_specs<char [4], char>' requested here
          constexpr auto result = parse_specs<id_type>(str, POS + 2, ID);
                                  ^
    include/fmt/compile.h:494:27: note: in instantiation of function template specialization
          'fmt::v7::detail::compile_format_string<fmt::v7::detail::type_list<int, int, char const (&)[4], int>, 5, 2, FMT_COMPILE_STRING>'
          requested here
        constexpr auto tail = compile_format_string<Args, POS, ID>(format_str);
                              ^
    include/fmt/compile.h:539:14: note: in instantiation of function template specialization
          'fmt::v7::detail::parse_tail<fmt::v7::detail::type_list<int, int, char const (&)[4], int>, 5, 2, fmt::v7::detail::spec_field<char, int, 0>, FMT_COMPILE_STRING>' requested here
          return parse_tail<Args, result.end, result.next_arg_id>(
                 ^
    include/fmt/compile.h:569:17: note: in instantiation of function template specialization
          'fmt::v7::detail::compile_format_string<fmt::v7::detail::type_list<int, int, char const (&)[4], int>, 0, 0, FMT_COMPILE_STRING>'
          requested here
            detail::compile_format_string<detail::type_list<Args...>, 0, 0>(
                    ^
    include/fmt/compile.h:648:37: note: in instantiation of function template specialization
          'fmt::v7::detail::compile<int, int, char const (&)[4], int, FMT_COMPILE_STRING, 0>' requested here
      constexpr auto compiled = detail::compile<Args...>(S());
                                        ^
    test/compile-test.cc:145:18: note: in instantiation of function template specialization
          'fmt::v7::format<FMT_COMPILE_STRING, int, int, char const (&)[4], int, 0>' requested here
                fmt::format(FMT_COMPILE("{:{}}{:{}}"), 42, 4, "foo", 5));
                     ^
    2 errors generated.

Solution:
- Explicitly cast the result of the subtraction to the (unsigned) outer
  type.

Co-authored-by: Jonathan Gopel <jgopel@quantlab.com>
2020-11-11 07:57:52 -08:00
1b8f499ee1 🔧 Silence useless cast warnings (#2008)
Problem:
- gcc-10 is generating the following warning at all standards:

    test/format-test.cc: In member function 'virtual void UtilTest_BitCast_Test::TestBody()':
    test/format-test.cc:108:42: error: useless cast to type 'uint64_t' {aka 'long long unsigned int'} [-Werror=useless-cast]
      108 |   s = fmt::detail::bit_cast<uint32_pair>(uint64_t(~0ull));
          |                                          ^~~~~~~~~~~~~~~
- gcc-8 is generating the following warning at all standards:
    test/format-test.cc: In member function 'virtual void UtilTest_BitCast_Test::TestBody()':
    test/format-test.cc:108:56: error: useless cast to type 'uint64_t' {aka 'long long unsigned int'} [-Werror=useless-cast]
       s = fmt::detail::bit_cast<uint32_pair>(uint64_t(~0ull));
                                                        ^
Solution:
- Cast 0 to a 64 unsigned bit int and then invert.

Co-authored-by: Jonathan Gopel <jgopel@quantlab.com>
2020-11-11 07:56:59 -08:00
f428d286a1 Update README.rst 2020-11-11 07:11:43 -08:00
beb248b6ac Optimize handling of large format strings 2020-11-11 06:11:05 -08:00
1936dddc3c fix gcc warning of missing override (#2001)
Co-authored-by: Lieven de Cock <killerbot@linux-2x3u.suse>
2020-11-10 07:57:21 -08:00
14f6bd0f4e Move one more headers to args.h 2020-11-09 20:35:03 -08:00
e01d26e1a4 Optimize includes 2020-11-09 16:34:54 -08:00
e528d919a8 Merge branch 'master' of github.com:fmtlib/fmt 2020-11-08 12:45:15 -08:00
4881677268 Update signatures 2020-11-08 12:29:26 -08:00
3302fd1088 use memchr for searching for '%' in printf format string (#1984) 2020-11-08 10:36:00 -08:00
4c2d637203 Update signatures 2020-11-08 10:10:44 -08:00
beaff39618 Update signatures 2020-11-08 10:00:08 -08:00
ffa0a0834a Use newer versions of Sphinx and Breathe 2020-11-08 09:46:27 -08:00
038057eb3e Document contexts 2020-11-08 08:16:23 -08:00
5bedcb665b Fix initialization of iterator_buffer (#1996) 2020-11-08 08:08:55 -08:00
2435ea4113 Workaround MSVC mess 2020-11-08 07:48:03 -08:00
8c6215f5de Fix fmt/color.h 2020-11-08 07:24:07 -08:00
10ebe6cb48 Document color 2020-11-08 07:18:01 -08:00
1ac50fcb5a Suppress more bogus warnings 2020-11-08 07:04:42 -08:00
e098be8e88 Fix warning filtering 2020-11-08 06:58:41 -08:00
8cf0afaf1c Improve docs 2020-11-08 06:48:34 -08:00
e29f93e8a8 Suppress more bogus warnings 2020-11-08 06:33:42 -08:00
4e8d000f76 Suppress more bogus warnings 2020-11-08 06:29:50 -08:00
7787792e8d Fix re usage 2020-11-08 06:20:53 -08:00
6ee5e507c7 Fix imports 2020-11-08 06:16:49 -08:00
06ee32d1b5 Filter useless doxygen warnings 2020-11-08 06:13:56 -08:00
86bb7fe614 Add a missing import 2020-11-08 05:55:49 -08:00
959a9f5cad Merge branch 'master' of github.com:fmtlib/fmt 2020-11-08 05:50:48 -08:00
4f7df299ea Improve docs 2020-11-08 05:40:39 -08:00
b3ab0bc7e3 🎨 [CI] Specify the exact version of clang to use (#1991)
Problem:
- The version of clang to use is specified only as `clang++`. This is
  inconsistent with the specifications for gcc and exposed to unexpected
  failure if the default changes.

Solution:
- Specify the exact version of clang to use. I chose `clang++-9` as that
  is the version that `clang++` is currently resolving to.

Co-authored-by: Jonathan Gopel <jgopel@quantlab.com>
2020-11-08 05:18:24 -08:00
701ed6c874 Install deps in github actions instead of script 2020-11-07 11:16:38 -08:00
8f2131cf2d Document chrono 2020-11-07 10:51:08 -08:00
32c4af8f0d Document chrono 2020-11-07 10:38:51 -08:00
295a60ec8d Document chrono 2020-11-07 10:30:23 -08:00
a4fae96c96 Document chrono 2020-11-07 10:24:27 -08:00
263bb0e68d Document chrono 2020-11-07 10:19:40 -08:00
0506b328b5 Document chrono 2020-11-07 09:59:57 -08:00
4e426c19d0 Document chrono 2020-11-07 09:47:56 -08:00
9795d87348 Update docs 2020-11-07 09:27:06 -08:00
2eb0be0b73 Remove debug code and fix bot contact 2020-11-07 09:16:55 -08:00
cd95579834 Move less installation to actions 2020-11-07 09:12:54 -08:00
98639d0f6f Debug doc build 2020-11-07 09:04:07 -08:00
ab5e0632fe Debug doc build 2020-11-07 08:54:58 -08:00
b123129f4e Dump the content of html dir 2020-11-07 08:42:13 -08:00
81d2b986af Print less command 2020-11-07 08:24:58 -08:00
7a0b1d5781 Add key 2020-11-07 08:09:01 -08:00
9f0617cbfb Fix branch ref 2020-11-07 08:04:01 -08:00
75b07598fe Chrono docs 2020-11-07 07:56:53 -08:00
dfbb6975b3 Remove travis config 2020-11-07 07:38:20 -08:00
5b3052f999 Switch doc build to github actions 2020-11-07 07:31:15 -08:00
506ff320f2 Fix build failure when not using fcntl with -Werror (#1990) 2020-11-06 15:39:59 -08:00
a30b279bad Apply clang-format and tweak comments 2020-11-04 17:17:23 -08:00
6a2495c840 -Wattributes visibility warning with some GCC versions (#1975) 2020-11-04 17:11:31 -08:00
cba5970cd8 Remove migrated build configs 2020-11-04 10:03:00 -08:00
689081d832 Merge branch 'release' of github.com:fmtlib/fmt 2020-11-04 07:46:02 -08:00
cc09f1a679 Update version 2020-11-04 06:50:09 -08:00
e4eb242ce8 Update changelog and bump version 2020-11-03 21:20:53 -08:00
ce98e0c6a0 Fix fallback float formatter at assymetric bounds (#1976) 2020-11-03 21:18:04 -08:00
49544ea943 Fuzz fallback formatter 2020-11-03 19:34:35 -08:00
6b7bfed40c Fix fallback float formatter at assymetric bounds (#1976) 2020-11-03 19:19:10 -08:00
bcab36da3f Update CI config 2020-11-03 16:01:26 -08:00
1689e73e90 Move PR template 2020-11-03 14:52:47 -08:00
0103408a5c Update CI config 2020-11-03 14:39:43 -08:00
38a16ecba2 Move build config to github actions 2020-11-03 13:35:37 -08:00
205eb3a8f2 Update CI config 2020-11-03 13:27:15 -08:00
fe61b8c630 Update CI config 2020-11-03 11:59:59 -08:00
867b15d77c Update CI config 2020-11-03 11:48:20 -08:00
98cb9f9931 Update CI config 2020-11-03 11:43:00 -08:00
95077d60c9 Update CI config 2020-11-03 11:41:25 -08:00
bc49f094e7 Update CI config 2020-11-03 11:02:49 -08:00
cef6dfb422 Update CI config 2020-11-03 10:46:03 -08:00
c8703ba40b Update CI config 2020-11-03 10:45:16 -08:00
ab4405bea5 Update README.rst 2020-11-03 10:42:06 -08:00
78a55e2898 Update CI config 2020-11-03 10:37:30 -08:00
d0a2494a99 Update cmake.yml 2020-11-03 10:17:38 -08:00
89d009ba6e Update cmake.yml 2020-11-03 10:14:38 -08:00
1f4ff47b41 Create cmake.yml 2020-11-03 10:04:28 -08:00
eb52ac7a35 🆕 Enable -Wshadow in pedantic mode
Problem:
- All `-Wshadow` warnings are fixed but there is nothing stopping them
  from being reintroduced.

Solution:
- Fail pedantic builds on `-Wshadow` warnings. This allows CI to prevent
  reoccurrence of the warning.

Notes:
- Not enabling `-Wshadow` for gcc versions 4 or lower because the
  warning is much more aggressive there to the point that it's mostly
  just noise.
2020-11-03 07:30:27 -08:00
e904e891bd 🎨 🐛 Rename all shadowed types and variables 2020-11-03 07:30:27 -08:00
771292c328 Remove sizeof from unused variable silencer (#1974)
Using sizeof causes some compilers to complain:
'operand of sizeof is not a type, variable, or dereferenced pointer'

static_cast itself should be enough to silence unused variable warning

Co-authored-by: Łukasz Mitka <lukasz.mitka@aptiv.com>
2020-11-03 06:48:19 -08:00
86bf6045c6 Merge branch 'release' of github.com:fmtlib/fmt 2020-11-02 06:27:49 -08:00
5f7f7b954d Update version 2020-11-01 06:30:39 -08:00
5d3f0741e3 Update changelog and bump version 2020-11-01 06:28:06 -08:00
563cbb6c21 Add a macro to workaround clang/gcc ABI incompatibility on ARM 2020-11-01 06:10:04 -08:00
425778aa67 Fix ABI compatibility (#1961) 2020-11-01 06:09:31 -08:00
69a84198b0 Remove accidental parenthesis (#1968)
fails only when FMT_BUILTIN_CTZLL is not defined
2020-11-01 06:09:25 -08:00
5c04504932 Removed [-Wsign-conversion] warning in GCC 2020-11-01 06:09:11 -08:00
556a1cfb34 Instantiate to_decimal to make gcc lto happy (#1955) 2020-11-01 06:08:57 -08:00
28a8eae850 Cleanup 2020-11-01 06:08:50 -08:00
236fea1f00 Workaround bugs in gcc 8 2020-11-01 06:08:28 -08:00
e50ced88c6 Add a macro to workaround clang/gcc ABI incompatibility on ARM 2020-10-31 07:52:08 -07:00
112755cf91 Remove FMT_SAFEBUFFERS (#1966) 2020-10-29 17:42:45 -07:00
4081b2fe94 Fix ABI compatibility (#1961) 2020-10-29 11:29:47 -07:00
2d9311e860 Remove accidental parenthesis (#1968)
fails only when FMT_BUILTIN_CTZLL is not defined
2020-10-29 07:08:06 -07:00
b3a4f28ad1 Fix implicit signedness conversion warning (#1963)
Problem:
- On Apple clang 11.0.3 (clang-1103.0.32.62), pedantic mode compilation
  generates the following error:

    test/std-format-test.cc:114:22: error: implicit conversion changes
          signedness: 'int' to 'size_t' (aka 'unsigned long')
          [-Werror,-Wsign-conversion]
        width_arg_id = c - '0';
                     ~ ~~^~~~~

Solution:
- Use a `to_unsigned` to make the conversion explicit. This is
  guaranteed to be safe due to the check before the ASCII-to-int
  conversion.
2020-10-29 06:26:18 -07:00
97c8873214 Allocator::max_size support in basic_memory_buffer (#1960) 2020-10-29 06:17:00 -07:00
bb68f6089b Removed [-Wsign-conversion] warning in GCC 2020-10-28 06:02:17 -07:00
f4ca065cfb Range support 2020-10-28 05:35:37 -07:00
cb224ecaa3 Instantiate to_decimal to make gcc lto happy (#1955) 2020-10-27 07:46:40 -07:00
7977c2b4d0 Cleanup 2020-10-27 07:19:28 -07:00
e54eb67639 Workaround bugs in gcc 8 2020-10-27 06:11:31 -07:00
4fe0b11195 Update version 2020-10-25 10:44:22 -07:00
df4bd60f42 Bump version 2020-10-25 10:43:03 -07:00
764fb35e1f Always install the required version of breathe 2020-10-25 10:34:47 -07:00
e1bdc0ecaf Use the correct version of sphinx 2020-10-25 09:52:21 -07:00
39bde329bd Tweak markup 2020-10-25 09:19:38 -07:00
204d299abb Tweak markup 2020-10-25 09:12:22 -07:00
e0995b1c14 Update readme 2020-10-25 09:04:39 -07:00
4af178bdfe Remove outdated build config 2020-10-25 09:01:44 -07:00
aa41dc02b1 Remove unused script 2020-10-25 09:00:25 -07:00
6a77ea3c93 Tweak markup 2020-10-25 08:59:36 -07:00
62c72059d9 Update changelog 2020-10-25 08:56:46 -07:00
c10e3f7f4f Update changelog 2020-10-25 07:29:24 -07:00
e542e6953e Update changelog 2020-10-25 06:46:45 -07:00
530cf316b8 Point to the release, not dev documentation 2020-10-24 12:02:12 -07:00
740385d636 Update changelog 2020-10-24 11:18:33 -07:00
cd4651116e Update changelog 2020-10-24 09:24:47 -07:00
46291be348 Update changelog 2020-10-23 07:38:01 -07:00
90071c1df0 Update ChangeLog.rst 2020-10-22 09:30:27 -07:00
25293d7ac6 Update ChangeLog.rst 2020-10-22 09:28:23 -07:00
5024742f8a Update ChangeLog.rst 2020-10-22 09:27:49 -07:00
0452a4e71f Update changelog 2020-10-22 09:08:30 -07:00
8de96817ce Woraround bugs in gcc 8 2020-10-22 07:33:32 -07:00
47e167679a Simplify arg formatter 2020-10-21 19:04:02 -07:00
f0a42346a4 Move parsing optimization one level up 2020-10-21 18:18:53 -07:00
86287b8d56 Optimize common case in parse_format_specs 2020-10-21 17:16:58 -07:00
8924211f3b Update README.rst 2020-10-21 14:02:55 -07:00
525e7649cf Update CONTRIBUTING.md 2020-10-21 14:02:33 -07:00
0ecb3d1829 Optimize alignment parsing 2020-10-21 12:45:11 -07:00
9755307842 Optimize format_uint 2020-10-21 08:19:21 -07:00
7446818f98 Simplify vformat_to 2020-10-21 07:15:11 -07:00
280b5612c0 Add option to force usage of inline namespaces
Detection of inline namespaces is imperfect as some compilers
don't provide __has_feature

This option allows to override it if needed.
2020-10-21 06:38:59 -07:00
e57ec7d563 Merge vformat_to overloads 2020-10-20 17:39:50 -07:00
2a3f4de3f4 Remove iterator_category 2020-10-20 16:44:49 -07:00
27fdb4ead2 Unshadow floaty 2020-10-20 15:05:00 -07:00
297e0bad8c Apply clang-format 2020-10-20 14:10:28 -07:00
e3b4c22ec9 Simplify is_output_iterator 2020-10-20 14:09:57 -07:00
da8278e1e3 Update changelog and bump version 2020-10-19 14:37:14 -07:00
17fba753c4 added position independent documentation (#1939)
* added position independent documentation

* suggested fixes to usage

* linebreaks

Co-authored-by: Adnan Yunus <adnan@opus.ai>
2020-10-19 14:20:54 -07:00
71e705a273 Update README.rst 2020-10-19 08:54:55 -07:00
74654c8cbb Fix compilation for systems without fcntl.h (#1942)
Co-authored-by: darklukee <no-reply@hidden>
2020-10-19 07:43:06 -07:00
f468b203ad Avoid conversion from long long to size_t (#1935) 2020-10-18 09:25:33 -07:00
20d4f2e836 Fix handling of weird character types when parsing sign (#1932) 2020-10-17 09:40:30 -07:00
08370c39ff Update README.rst 2020-10-17 08:27:21 -07:00
bd3c792507 Fix float fuzzer 2020-10-16 07:35:53 -07:00
8d3fd86d6d Merge branch 'master' of github.com:fmtlib/fmt 2020-10-16 07:35:02 -07:00
4034715713 Update README.rst 2020-10-16 06:47:16 -07:00
37d738fa6b Update README.rst 2020-10-16 06:46:39 -07:00
271eff149f Make classes derived from buffer<T> final to silence the virtual destructor warning. (#1937)
Co-authored-by: Bart Siwek <bsiwek@cisco.com>
2020-10-15 17:41:56 -07:00
010efc310f Add float fuzzer and cleanup 2020-10-14 20:13:09 -07:00
811c8b58c5 Add float fuzzer and cleanup 2020-10-14 07:39:51 -07:00
82c4e2236a Cleanup fuzzing 2020-10-13 09:08:04 -07:00
63e40c9614 Fix naming of fuzzers 2020-10-12 16:48:25 -07:00
2f448ed565 Fix fuzzer timeouts 2020-10-12 16:46:21 -07:00
af28305961 Cleanup 2020-10-11 10:13:42 -07:00
48ea8193df Explain why assert-test is a separate test 2020-10-11 10:13:42 -07:00
1d112bdd1e Remove old test 2020-10-11 10:13:42 -07:00
5eb292a653 Update README.rst 2020-10-11 09:57:21 -07:00
7e56b6b6cb Fix coding style and remove duplicate fuzzer 2020-10-11 08:07:52 -07:00
41d97e1ef4 Fix a UB on ridiculously large precision 2020-10-11 08:07:52 -07:00
01c37e0a4b Added check for -mbig-obj and ref qualifier check (#1929)
* Added check whether mingw has -mbig-obj flag
* Removed ref qualifiers
2020-10-11 07:49:54 -07:00
a5e7e7db95 Fix handling of thousand separator (#1927) 2020-10-10 07:23:36 -07:00
bf19051a9f Optimize floating point formatting 2020-10-09 15:29:56 -07:00
3c13a88b14 Optimize floating point formatting 2020-10-09 11:01:01 -07:00
f6d75c534c Refactor write_float 2020-10-09 09:11:39 -07:00
e9c0b2d69e Merge write_float overloads 2020-10-08 20:00:38 -07:00
7eddbfed53 Cleanup exponent handling in write_float 2020-10-07 15:58:43 -07:00
b347b3023f Update dynamic_formatter comment (#1923) 2020-10-07 12:15:07 -07:00
3541880efd Fix integer overflow when using max int precision 2020-10-07 11:27:02 -07:00
7b50dc0b24 Don't exclude all detail symbols from docs 2020-10-07 09:07:39 -07:00
2805243103 Fix the doc config 2020-10-07 08:11:59 -07:00
34f22e88a1 Cleanup CMake config 2020-10-07 08:11:42 -07:00
a18b3fbbdc Fix fixed precision handling when rounding (#1917) 2020-10-07 07:42:23 -07:00
7277035736 Fix long lines in usage.md 2020-10-06 06:26:11 -07:00
7612c1ea87 Add reference to lhelper package manager in usage 2020-10-06 06:26:11 -07:00
b91d39f20b Get rid of float_writer 2020-10-05 06:34:04 -07:00
b4b64b9cce Refactor float formatting 2020-10-04 14:44:25 -07:00
712abe40f2 Workaround a bug in gcc 7.5 (#1912)
Thanks Martin Janzen.
2020-10-04 09:20:37 -07:00
af8a180aed Make GetCachedPower test more precise 2020-10-04 08:00:47 -07:00
a581e9e5d8 Fix warning C4018: '<=': signed/unsigned mismatch (#1908) 2020-10-02 06:30:57 -07:00
05a28312cf Update docs 2020-09-30 17:38:28 -07:00
4d0aa4d8fe Update link 2020-09-30 17:21:07 -07:00
575f401896 Simplify FP formatting and follow coding conventions 2020-09-30 06:36:17 -07:00
6f3536f974 Move zero-check to an earlier branch (#1906) 2020-09-29 06:24:53 -07:00
90ef46df0b Fix dragonbox integration 2020-09-28 18:10:46 -07:00
3ae88147e2 Fix declaration 2020-09-28 06:50:09 -07:00
6417952574 Improve dragonbox integration 2020-09-27 20:49:37 -07:00
79694d424c Fix WriteConsole signature 2020-09-27 14:26:28 -07:00
51f2e2ca27 Move nan test to where it belongs 2020-09-27 12:50:18 -07:00
68555fdbd2 Make format-test not depend on color.h 2020-09-27 09:17:57 -07:00
63e0c35412 Make dragonbox::to_decimal available in format.h 2020-09-27 07:27:44 -07:00
2213a7110c Update README.rst 2020-09-26 11:46:39 -07:00
79ba37f3bf Update README.rst 2020-09-26 10:13:04 -07:00
a905d8f704 Merge grisu-test into format-test 2020-09-26 08:23:16 -07:00
762c33a964 Simplify windows handling (#1903) 2020-09-26 08:20:38 -07:00
253d63159f Remove dependency on windows.h (#1900) 2020-09-26 07:03:16 -07:00
c156093ffd Fix carry in fallback_format 2020-09-25 10:12:44 -07:00
34179b3354 Update format.h (#1898) 2020-09-24 08:16:16 -07:00
0651e4598b Minor tweaks to get_cached_power 2020-09-23 16:04:40 -07:00
6c025520aa Test that max_k is correctly defined 2020-09-23 15:44:37 -07:00
51f8d0cc21 Reuse log10_2_significand constant 2020-09-23 13:19:21 -07:00
1305cbeb6f Fix MSVC2019 error C2049 when compiling with /clr (#1897)
'fmt::v7': non-inline namespace cannot be reopened as inline
2020-09-23 09:55:41 -07:00
2d4fde3a2e Don't emit trailing zero for consistency with std::format 2020-09-23 09:19:12 -07:00
5fd89d50e4 Minor simplifications 2020-09-23 08:05:31 -07:00
605ce5e429 Simplify divisible_by_power_of_2 2020-09-22 20:44:29 -07:00
085171e7e6 Remove grisu_count_digits 2020-09-22 19:36:52 -07:00
aa729bf25b Remove dead code 2020-09-22 16:58:02 -07:00
aa2ddf9b86 Simplify Dragonbox integration 2020-09-22 16:20:40 -07:00
c1654ce487 Simplify uint32_or_64_or_128_t definition 2020-09-22 15:08:37 -07:00
33712dc07a Combine pragmas 2020-09-22 14:47:35 -07:00
e5942ac9dd Tweak comments 2020-09-22 14:36:10 -07:00
aae7a1338c Remove unused pragmas 2020-09-22 14:00:41 -07:00
6bcde9aab2 https://github.com/fmtlib/fmt/pull/1882#issuecomment-696823912 (#1894) 2020-09-22 10:33:52 -07:00
bb0db5e51e clang-format 2020-09-22 08:19:37 -07:00
16410056bf Optimize copy_str for counting_iterator 2020-09-22 07:56:09 -07:00
2591ab91c3 MSVC optimizations for count_digits. (#1890)
Changed the clz implementations to use xor instead of subtraction so that when
count_digits "undoes" the BSR -> CLZ translation, the optimizer is more
willing to recognize the equivalence.
Changed the data array in bsr2log10 to static since otherwise MSVC generates
code to build the array every time the function is called.
2020-09-21 11:38:06 -07:00
d5b8002dcb Update README.rst 2020-09-21 09:40:49 -07:00
821471e1d1 qkw: generalizing aliasing | using fmt library and it's features (#1888)
I make extensive use of this library for building qkw targeting linux users. Please add this to your list.
https://github.com/ravijanjam/qkw
2020-09-21 09:39:07 -07:00
2e620ddbcd Small improvements that should have zero to negligible impact on the runtime (#1887) 2020-09-20 09:34:44 -07:00
2f7e08856b Disable range formatter if value type is not formattable (#1885) 2020-09-20 08:37:49 -07:00
c46a8de4e1 Simplify test 2020-09-20 07:24:24 -07:00
2696dc9273 add forgotten template argument to make_format_args which made some u… (#1877)
* add forgotten template argument to make_format_args which made some uses of FMT_COMPILE not work anymore after 54daa0864a, add more elaborate test cases to compile-test as regression tests

* fix old-style cast which gcc on travis thankfully doesn't accept anymore

* hopefully last forgotten (void*)
2020-09-20 06:51:11 -07:00
0016da7ab3 Don't generate zeros and fix UB on huge precision 2020-09-19 16:01:43 -07:00
ce3f76994a Merge intrinsic blocks 2020-09-19 07:54:45 -07:00
3b6248f602 Change formatting 2020-09-19 07:23:41 -07:00
2d9b1dd0ad Fix sign mismatch 2020-09-19 07:23:41 -07:00
1f0600a23b Fix bug regarding FMT_SAFEBUFFERS 2020-09-19 07:23:41 -07:00
2ecdbb986d Fix a bug in ctzll 2020-09-19 07:23:41 -07:00
6f81ea151a Fix typo (and thus bug) 2020-09-19 07:23:41 -07:00
0c8ffe9b0f Implement Dragonbox (first version) 2020-09-19 07:23:41 -07:00
42699bf408 Fix msvc version of clz & clzll (#1880)
Change msvc version of clz & clzll to match __builtin_clz & _builtin_clzll
2020-09-18 11:07:01 -07:00
bc51a8df04 Disable fallthrough attributes for the Intel compilers on Linux and MacOS (#1879)
* Disable fallthrough attributes for the Intel compilers

On MacOS and Linux the Intel compilers may be identified as the
host compilers (Clang or GNU) but do not support the corresponding
compiler specific fallthrough attributes.

* Rearrange ifdef logic for excluding pre-C++17 fallthrough attributes

This puts Intel and PGI compilers into a separate group
and thus makes the intent and logic more obvious.
2020-09-18 09:57:00 -07:00
45da432d60 fix compiler warnings in public header files 2020-09-17 15:53:53 -07:00
d55e61f120 Improve FMT_ALWAYS_INLINE (#1878)
1. FMT_ALWAYS_INLINE should imply inline; otherwise, there might be
   linkage problems
2. Add specialization for MSVC (__forceinline)
2020-09-17 15:21:17 -07:00
7e6827521a Remove trailing zeros when using fallback formatter (#1873) 2020-09-17 08:16:21 -07:00
1d696dc280 Handle exotic character types in compilation 2020-09-17 07:12:34 -07:00
f674434a67 Add format_to_n overload that accepts FMT_COMPILE (from #1767) (#1869)
* Add format_to_n overload that accepts FMT_COMPILE

* add FormatToNWithCompileMacro test into CompileTest

Co-authored-by: Dmitriy Kurkin <Dmitriy.Kurkin@itiviti.com>
2020-09-15 07:28:06 -07:00
5b5a597198 Fix handling of wide alignment 2020-09-15 06:53:06 -07:00
f80ed64dd9 Update README.rst 2020-09-14 11:13:51 -07:00
3813966497 Simplify fallback format 2020-09-13 11:27:34 -07:00
dce8e49b4f Handle float in fallback formatter 2020-09-13 09:28:40 -07:00
78b5944313 Spelling 2020-09-12 13:14:49 -07:00
f233b56cdd Don't generate insignificant digits 2020-09-12 09:19:50 -07:00
595902f8a0 Update test 2020-09-11 07:57:40 -07:00
4f2ee8921d Use built-in FP formatter for any precision 2020-09-11 07:20:16 -07:00
58a044be5d Use built-in FP formatter for any precision 2020-09-11 07:19:45 -07:00
efe3694f15 Macro tweak and clang-format 2020-09-07 14:43:00 -07:00
9f312fe87e Implement fallback FP formatting with given precision (#1526) 2020-09-07 09:34:30 -07:00
fb289cf56b Fix coding conventions 2020-09-06 09:26:32 -07:00
86f0a7046e Fix formatting 2020-09-06 08:58:19 -07:00
bff4d18efb Add color format_to overloads
* Fix variable size basic_memory_buffer colorization
* Fix an unused arguments warning on GCC that blocks the CI otherwise
* Ref #1842
* Ref #1593
2020-09-06 08:24:15 -07:00
f19b8885f2 Fixed a warning in mingw32/mingw64 (#1860) 2020-09-06 06:27:37 -07:00
f8e00a084a NOMINMAX not handled properly (#1855) 2020-09-03 09:45:47 -07:00
6cccdc24bc Fix move constructor (#1844) 2020-09-01 08:48:56 -07:00
69902c1787 Allow use of <fcntl.h> in Linux when __has_include is not available (#1848) 2020-09-01 06:29:34 -07:00
1edd38b96e Add append mode. (#1847) 2020-08-31 15:48:39 -07:00
e66ba16923 Added build2 usage instructions. (#1838)
The `fmt` package have been available for `build2` users for several version, see: https://cppget.org/fmt

This simply add the minimum instructions for making a `build2` project depend on it.

There are other ways to do it, but they need more understanding of `build2`.
2020-08-28 15:15:15 -07:00
f39e6fb617 Add formatters for chrono::time_point<system_clock> (#1837)
Add formatters for chrono::time_point and helper overloads for localtime/gmtime(time_point)
Fixes #1819
2020-08-28 07:41:38 -07:00
77b627be20 Fix bogus MSVC warnings (#1825) 2020-08-26 12:33:54 -07:00
5dff01d31b Add complex tests 2020-08-26 11:48:50 -07:00
d16d585e64 Update signatures 2020-08-26 09:35:19 -07:00
c7e6d8afb0 Fix usage of override (#1836) 2020-08-23 11:01:46 -07:00
92bff2fe2c Revert "Add missing includes"
This reverts commit 06895a7687.
2020-08-21 16:24:53 -07:00
a0dcfbc57b Add ptr to docs 2020-08-21 06:54:05 -07:00
1651b2d433 Fix detail::write with fallback formatter (#1829)
* add support for fallback_formatter in detail::write

* add ToString test into OStreamTest

to check fmt::to_string() with class that has output stream operator

* add WithOstreamOperator test into CompileTest

to check fmt::format() with FMT_COMPILE() and class that has output stream operator

* use conditional_t inside detail::write instead of 2 overloads

* Revert "add WithOstreamOperator test into CompileTest"

* remove Context from template parameters in detail::write
2020-08-20 06:41:09 -07:00
06895a7687 Add missing includes 2020-08-19 20:33:04 -07:00
92a448a071 Apply clang-format 2020-08-19 10:42:22 -07:00
6be6544668 Fixing buffer_appender's ++ slicing (#1822)
* Fixing buffer_appender's ++ slicing.

* This test requires C++14.

* Removing string_view dependency.

* Simplifying test case.

* Adding message to static_assert
2020-08-18 12:37:56 -07:00
951e0d2333 CMakeLists.txt: Added Wundef warning to clang and gcc. (#1823)
Co-authored-by: Martin Wührer <martin.wuehrer@artech.at>
2020-08-18 07:04:44 -07:00
f9f02df719 CMakeLists.txt: Clang-warnings: removed -Wno-sign-conversion (#1817)
* CMakeLists.txt: Clang-warnings: removed -Wno-sign-conversion

* test/ranges-test.cc: changed type of integer literals to unsigned

* test/format-test.cc: fixed implicit conversion changes signedness warning in clang

Co-authored-by: Martin Wührer <martin.wuehrer@artech.at>
2020-08-14 13:58:20 -07:00
76e97dc4df Eliminate shadowed variable warnings on intel (#1816)
The intel-19 compiler warns about hidden variables:
```
/s/dev/nightly/libraries/ioss/src/fmt/format.h(2689): warning #1599: declaration hides variable "begin" (declared at line 2668)
      FMT_CONSTEXPR void operator()(const Char* begin, const Char* end) {
                                                ^
          detected during:
            instantiation of "Context::iterator fmt::v7::vformat_to<ArgFormatter,Char,Context>(ArgFormatter::iterator, fmt::v7::basic_string_view<Char>, fmt::v7::basic_format_args<Context>, fmt::v7::detail::locale_ref) [with ArgFormatter=fmt::v7::detail::arg_formatter<fmt::v7::detail::buffer_appender<char>, char>, Char=char, Context=fmt::v7::format_context]" at line 3492
            instantiation of "fmt::v7::detail::buffer_appender<Char> fmt::v7::detail::vformat_to(fmt::v7::detail::buffer<Char> &, fmt::v7::basic_string_view<Char>, fmt::v7::basic_format_args<fmt::v7::basic_format_context<fmt::v7::detail::buffer_appender<fmt::v7::type_identity_t<Char>>, fmt::v7::type_identity_t<Char>>>) [with Char=char]" at line 1413 of "/s/dev/nightly/libraries/ioss/src/fmt/format-inl.h"

/s/dev/nightly/libraries/ioss/src/fmt/format.h(2689): warning #1599: declaration hides variable "end" (declared at line 2669)
      FMT_CONSTEXPR void operator()(const Char* begin, const Char* end) {
                                                                   ^
          detected during:
            instantiation of "Context::iterator fmt::v7::vformat_to<ArgFormatter,Char,Context>(ArgFormatter::iterator, fmt::v7::basic_string_view<Char>, fmt::v7::basic_format_args<Context>, fmt::v7::detail::locale_ref) [with ArgFormatter=fmt::v7::detail::arg_formatter<fmt::v7::detail::buffer_appender<char>, char>, Char=char, Context=fmt::v7::format_context]" at line 3492
            instantiation of "fmt::v7::detail::buffer_appender<Char> fmt::v7::detail::vformat_to(fmt::v7::detail::buffer<Char> &, fmt::v7::basic_string_view<Char>, fmt::v7::basic_format_args<fmt::v7::basic_format_context<fmt::v7::detail::buffer_appender<fmt::v7::type_identity_t<Char>>, fmt::v7::type_identity_t<Char>>>) [with Char=char]" at line 1413 of "/s/dev/nightly/libraries/ioss/src/fmt/format-inl.h"
```
Rename the second set of variables to `pbegin` and `pend` to eliminate warning.
2020-08-13 18:58:31 -07:00
e204df0e66 nvcc compiler should be EDG-based, but fails test (#1818)
Our nvcc compilers (10.1.243 and 9.2.X) do not define the correct value for `FMT_USE_UDL_TEMPLATE` and then end up with an error later on in the build.  Explicitly search for `__NVCC__` symbol not being defined.   Might want to instead use `FMT_NVCC` or some other check, but the raw `__EDG_VERSION__` check is not working correctly for nvcc.
2020-08-13 15:18:57 -07:00
1c8bb54703 small changes to reduce clang-9 warnings (#1808)
* include/fmt/format.h: int_writer: removed unnecessary iterator type re-declaration (prevents shadow-waringing in clang)

* include/fmt/format.h: int_writer: correctly cast signed integer to unsigned to prevent 'implicit conversion changes signedness'-warnings in clang.

Co-authored-by: Martin Wührer <martin.wuehrer@artech.at>
2020-08-13 11:56:03 -07:00
4b69c78751 fix: warning C4100: unreferenced formal parameter (#1814)
Add [[maybe_unused]] to fix it.
2020-08-12 06:57:22 -07:00
fb0aeb8209 fix: disabled UDL templates for PGI (#1811) (#1812)
* fix: disabled UDL templates for PGI (#1811)

* fix: insert defined auround __PGI

Co-authored-by: n16h7hunt3r <n16h7hunt3r@nixos>
2020-08-11 15:27:27 -07:00
54daa0864a Add dynamic width support to FMT_COMPILE (#1809) 2020-08-10 09:40:11 -07:00
6fb7c6fb25 Workaround a bug in gcc10 (#1810) 2020-08-10 07:20:34 -07:00
16985fdadf Update README.rst 2020-08-09 08:56:51 -07:00
1378ddaefd Update README.rst 2020-08-08 18:01:56 -07:00
4fd95e4b4d Don't remove trailing zeros with # 2020-08-08 08:14:39 -07:00
e06ae32294 Avoid warnings on functions with external linkage that don't have declarations 2020-08-08 07:58:13 -07:00
7fc3d1f54c Add override to grow 2020-08-08 07:23:11 -07:00
065889a593 Use correct capacity in iterator_buffer (#1807) 2020-08-08 07:01:21 -07:00
d0dd678693 Adding convenience append(range) 2020-08-08 06:33:46 -07:00
0e7cef069b Merge commit 'c13f79e0' 2020-08-08 06:28:45 -07:00
e2c8c4557a Update README.rst 2020-08-07 20:58:29 -07:00
e4c954ff0e Update README.rst 2020-08-07 16:03:15 -07:00
c13f79e09e Merge release branch 2020-08-07 07:01:21 -07:00
d7921d649a Update README.rst 2020-08-06 19:41:17 -07:00
cd4af11efc Update version 2020-08-06 08:51:01 -07:00
1ebc2f7cc6 Bump version 2020-08-06 07:41:04 -07:00
f4c997062a Fix changelog 2020-08-06 07:40:46 -07:00
72920ba30a Update changelog 2020-08-06 07:39:37 -07:00
0907c08ae5 Fix handling of default alignmment with locale (#1801) 2020-08-06 07:39:09 -07:00
37c8f4eaf3 Don't use 128 bit integers with clang-cl (#1800)
clang-cl currently has a long-standing bug that using 128 bit integers
generates references to symbols that are provided neither by its own nor
by the Microsoft runtime: https://bugs.llvm.org/show_bug.cgi?id=25305
2020-08-06 07:38:57 -07:00
eaaaec9992 Workaround a bug in msvc 2020-08-06 07:38:51 -07:00
ccf8561cb3 Workaround broken numeric_limites, part 2 (#1787) 2020-08-06 07:38:32 -07:00
0cc73ebf79 Report error on missing named argument (#1796) 2020-08-06 07:38:18 -07:00
33efc3c94f Fix handling of iterators in locale-specific formatting (#1782) 2020-08-06 07:38:08 -07:00
4a4fc225ed Update changelog 2020-08-06 07:34:56 -07:00
61602a75db Remove -Wno-shadow 2020-08-05 10:55:09 -07:00
2f8fc29e9b Update README.rst 2020-08-05 10:53:49 -07:00
717b226b59 include/fmt/format.h: explicit cast to std::size_t for parameter to buffer.resize() in order to get rid of warning 'implicit conversion changes signedness:' in clang-8 (#1802)
Co-authored-by: Martin Wührer <martin.wuehrer@artech.at>
2020-08-05 09:37:10 -07:00
2a69f56769 Tweak buffer size 2020-08-05 08:22:12 -07:00
ea76933802 Simplify ostream 2020-08-04 20:11:43 -07:00
5413713c95 Remove unused function 2020-08-04 19:08:06 -07:00
57f462428d Increase the default buffer size 2020-08-04 08:19:19 -07:00
0b6e7cc60a Update README.rst 2020-08-03 21:51:48 -07:00
e587adb4e9 Simplify count_digits 2020-08-03 15:45:48 -07:00
279d698e1b Fix handling of default alignmment with locale (#1801) 2020-08-03 10:51:42 -07:00
76cfb50b2d Test complex formatter 2020-08-03 10:05:18 -07:00
208291205d Optimize count_digits 2020-08-02 07:58:36 -07:00
8d9ab96736 Cut a few cycles from count_digits 2020-08-01 18:33:53 -07:00
734344931f Simplify ostream_params 2020-08-01 18:33:53 -07:00
2a47a1e48f Update README.rst 2020-08-01 12:00:01 -07:00
7c4c5c79d2 Make buffer size configurable 2020-08-01 10:53:58 -07:00
f0b84da5ff Don't use 128 bit integers with clang-cl (#1800)
clang-cl currently has a long-standing bug that using 128 bit integers
generates references to symbols that are provided neither by its own nor
by the Microsoft runtime: https://bugs.llvm.org/show_bug.cgi?id=25305
2020-07-30 17:21:35 -07:00
a3dfd6f927 Workaround a bug in msvc 2020-07-30 11:13:54 -07:00
51d05521e9 Workaround broken numeric_limites, part 2 (#1787) 2020-07-30 09:42:24 -07:00
21c8b5c142 Report error on missing named argument (#1796) 2020-07-30 07:16:15 -07:00
d82fdcc9e2 Fix handling of iterators in locale-specific formatting (#1782) 2020-07-30 07:03:11 -07:00
633213d96f Merge release branch 2020-07-29 08:52:53 -07:00
b9d749095e Update version 2020-07-29 07:30:55 -07:00
86b63bb71a Bump version 2020-07-29 07:14:25 -07:00
cbf6be9604 Update changelog 2020-07-29 07:07:56 -07:00
229ee9b469 Workaround broken numeric_limits (#1725) 2020-07-29 07:06:45 -07:00
2b7a146fa1 Fix a regression in handling digit separators (#1782) 2020-07-29 07:04:11 -07:00
89d0c7124b Fix compatibility with CMake 3.4 (#1779) 2020-07-29 07:03:59 -07:00
e8f2580a43 Bump version 2020-07-28 09:25:15 -07:00
6cefe55ac7 Update changelog 2020-07-28 09:15:02 -07:00
64e2da15cd Update README.rst 2020-07-28 08:35:28 -07:00
1c8c810f88 Update README.rst 2020-07-28 08:32:37 -07:00
c2399ccfca Update README.rst 2020-07-28 08:21:04 -07:00
a7c5db06d5 Update README.rst 2020-07-28 08:18:10 -07:00
a4c22acd0a Update README.rst 2020-07-26 12:12:31 -07:00
0c1f4b5a0d Update README.rst 2020-07-26 10:57:59 -07:00
63b422ee5e Update README.rst 2020-07-26 10:37:00 -07:00
26e81a6731 Update README.rst 2020-07-26 10:29:03 -07:00
de5fc6af3b Update README.rst 2020-07-26 10:19:55 -07:00
9c2edfd1aa Partially revert 638db5 because it breaks the doc build 2020-07-26 09:44:37 -07:00
810357c014 Document color 2020-07-26 08:22:56 -07:00
0a7032a400 Update README.rst 2020-07-26 08:14:18 -07:00
95d3abf95c Make format_to_n part of the core API 2020-07-24 09:25:26 -07:00
98626093d2 Correct the locale format specifier in api.rst (#1792) 2020-07-23 21:01:54 -07:00
47f8d7a345 Make formatted_size part of the core API 2020-07-23 08:51:38 -07:00
46a63b7087 Update docs 2020-07-23 07:12:19 -07:00
430f393d6f Disabled __attribute__((deprecated)) usage for LCC (#1790) 2020-07-23 06:34:03 -07:00
febffa4e64 Make join() handle non-const-only begin/end ranges (#1786)
See fmtlib/fmt#1784.

Add tests that demonstrate the problem and check obvious variations.
2020-07-21 12:13:00 -07:00
d69e2da221 Fix apidoc 2020-07-20 10:38:14 -07:00
ce73ea37fb Reorder functions 2020-07-20 09:42:14 -07:00
d39d661b18 Workaround broken numeric_limits (#1725) 2020-07-20 08:39:15 -07:00
c228bfe882 Improve docs 2020-07-20 07:56:20 -07:00
38ce19f738 Update README.rst 2020-07-20 07:29:57 -07:00
d11849bc0b Add FMT_REDUCE_INT_INSTANTIATIONS flag (#1781)
* Remove <typename UInt> from int_writer

Reduce code bloat by removing multiple instantiation of int_writer based
on the <typename UInt> parameter.

Rationale:
- The only functions that gains a speedup by int size would be
  int_writer::on_dec()'s call to count_digits which uses CLZ. Thus to
  still take advantage of this speedup, we store the size of the int
  so we can use a switch statement to call the correct count_digits.
- All other implementations of count_digits require some sort of looping
  that terminates when the value hits zero regardless of what sized int
  it is.

Caveats:
- There is a performance hit when dealing with and passing around
  64-bit/128-bit values compared to 32-bit values on 32-bit platforms,
  and with 64-bit values on 64-bit systems. But this should not reduce the
  performance that dramatically.
- There is also a performance hit for on_dec() due to the addition of a
  switch case. But, due to it size, this should reduce to a jump table.

Resolves #1778

* Add FMT_USE_SMALLEST_INT flag

When defined and set to zero, will use the largest available integer
container for writing ints. The has the benefit of reducing instances
the of int_writer class which will reduce the binary cost.

* Rename flag to FMT_REDUCE_INT_INSTANTIATIONS

Add comment above FMT_REDUCE_INT_INSTANTIATIONS definition describing
why a developer would use it.

* Move FMT_REDUCE_INT_INSTANTIATIONS to format.h

Co-authored-by: Khalil Estell <kammce@google.com>
2020-07-19 13:09:10 -07:00
c08518a25b Move make_args_checked to the public API 2020-07-19 10:23:46 -07:00
e2837084ee Add a color section 2020-07-19 09:51:52 -07:00
9f0c003371 Simplify format string checks 2020-07-19 09:24:11 -07:00
d615137ca0 Improve handling of buffer iterator 2020-07-19 09:02:26 -07:00
26b47b6fb5 Bump tested CMake version to 3.18
Use the version range feature introduced in 3.12. On CMake <3.12 the extra dots are simply interpreted as extra version number separators.
The fallback for ancient CMake versions is kept.
2020-07-19 08:50:34 -07:00
7a01c9c523 Update README.rst 2020-07-18 09:17:10 -07:00
b17d5c4f5d Fix a regression in handling digit separators (#1782) 2020-07-18 08:31:47 -07:00
eb90da2e82 Type erase output iterators 2020-07-18 07:50:29 -07:00
9d3cd0afb2 Type erase output iterators 2020-07-17 12:57:50 -07:00
18024853b6 Fix compatibility with CMake 3.4 (#1779) 2020-07-17 06:41:25 -07:00
f5d4215b7c Trying to clear ambiguous compile time claims (#1775)
* Trying to clear ambiguous compile time claims

Documentation was a bit misleading.
Many people assume that fmt does compile time checks by default, while it requires the use of `FMT_STRING`.
It was also unclear that FMT_COMPILE does the same checks.

https://github.com/fmtlib/fmt/issues/1772

* Update api.rst
2020-07-16 06:19:49 -07:00
c26349f4d2 Improve error reporting 2020-07-14 12:06:12 -07:00
f4b11ef6e2 Add a short anchor 2020-07-14 09:39:22 -07:00
0097cf113d Report unformattable type name more prominently 2020-07-13 08:46:53 -07:00
8fa20b471b dev -> latest 2020-07-13 06:15:47 -07:00
a03bd3ddb0 Autodetect MSVC static runtime (#1770)
* Autodetect MSVC static runtime

* Update condition (MSVC)
2020-07-13 06:11:23 -07:00
c108ee1d59 Clarify a comment 2020-07-12 10:59:33 -07:00
a8074a865a Update README.rst 2020-07-12 09:57:02 -07:00
5f62954864 Update README.rst 2020-07-12 09:55:24 -07:00
bd903f96ac Clarify precedence 2020-07-12 09:02:31 -07:00
16cac46a09 Improve handling of streamable and convertible to bool types (#1766) 2020-07-12 08:34:45 -07:00
415cd51913 direct_buffered_file -> ostream 2020-07-11 17:29:17 -07:00
e1bfb59619 Fix handling of code units in compile 2020-07-11 09:03:21 -07:00
ba8d98cbb7 Cleanup direct_buffered_file 2020-07-11 08:27:37 -07:00
04a1f6e991 Improve handling of single code units in compile 2020-07-11 08:21:14 -07:00
e4f57bfd7f Add an overload of write for buffer_appender 2020-07-11 08:20:30 -07:00
d870468159 Make append work with fixed-size buffer 2020-07-11 07:27:20 -07:00
e8ec09ae83 Cleanup core-test 2020-07-10 21:25:27 -07:00
a2c4fed981 Double buffering no more 2020-07-10 20:35:14 -07:00
36406509d9 Add a fixed buffer 2020-07-10 06:30:37 -07:00
60c43e8703 Apply clang-format 2020-07-09 09:06:24 -07:00
b998e0f30b Reduce symbol sizes and simplify iterator use 2020-07-09 08:51:43 -07:00
c5adfc51c5 Update README.rst 2020-07-09 06:21:02 -07:00
c4ad94ce26 Update README.rst 2020-07-08 18:17:26 -07:00
c1429651eb Fix image source link 2020-07-08 13:34:47 -07:00
638db5ca5e Use Cmake to find Python and Sphinx-doc.
Signed-off-by: Vitaly Zaitsev <vitaly@easycoding.org>
2020-07-08 08:06:57 -07:00
c090569751 Update readme 2020-07-08 08:01:36 -07:00
1efdb2dde4 Simplify readme 2020-07-08 07:47:18 -07:00
dc69afad14 Cleanup example 2020-07-08 07:44:36 -07:00
445f5d392b Break long lines 2020-07-08 07:36:07 -07:00
23063c3444 Update readme 2020-07-08 07:11:13 -07:00
f57b62575c Move PR template to the top level 2020-07-08 07:01:19 -07:00
f19b1a521e Update version 2020-07-07 07:47:44 -07:00
5c67fefb26 Fix a changelog entry 2020-07-07 06:58:44 -07:00
1d2a556e1b Fix undefined reference error 2020-07-07 06:37:17 -07:00
04c9b62fb4 Merge release branch 2020-07-07 06:34:39 -07:00
6be6762e57 Fix date 2020-07-07 06:32:19 -07:00
f1dd2eb3c0 Bump version 2020-07-07 06:24:32 -07:00
fbf3b943cc Workaround a bug in gcc 2020-07-07 06:06:50 -07:00
a29a01d304 Fix docs 2020-07-07 06:05:00 -07:00
9f0b3afb79 Bump version in namespace 2020-07-06 09:47:27 -07:00
86b2f99f8c Fix the docs 2020-07-06 07:53:07 -07:00
c472ff12d8 Update version 2020-07-06 06:45:20 -07:00
5173a76ba4 Update version 2020-07-05 08:43:47 -07:00
1614af3520 Minor corrections in the changelog 2020-07-05 08:43:01 -07:00
569a9b3a7f Bump version 2020-07-05 07:59:11 -07:00
4e7e3c65a3 Update docs 2020-07-05 07:32:43 -07:00
0f7a6bfa12 Add a section on std::format compatibility 2020-07-05 07:07:29 -07:00
4faec5a5ee Update README.rst 2020-07-05 06:41:51 -07:00
7dbc8ac716 Update changelog 2020-07-05 06:29:05 -07:00
c87dd746fa Update changelog 2020-07-05 06:21:54 -07:00
372175caf8 Revert changelog changes 2020-07-05 06:21:54 -07:00
9047548766 Add ClickHouse to the list of projects (#1751) 2020-07-05 05:57:04 -07:00
d30bca64e3 Revert changelog conversion since GFM is not supported there 2020-07-04 17:43:30 -07:00
d6047cdc4a Update changelog 2020-07-04 15:46:48 -07:00
810241b36e Convert changlog to markdown 2020-07-04 15:20:33 -07:00
661c474739 Rename changelog 2020-07-04 15:14:42 -07:00
7c33059fad Update ChangeLog.rst 2020-07-04 10:16:55 -07:00
9e20883ab3 Update README.rst 2020-07-04 09:37:27 -07:00
41899d5225 Update changelog 2020-07-04 09:31:12 -07:00
f42f459089 Update changelog 2020-07-04 08:40:42 -07:00
2381df654f Update readme 2020-07-04 08:27:57 -07:00
7ae816563e Update README.rst 2020-07-04 08:20:45 -07:00
c56cf3d074 Update changelog and readme 2020-07-04 08:20:10 -07:00
01309a34ab Deprecate arg_formatter 2020-07-04 07:29:11 -07:00
a62d060554 Update changelog 2020-07-04 07:24:49 -07:00
23e3a2eee8 Update changelog 2020-07-03 19:39:08 -07:00
d8e0554b97 Disable numeric formatting by default 2020-07-03 10:35:49 -07:00
1e8eea4f44 Update changelog 2020-07-03 10:31:14 -07:00
44bd5384a9 Fix formatting 2020-07-03 09:18:18 -07:00
20e19387a2 Update changelog 2020-07-03 09:14:11 -07:00
56fed78149 FMT_NUMERIC_ALIGN -> FMT_DEPRECATED_NUMERIC_ALIGN 2020-07-03 08:53:01 -07:00
56e63078ff Make the n specifier an opt-in 2020-07-03 08:02:48 -07:00
31ce6bc702 Fix a conversion warning with Clang10 on Windows (#1750)
Fixes #1747
2020-07-03 05:53:42 -07:00
c9c5b90da7 Fix a typo. Thanks Tracy Chapman from TripleChecker 2020-07-02 15:09:34 -07:00
1f3f84631c Fix a typo 2020-07-02 07:29:38 -07:00
5de62af604 Fix possible infinite recursion in FMT_ASSERT (#1744)
Use std::fprintf for assertion message output preventing infinite
recursion when output to stderr is limited or broken.
2020-07-01 08:28:27 -07:00
cbddab2fe2 Use consistent include style 2020-06-29 09:59:25 -07:00
f69b6eaabd Add a simple buffered stream with no sync 2020-06-28 09:55:29 -07:00
ba363b3a24 Use digit pairs as in unrolledlut 2020-06-27 12:05:38 -07:00
a6f8e7d860 Update changelog 2020-06-27 09:35:02 -07:00
e753244ab6 Update changelog 2020-06-27 06:02:34 -07:00
98a7a8b405 Update changelog and disable internal 2020-06-26 19:07:33 -07:00
3135d95fd9 Don't use non-portable attribute 2020-06-26 10:21:14 -07:00
8630a8f5ff Tweak the docs 2020-06-25 11:29:49 -07:00
cc3a88e6b3 Extract docs from compile.h 2020-06-25 08:36:07 -07:00
79c4b6bd70 Apply clang-format 2020-06-25 08:12:10 -07:00
d130ee070f Document format string compilation 2020-06-25 08:12:10 -07:00
d0f90b5be7 Spelling fixes 2020-06-24 06:29:54 -07:00
6e080660dc Update README.rst 2020-06-24 06:26:58 -07:00
31c3a24266 Spelling fixes 2020-06-23 15:56:16 -07:00
613b3b459d Spelling fixes 2020-06-23 15:55:31 -07:00
978521bb81 Fix a compile error introduced in #1738 2020-06-23 15:17:43 -07:00
4e94c649f9 Deprecate compile 2020-06-23 14:03:37 -07:00
1a83443e6c Add user-defined type support to compilation 2020-06-23 12:45:57 -07:00
8bef1c3b3a Tweaks for EDG based compilers (Intel, nVidia, MCST/Elbrus, etc).
Using the __EDG_VERSION__ macro for checks related to EDG-based
compilers instead of a macros specific for each of ones.
2020-06-23 05:50:25 -07:00
b287c37c65 Do not use -Wl,--as-needed with emscripten.
On some platform, fmt is using the following link flag:
```cmake
  target_link_libraries(fmt -Wl,--as-needed)
```

This is not supported by wasm-ld as of today.
This patch stop using it when compiling using emscripten.

Bug: https://github.com/fmtlib/fmt/issues/1736
2020-06-21 11:46:04 -07:00
2cac8a9d2e Reintroduce UDT support to fmt::to_string and test ADL 2020-06-21 09:21:07 -07:00
9a4cc88426 Add FMT_COMPILE support to format_to 2020-06-20 15:15:41 -07:00
5ddf9ee1bd Streamline default FP formatting 2020-06-20 07:12:50 -07:00
0b3a83f7f4 Update README.rst 2020-06-20 05:37:58 -07:00
5aa5c98738 Added #define WIN32_LEAN_AND_MEAN before including windows.h (#1729)
Co-authored-by: gabime <gmelman1@mgail.com>
2020-06-17 07:44:03 -07:00
397ad1bec3 Optimize common case 2020-06-15 18:30:31 -07:00
7431165f38 Make to_string bypass format 2020-06-15 17:55:16 -07:00
ee4d4c7fd0 Inline compiled format 2020-06-14 11:38:39 -07:00
ab2f8484e0 Finish text::format 2020-06-14 11:04:41 -07:00
e900d735bb Re-enable assert in format_decimal 2020-06-14 09:30:03 -07:00
f4de7b684a Fix ambiguity 2020-06-14 08:26:12 -07:00
1f8f5450b5 Reuse format_decimal 2020-06-14 07:42:52 -07:00
d702a68df2 Fix formatting of bool with FMT_COMPILE and add more tests 2020-06-14 07:16:50 -07:00
e956a14e9e Use write instead of format_int in to_string 2020-06-13 20:07:08 -07:00
98dcc251eb Undo branching reduction 2020-06-13 18:23:52 -07:00
5b8641dddf Undo branching reduction 2020-06-13 16:50:55 -07:00
8c88abde64 Fix sign handling in 'L' 2020-06-13 06:57:19 -07:00
23b976a615 Reduce branching 2020-06-12 19:46:00 -07:00
9edee0e727 Optimize small string parsing 2020-06-12 19:22:33 -07:00
a909d42b76 Fix a warning 2020-06-12 13:49:31 -07:00
16637341b9 Enable compilation for all types 2020-06-12 13:27:21 -07:00
2d71d7e030 Add a simple format string compilation API 2020-06-12 08:37:15 -07:00
d259fcfb05 Tweak comments 2020-06-12 06:22:05 -07:00
704ed557a1 Move project in order to solve a CMake warning
CMake Warning (dev) at /usr/share/cmake-3.17/Modules/GNUInstallDirs.cmake:225 (message):
  Unable to determine default CMAKE_INSTALL_LIBDIR directory because no
  target architecture is known.  Please enable at least one language before
  including GNUInstallDirs.
2020-06-12 06:04:31 -07:00
8603bd20d0 Update README.rst 2020-06-11 17:25:20 -07:00
547f12ae63 Fix a warning (#1722) 2020-06-11 15:02:42 -07:00
f904e8a1b4 c++11 use formatting user-defined types (#1721) 2020-06-11 10:10:39 -07:00
100e8af08a Update README.rst 2020-06-10 07:46:01 -07:00
c11d0f056e Update README.rst 2020-06-10 07:02:12 -07:00
2453ee576a Improve default formatting 2020-06-09 08:59:01 -07:00
47ae521557 MINGW cross compiler fixes 2020-06-09 06:19:22 -07:00
936a1833c2 Add default_arg_formatter 2020-06-08 08:14:34 -07:00
f2c9cb6244 Fix a UB 2020-06-08 06:32:11 -07:00
d3107f8551 Cleanup arg_formatter_base 2020-06-07 20:55:38 -07:00
5e7c70e206 Simplify arg_formatter_base 2020-06-07 19:38:43 -07:00
38cc68b3e5 Inline visitor 2020-06-07 08:36:33 -07:00
6732ea5000 Make symbols readable 2020-06-07 07:49:11 -07:00
57ddc77ce7 Make advance_to a noop for back_insert_iterator 2020-06-06 19:36:39 -07:00
50bad7d62d Optimize format string parsing 2020-06-06 10:15:19 -07:00
8f7a824e47 Inline visit 2020-06-06 09:02:32 -07:00
f11e968708 Optimize format string parsing 2020-06-06 08:15:33 -07:00
09737dd83b Optimize format handler 2020-06-06 07:17:02 -07:00
d9e3d6e6ed Move format_handler to detail 2020-06-06 06:38:48 -07:00
795b47a7b5 Fix a warning (#1712) 2020-06-05 08:24:09 -07:00
95c6ac0cc8 fix typo which caused the loss of the counting information when using a printf context with a truncating_iterator 2020-06-05 07:37:54 -07:00
21409cfdda Fix warnings 2020-06-04 07:50:07 -07:00
88c8d534e7 Move digits10 to where they belong and add comments 2020-06-04 06:39:18 -07:00
0f3eaeac0a Fix a warning 2020-06-04 06:33:11 -07:00
344218510d Ignore /doc/node_modules directory 2020-06-04 05:19:39 -07:00
16aec06179 Cleanup arg_formatter_base 2020-05-31 10:58:52 -07:00
1e1193590d Fix format_decimal overloads 2020-05-31 10:12:34 -07:00
0893c9c2ef Inline parse_format_string 2020-05-30 20:30:18 -07:00
3245145a41 Remove undocumented buffer_range and output_range 2020-05-30 13:07:52 -07:00
57fc44907f Increase VM disk size 2020-05-30 11:25:40 -07:00
7d22bebb6f Remove uses of buffer_range 2020-05-30 06:50:45 -07:00
8f2b5fe74d Don't install sphinx cache files
When building documentation sphinx creates cached files in the .doctrees
directory and aren't required for viewing documentation only for
building. As added benefit this makes fmt reprodcubile as the cached
files are different when the build environment is varied.
2020-05-30 06:14:02 -07:00
f095c67b6a Remove uses of buffer_range 2020-05-29 18:14:03 -07:00
5aabf1f715 Simplify copy_str 2020-05-29 17:59:08 -07:00
19c5b5d159 Simplify arg_formatter 2020-05-29 16:53:12 -07:00
519571edec Simplify arg_formatter_base 2020-05-29 14:44:18 -07:00
ac8dfd841f Improve handling of separators 2020-05-29 08:15:44 -07:00
2c6165a22b Reduce the number of comparisons 2020-05-29 05:42:35 -07:00
28639969ef Use memcpy for copying digits 2020-05-28 22:33:08 -07:00
f5fa1dee54 Support custom FMT_INC_DIR in pkgconfig and cmake configs (#1702)
* Support custom FMT_INC_DIR in pkgconfig and cmake configs

When CMAKE_INSTALL_INCLUDEDIR or FMT_INC_DIR override the header
installation directory, they should be used instead of
${CMAKE_INSTALL_PREFIX}/include in fmt-targets.cmake and fmt.pc.

* Put headers into FMT_INC_DIR/fmt rather than directly into FMT_INC_DIR

This makes FMT_INC_DIR an alias for CMAKE_INSTALL_INCLUDEDIR and
simplifies generation of pkgconfig and cmake configs.

* Do not split target_include_directories
2020-05-28 08:17:34 -07:00
51bf9cfacb Fix Mingw support
If the ``_POSIX_`` flag is set, _fdopen will not be defined by
Mingw headers, which is addressed by this commit.

For what is worth, as opposed to ``fdopen``, ``_pipe`` *will*
actually have the ``_`` prefix when ``_POSIX_`` is set.
2020-05-26 06:39:22 -07:00
1a716caf5d Optimize common case 2020-05-25 19:16:35 -07:00
98d4bbf813 Update README.rst 2020-05-24 06:28:35 -07:00
8c8f74a870 fix zero flag for char types and make zero flag ignored if a precision is specified 2020-05-23 12:46:26 -07:00
bc1b89da26 Temporarily revert parsing changes 2020-05-22 15:39:33 -07:00
a7fb321ac6 Remove a redundant branch 2020-05-22 15:39:33 -07:00
8cadb96506 fix max/min macro (#1697) 2020-05-22 06:38:43 -07:00
297c3b2ed5 Fix an example (thanks Alexey Kuzmenko) 2020-05-20 15:52:19 -07:00
943532fece Make ostream formatter work with compile-time format strings (#1692) 2020-05-20 14:59:57 -07:00
bd8804019b Update README.rst 2020-05-19 19:25:46 -07:00
f230300ac5 Knuth is using fmt library (#1691) 2020-05-19 18:08:32 -07:00
a265e25b79 Optimize small string parsing 2020-05-19 13:44:22 -07:00
2aa2526f64 Optimize small string concatenation 2020-05-19 11:45:09 -07:00
8d78045e7c Move void_t to where it's used 2020-05-18 10:46:25 -07:00
7aafa6bc64 Update analytics 2020-05-18 10:26:22 -07:00
c66aae1652 Adding sentinel support to fmt::join(). (#1689) 2020-05-18 06:31:01 -07:00
6d66de3805 Add c specifier support to integral types (#1652) 2020-05-17 08:44:59 -07:00
6b219a58db fix interaction of space flag and '+' flag, as well as '-' flag and '0' flag (#1687) 2020-05-17 04:27:18 -07:00
eee2023c2a Update signatures 2020-05-15 15:25:02 -07:00
c5ed73aab2 Add fmt::detail::buffer to the docs (#704) 2020-05-15 14:35:55 -07:00
ea1cd9638c Fix apidoc 2020-05-15 10:03:02 -07:00
d3964d7b1e Merge branch 'master' of github.com:fmtlib/fmt 2020-05-15 09:43:38 -07:00
d18c6723a2 Update docs 2020-05-15 09:43:35 -07:00
96c18b26c2 make plus flag for printf not be ignored for char argument (#1683)
* make plus flag for printf not be ignored for char argument

* clarify overwriting of alignment specifiers for printf with char argument
2020-05-15 06:45:51 -07:00
ba25baeb97 Apply doc patch to 6.2.1 2020-05-14 19:11:40 -07:00
981b517ccf nested replacement fields may omit arg_id (#1681)
syntax.html already has examples like `fmt::format("{:.{}f}", 3.14, 1)` using this, 
and https://en.cppreference.com/w/cpp/utility/format/formatter#width_and_precision shows that this is the case for the C++20 std::format

The Format Specification Mini-Language grammar seems to be the only one not showing this; update it to match.
2020-05-13 17:20:05 -07:00
922ea924bf Make dynamic_format_arg_store reusable and add reserve() (#1677)
Implemented #1674: make dynamic_format_arg_store reusable and add
reserve() for better memory menagement.
2020-05-12 11:00:42 -07:00
e0d98923c7 Update version 2020-05-10 18:05:46 -07:00
8069265373 internal -> detail (#1538) 2020-05-10 07:34:30 -07:00
963ee08310 Simplify named arguments 2020-05-09 16:43:31 -07:00
02a6fe59fb Named arguments go brrr 2020-05-09 13:22:38 -07:00
de290f5c4c Ditch internal::arg_map 2020-05-09 12:43:11 -07:00
d0623de510 Bump version 2020-05-09 10:57:04 -07:00
73e335ed38 Make implicit capture explicit for C++20 (#1669) 2020-05-09 10:55:37 -07:00
b4d46e3988 Update changelog 2020-05-09 10:05:16 -07:00
a182f7341e Update changelog 2020-05-09 08:30:31 -07:00
68201831a5 Support named args in dynamic_format_arg_store (#1655). (#1663)
Dynamic arguments storage. Implementation of enhancement from issue
#1170.
2020-05-09 06:25:03 -07:00
7f723fbcb8 Consistently namespace qualify size_t 2020-05-07 15:59:46 -07:00
c06851456d Purge basic_writer 2020-05-07 15:04:48 -07:00
2f05054dd3 Purge basic_writer 2020-05-07 11:35:41 -07:00
f0ce21164c Revert enum change 2020-05-07 07:25:33 -07:00
44639b11fe Fix some warnings (#1667)
* Fix sign-conversion warning

* Add missing "extern template" declarations for non-header-only build

* Use typed enums to fix Wsigned-enum-bitfield warnings

* Consolidate FMT_HEADER_ONLY code
2020-05-07 06:14:07 -07:00
1c86a99e8f Purge basic_writer 2020-05-06 18:46:01 -07:00
8f511fc12f Make copyfmt not throw (#1666) 2020-05-06 17:38:46 -07:00
59fe455f36 Remove compatibility stubs 2020-05-06 07:31:35 -07:00
b0f47a13e6 Separate nonfinite formatting 2020-05-06 07:19:37 -07:00
d6cea50d01 Remove deprecated APIs 2020-05-05 20:03:48 -07:00
40bc7163fb Move FMT_MAYBE_UNUSED to where it's actually used 2020-05-05 19:41:07 -07:00
080e44d0bf Fix inconsistent type detection (#1662) 2020-05-05 19:09:21 -07:00
7e57cace5d Exclude std::abort from compilation when compiling CUDA with Clang (#1661) 2020-05-04 06:21:21 -07:00
7b66e2f219 Inherit arg_formatter_base from basic_writer 2020-05-03 21:05:45 -07:00
bab3f58003 Refactor pointer formatting 2020-05-03 20:33:25 -07:00
9cc7edfddc Move int_writer to the namespace scope 2020-05-03 17:34:48 -07:00
8d9d528bf5 Improve handling of alignment 2020-05-03 10:58:18 -07:00
8efd1a8ef6 Improve handling of alignment 2020-05-03 10:08:57 -07:00
a71bc9c825 Use '0' fill with numeric align for consistency with std::format 2020-05-03 09:52:31 -07:00
60d85d598c Suppress ubsan warning 2020-05-03 08:43:10 -07:00
c3099beb6f Cleanup 2020-05-02 22:00:34 -07:00
cbb4cb8991 Remove undocumented deprecated APIs 2020-05-02 21:34:44 -07:00
b85e9ac38b Simplify vformat_to 2020-05-02 21:34:44 -07:00
e3710ab972 FMT_CONSTEXPR -> constexpr 2020-05-02 21:34:44 -07:00
d59751f0f0 Update date formatting example to use threadsafe localtime 2020-05-02 09:04:31 -07:00
d6abb2fa03 Reduce library size 2020-05-01 17:23:45 -07:00
e9fdea90b5 Update README.rst 2020-05-01 10:40:07 -07:00
44b6584f22 Update README.rst 2020-05-01 10:39:28 -07:00
78f041ab5b build: Fix installation paths
It is not generally true that `CMAKE_INSTALL_<dir>` variables are relative paths:

https://github.com/jtojnar/cmake-snips#concatenating-paths-when-building-pkg-config-files
2020-05-01 10:27:24 -07:00
7ca89bf87a Reduce template bloat in write_int 2020-05-01 07:56:57 -07:00
3c114d091b Fix a shadowing warning (#1658) 2020-05-01 07:00:25 -07:00
e2ef12a8c0 Allow to avoid inclusion of os.cc in fmt target
- Allows to avoid part of #1654
- Not possible to use with MASTER_PROJECT as testing uses it a lot
2020-05-01 06:24:22 -07:00
bca82719ab Pass iterator by value 2020-04-30 21:06:17 -07:00
99da389627 Make write_padded non-members 2020-04-30 16:05:30 -07:00
f19d667943 Bump fuzzer allocation limit 2020-04-30 08:45:50 -07:00
3e69847616 Reduce branching in write_padded 2020-04-30 06:33:45 -07:00
9ac1eebd47 Reduce library size 2020-04-29 17:37:05 -07:00
e2ff910675 Replace FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION with fmt-specific macro (#1650)
Signed-off-by: Asra Ali <asraa@google.com>
2020-04-29 09:12:43 -07:00
f2ed03b919 Fix a warning (#1649) 2020-04-28 06:39:24 -07:00
9dde9f0131 Reduce library size 2020-04-27 20:43:30 -07:00
b1af642d1d Reduce library size 2020-04-27 18:50:49 -07:00
4a617f25c6 Clarify encoding conversion in chrono 2020-04-27 09:57:08 -07:00
6f435f55c8 Improve compile time by using extern template (#1452) 2020-04-26 14:02:15 -07:00
cb475cb884 Clarify why we don't check argument id 2020-04-26 13:38:42 -07:00
1e1ac6e964 Check dynamic width/precision id at compile time (#1614) 2020-04-25 08:36:24 -07:00
e51c449fe6 Revert "Check dynamic widht/precision id at compile time (#1614)"
This reverts commit 7d748a6f82.
2020-04-25 07:43:56 -07:00
0463665ef1 Don't access a C string past precision in printf (#1595) 2020-04-22 17:10:23 -07:00
7d748a6f82 Check dynamic widht/precision id at compile time (#1614) 2020-04-22 14:45:37 -07:00
2b75bd7ce6 Get rid of do_check_format_string 2020-04-22 12:15:29 -07:00
4a1d5931cb Simplify udl_formatter with FMT_STRING 2020-04-22 11:26:05 -07:00
811b0f9054 Enable compile-time error tests 2020-04-22 11:00:20 -07:00
450e8eed97 Fix markup 2020-04-22 09:30:09 -07:00
b8fbcec1be Clarify formatter reuse 2020-04-22 09:15:52 -07:00
56bc86ffac Suppress bogus MSVC analysis warnings 2020-04-22 07:51:25 -07:00
3f79357ef0 Fix a recent regression in handling max packed arguments 2020-04-22 07:15:19 -07:00
8a11148f99 Add Facebook Folly to the list of projects 2020-04-22 06:16:07 -07:00
e371e8b686 Tweak readme 2020-04-22 06:13:36 -07:00
813732fede Improve readme formatting 2020-04-22 06:07:12 -07:00
3670d5b3f6 README: add vectorized.io/redpanda in the list of users 2020-04-22 06:04:09 -07:00
9e2ad7cf68 Add windows terminal to the projects using {fmt} 2020-04-21 15:47:04 -07:00
63479c8519 Use a delegating ctor and add inlines 2020-04-20 19:17:16 -07:00
5944fcad37 Remove remaining wchar_t instantiation 2020-04-19 16:48:15 -07:00
e253b371b2 Don't generate RTTI for allocator 2020-04-19 15:57:48 -07:00
0c86f467bc Fix build on ancient gcc 2020-04-19 09:52:40 -07:00
1929df4bc2 Simplify format_args 2020-04-19 09:21:39 -07:00
a138221813 Always inline arg_data functions 2020-04-19 08:20:00 -07:00
04e0dfd4bd Always inline value ctors 2020-04-19 08:05:02 -07:00
04cde756bc Simplify checks 2020-04-19 07:35:19 -07:00
c9a57b9a81 Fix incorrect assumptions about nul termination 2020-04-18 06:51:52 -07:00
f46f5ecaf0 Reenable constexpr _compile on GCC 9 2020-04-17 06:10:57 -07:00
6e8d7e2776 Don't use constexpr on Intel compiler (#1628) 2020-04-16 07:08:04 -07:00
567ed03f88 Merge arg overloads and cleanup 2020-04-15 08:44:58 -07:00
c3fa333140 Remove warning in core.h with when compiling with gcc and -Wshadow
In file included from build/_deps/fmt-src/include/fmt/format.h:44:0,
                 from src/main.cpp:5:
build/_deps/fmt-src/include/fmt/core.h: In member function ‘const T& fmt::v6::internal::dynamic_arg_list::push(const Arg&)’:
build/_deps/fmt-src/include/fmt/core.h:1256:10: error: declaration of ‘node’ shadows a member of ‘fmt::v6::internal::dynamic_arg_list’ [-Werror=shadow]
     auto node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
          ^~~~
build/_deps/fmt-src/include/fmt/core.h:1236:37: note: shadowed declaration is here
   template <typename = void> struct node {
2020-04-15 07:31:24 -07:00
84898b4626 Remove warning in format.h when compiling with gcc and -Wshadow
build/_deps/fmt-src/include/fmt/format.h: In member function ‘decltype (ctx.out()) fmt::v6::formatter<fmt::v6::bytes>::format(fmt::v6::bytes, FormatContext&)’:
build/_deps/fmt-src/include/fmt/format.h:3251:58: error: declaration of ‘writer’ shadows a global declaration [-Werror=shadow]
     internal::basic_writer<range_type> writer(range_type(ctx.out()));
                                                          ^~~
build/_deps/fmt-src/include/fmt/format.h:2741:53: note: shadowed declaration is here
 using writer FMT_DEPRECATED_ALIAS = internal::writer;
2020-04-15 07:31:24 -07:00
538d83fd08 Cleanup named arguments 2020-04-15 06:28:41 -07:00
8a4630686e Improve handling of named arguments 2020-04-14 11:56:55 -07:00
a9d62d3f35 Add check for CompiledFormat to avoid ambiguous call 2020-04-14 05:59:02 -07:00
fdcf7870a2 Add stack-based named argument storage 2020-04-13 08:03:51 -07:00
5899267c47 Fix a clang-tidy warning 2020-04-12 08:27:39 -07:00
07b4c246ea Fix a typo 2020-04-12 08:18:47 -07:00
e99809f29d Fix ostream support in sprintf (#1631) 2020-04-12 07:53:17 -07:00
3cd5179f32 Fixed clang tidy warning -multiple declarations in a single statement reduces readability 2020-04-12 06:29:09 -07:00
7404e33a73 Fix clang warning about explicit ctor 2020-04-12 06:19:16 -07:00
3aab2171ed Clean up basic_format_args 2020-04-11 08:22:53 -07:00
7645ca0724 Clean up printf 2020-04-11 08:01:00 -07:00
e30d8391e4 Suppress an MSVC warning (#1622) 2020-04-11 07:49:00 -07:00
8cd8ef03eb Simplify warning suppression 2020-04-11 06:17:31 -07:00
bbb6b357c7 Add floating-point L specifier (#1624) 2020-04-10 07:16:20 -07:00
36ea32640f Suppress a bogus MSVC warning 2020-04-10 06:44:07 -07:00
141a00d642 Define FMT_EXTERN_TEMPLATE_API on export 2020-04-09 11:54:55 -07:00
3860edc5d9 Bump version 2020-04-08 14:48:14 -07:00
7d01859ef1 Fix handling of unsigned char strings in printf 2020-04-08 13:05:42 -07:00
63b23e786a Merge branch 'master' of github.com:fmtlib/fmt 2020-04-08 13:03:44 -07:00
4999796c15 Fix the docs 2020-04-08 07:52:36 -07:00
34b3f7b7aa Avoid windows issue with min() max() macros
Including the ``windows.h`` file without defining ``NOMINMAX`` will define the `min()` and `max()` macros which will result in issues compiling any C++ code that uses any variant of `max`, for example `std::numeric_limits<std::streamsize>::max()` and many others.  Although max() isn't used in Fmt anywhere, it is often used in codes that include a format include file so simply upgrading to the current version of lib::fmt will break the windows build which worked prior to the update...
2020-04-07 08:34:34 -07:00
27e3c0fe9b Update signature in the docs 2020-04-06 07:17:41 -07:00
9bdd1596ce Update version 2020-04-05 06:46:41 -07:00
d151562bdd Fix punctuation in changelog 2020-04-04 12:49:56 -07:00
346500e70b Fix gcc version check 2020-04-04 11:23:40 -07:00
a434a8f778 Update changelog 2020-04-04 06:34:23 -07:00
9eb47d951a Fix markup 2020-04-03 08:49:29 -07:00
51c58a56ba Bump version 2020-04-03 08:32:45 -07:00
3fc33f6273 Update changelog 2020-04-03 08:29:02 -07:00
2e32db5b99 Update changelog 2020-04-03 07:42:02 -07:00
c1ce6e01f7 Update changelog 2020-04-02 08:18:42 -07:00
1c3c80dc1f Update changelog 2020-04-02 07:27:58 -07:00
d1d653d895 Implement the L specifier 2020-04-02 06:58:38 -07:00
73c8437485 Follow naming conventions 2020-04-01 09:30:28 -07:00
e588b02b17 Fix posix-mock-test 2020-04-01 08:42:14 -07:00
1a62711d01 Reduce binary size 2020-03-31 08:07:11 -07:00
5b02881582 Merge branch 'master' of github.com:fmtlib/fmt 2020-03-28 09:46:44 -07:00
a133187a8c Update changelog 2020-03-28 09:44:27 -07:00
80ce222ca6 Fix wide print overload (#1609) 2020-03-28 09:44:18 -07:00
770a94edef Use FMT_THROW macro where applicable 2020-03-27 12:17:22 -07:00
2864e8432a Update readme and add compatibility option 2020-03-26 07:18:27 -07:00
21a295c272 Undo comment change 2020-03-25 08:14:31 -07:00
96c68afe69 Fix -Wsign-conversion warnings 2020-03-25 07:46:00 -07:00
664dd88e31 Enable FMT_STRING() use with types other than string literals 2020-03-24 12:56:21 -07:00
69779b4ed6 Fix handling of small precision in general format 2020-03-24 09:01:57 -07:00
01a172c969 Add .vs to .gitignore 2020-03-23 15:01:02 -07:00
08ca40ea91 Detect /utf-8 in MSVC 2020-03-22 08:19:38 -07:00
dd97f4920c Improve exception safety in dynamic_format_arg_store 2020-03-21 08:58:50 -07:00
2951169481 Move FMT_USE_FLOAT and friends to fmt/format.h 2020-03-20 07:55:43 -07:00
d3e668418f Allow disabling floating point support (#1590)
* Allow disabling floating point support

Add FMT_USE_FLOAT, FMT_USE_DOUBLE and FMT_USE_LONG_DOUBLE to allow a
user of the library to configure the float types they want to allow.
This is specially useful in embedded environements where code size is
important.

* Avoid conditional macros to disable float support

* Add is_supported_floating_point constexpr function

* Fix empty-body warning
2020-03-20 06:46:31 -07:00
52d0e1bbe3 Don't use properties when setting FMT_LIB_NAME 2020-03-19 08:35:09 -07:00
5d32ccfc31 Add back missing OUTPUT_NAME in target properties. (#1598) 2020-03-19 07:01:51 -07:00
3cf619de55 Simplify dynamic_format_arg_store 2020-03-17 07:13:46 -07:00
2559983e7a Color formatting fixed for wide strings (fixes issue #1594) (#1596)
* Use std::char_traits::length for ansi_color_escape::begin

-Fixes issue #1594 https://github.com/fmtlib/fmt/issues/1594
2020-03-17 06:24:42 -07:00
026f99178e Simplify dynamic store 2020-03-16 19:10:41 -07:00
9f70fc3e7a Minor tweaks for dynamic_format_arg_store 2020-03-16 07:58:15 -07:00
6012dc9ab4 Dynamic arguments storage. Implementation of enhancement from issue #1170. (#1584) 2020-03-16 07:00:29 -07:00
85050aa2e6 Ability to join elements of std::initializer_list was added 2020-03-15 16:10:00 -07:00
ff486a72a7 Allow leading zeros in precision (#1579) 2020-03-14 11:37:38 -07:00
678341275b Deprecate fmt::char8_t 2020-03-14 10:32:34 -07:00
6f01b6ebb6 Fix a typo in CMake config: STRINGS -> STRING 2020-03-14 09:50:25 -07:00
61c5a51604 Fix handling of empty tuples (#1588) 2020-03-14 07:41:08 -07:00
02bfd8a9a5 Add FMT_HAS_CPP14_ATTRIBUTE / FMT_HAS_CPP17_ATTRIBUTE to test for language-specific attributes.
FMT_DEPRECATED is now defined as FMT_HAS_CPP14_ATTRIBUTE(deprecated), as this attribute was introduced in C++14.

FMT_FALLTHROUGH is now defined as FMT_HAS_CPP17_ATTRIBUTE(fallthrough), as this attribute was introduced in C++17.

FMT_MAYBE_UNUSED is defined as FMT_HAS_CPP17_ATTRIBUTE(maybe_unused), as this attribute was introduced in C++17.

FMT_MAYBE_UNUSED has been applied to fix a couple of -Wunused-member-function warnings from clang.
2020-03-13 09:03:52 -07:00
3c24052cf1 Workaround 'cannot call member function without object' error on gcc 4.9 2020-03-11 17:39:32 -07:00
f72a905eb3 Fix handling of volatile enums 2020-03-11 08:40:57 -07:00
941d5e147a Workaround broken fallthrough attribute in the PGI compiler (#1583) 2020-03-11 07:56:23 -07:00
ee2b828b9a Tweak a comment 2020-03-09 11:27:14 -07:00
5bb8856655 Workaround for broken [[deprecated]] in PGI compiler (#1581)
* Workaround broken [[deprecated]] in PGI compiler
  - similar to Intel and NVCC, add workaround for PGI compiler
2020-03-09 11:25:38 -07:00
1c0c59d4a0 Fix empty debug postfix 2020-03-09 08:34:02 -07:00
b1adaa9881 Remove gcc 4.4 workaround 2020-03-07 14:50:52 -08:00
48e8d0ebef set_doc -> set_verbose 2020-03-07 14:31:39 -08:00
ce00979152 Cleanup CMake config 2020-03-07 08:18:01 -08:00
db4a6cfbf9 is_static_compiled_format -> is_compiled_format 2020-03-06 07:25:34 -08:00
29a1ea795a Fix clang -Wdisabled-macro-expansion warning from FMT_STRING_IMPL.
FMT_STRING_IMPL has an internal helper named FMT_STRING, however FMT_STRING is also the name of the macro that invokes FMT_STRING_IMPL.

Renaming this helper avoids the appearance of a recursive macro.
2020-03-06 07:00:47 -08:00
8a06ca84c7 Fix ambiguous overloads of format & format_to 2020-03-05 12:22:43 -08:00
153f753bde Deprecate undocumented _u suffix 2020-03-04 19:20:19 -08:00
eafd079868 Improve width computation 2020-03-04 17:17:34 -08:00
0c6919ec72 Make FMT_DEBUG_POSTFIX a cache variable (#1566) 2020-03-04 08:37:11 -08:00
197a5c3721 Apply clang-format 2020-03-04 08:37:00 -08:00
68742e1d87 Fix clang -Wsign-conversion warning in grisu_count_digits. (#1573)
grisu_count_digits is only used by grisu_gen_digits, which assigns the unsigned result to a (signed) int.

Although grisu_count_digits always returns a positive integer this keeps its return type in sync with the type its result is assigned to.
2020-03-04 06:48:41 -08:00
1e8493196e Make compile-time checks in format_to handle references 2020-03-01 07:57:34 -08:00
58e6c84f5a Fix simple -Wsign-conversion cases. (#1571)
* Fix -Wsign-conversion in bigint::subtract_aligned.

n is assigned a size_t, and only used for comparisons with j.

j is assigned 0, compared to n (size_t), and passed to basic_memory_buffer::operator[] (size_t).

* Fix -Wsign-conversion in bigint::assign.

num_bigits is initialised to 0, is only ever incremented, and is passed to basic_memory_buffer::operator[] (size_t) and basic_memory_buffer::resize (size_t).
2020-03-01 07:22:15 -08:00
75a4525e5f Move FMT_CLANG_VERSION definition to core.h (#1568)
Previously format.h defined FMT_CLANG_VERSION after including core.h, however core.h tests FMT_CLANG_VERSION when it defines FMT_API.
2020-02-29 17:19:34 -08:00
6ccb2e241b Add FMT_NORETURN to assert_fail prototype. (#1569)
When building with -Werror,-Wmissing-noreturn clang identifies that assert_fail could be declared with the 'noreturn' attribute.
2020-02-29 17:17:55 -08:00
bed134a4aa Tentative fix for default template param in friend error 2020-02-27 15:29:46 -08:00
b2d3a86ec0 Make FMT_ASSERT work in constexpr on clang 4.0.1 2020-02-26 06:26:46 -08:00
13d82e32bd Don't use internal GTest API 2020-02-24 11:32:34 -08:00
2161a73f2b Fix FMT_FORMAT_AS const specifier position (#1554)
The current `FMT_FORMAT_AS` macro will make `formatter<Char *>::format`
have the first argument type `const Char *&` which is incorrect an
should be `Char *const &`.  This pull request fixes that by changing the
first argument type in the macro definition body from `const Type &` to
`Type const &`.
2020-02-23 07:27:22 -08:00
e00997b004 improved use of find (#1560)
* improved use of find

*begin is supposed to be different from '{' when this find is used, so we can avoid checking it.
2020-02-21 14:43:06 -08:00
0415cf2350 add const begin and end overload to buffer (#1553)
* add const begin and end overload to buffer

since there is a const overload for data I think there should also be one for begin and end
2020-02-19 14:59:50 +01:00
3bafd0749b Fix to_string docs 2020-02-15 09:51:35 +01:00
f733882b55 Remove misleading FMT_USE_WINDOWS_H 2020-02-14 14:09:27 +01:00
dc22360c34 Workaround broken UDL templates in GCC < 6.4 2020-02-10 17:08:14 +01:00
1f1b50707c Make formatter override implicit conversion to a C string 2020-02-07 19:24:36 -08:00
24924128e3 Fix a link error in gcc8 (#1548) 2020-02-07 18:34:05 -08:00
c54cd71800 only modify CMAKE_RUNTIME_OUTPUT_DIRECTORY if it is not already set 2020-02-07 07:10:03 -08:00
43e9b29e50 Only use compiler features if available 2020-02-06 15:43:33 -08:00
b55ea58705 string_view::char_type -> value_type (#1539) 2020-02-01 12:27:44 -08:00
4098970db2 Update README.rst 2020-01-31 11:33:51 -08:00
314e15001f Fix symbol visibility on Linux when compiling with -fvisibility=hidden (#1535)
Make FMT_API symbols use the default visibility on non-Windows
platforms. Otherwise, one cannot use the generated fmt library when
compiling globally with -fvisibility=hidden.

Fixes compile errors like:

```
../3rdParty/fmt/include/fmt/core.h:757: error: undefined reference to 'fmt::v6::internal::assert_fail(char const*, int, char const*)'
```

Note that the symbol exists, but is local:

```
$ nm -C libfmtd.so.6.1.3  | grep assert_fail
                 U __assert_fail
0000000000233ffa t fmt::v6::internal::assert_fail(char const*, int, char const*)
```

With this patch, the compile error is gone and the symbol is properly
exported:

```
$ nm -a bin/libfmtd.so -C | grep assert_fail
                 U __assert_fail
00000000002366ba T fmt::v6::internal::assert_fail(char const*, int, char const*)
```

Change-Id: I96054e622d9a2ae81907e1b01a1033e629767a91
2020-01-30 06:26:18 -08:00
f499b393d1 Apply coding conventions 2020-01-26 19:48:48 -08:00
6c30f41443 Configure fmt.pc library name correctly.
Simplify getting library name.

Add FMT_DEBUG_SUFFIX variable.
2020-01-26 19:48:14 -08:00
1acb73f970 Fix formatting std::chrono::duration types to wide strings (#1533)
* Fix formatting chrono durations to wide strings

* Make format buffers const correct

* Add FormatWide chrono test case

* Fix incorrect wide encoding of 'µs'
I think might be a source file encoding issue, so I used \u00B5 instead.

* Update FormatWide test to use proper encoding of µs

* Revert changes to format_localized's parameters

* Use different overload of `std::time_put<T>::put` to avoid needing a format string

* Use utf8_to_utf16 instead of having redundant overloads of get_units

* Revert some minor changes

* Remove FMT_CONSTEXPR from expression

This should hopefully fix compilation on VS <2019

* Make suggested changes from code review

* Run clang-format on chrono.h

* Make sure unit isn't null before constructing a string_view from it
2020-01-23 18:48:36 -08:00
09a13244c8 Disallow passing non-string-literals to FMT_STRING 2020-01-22 21:05:46 -08:00
419db8baa1 Fix length computation of constexpr C strings 2020-01-22 18:25:07 -08:00
9fc4161f5e fix interal compiler error when building with mingw 2020-01-22 18:14:46 -08:00
25d6916b3a Fix so can work without locale defined
If `FMT_STATIC_THOUSANDS_SEPARATOR` defined, then locale is not included or defined, so this call will be unresolved.  I think this is the correct fix based on the code in `format-inl.h` and `format.h`
2020-01-22 07:26:03 -08:00
0b2eb6501c Add locale example 2020-01-20 08:42:16 -08:00
fd1cabe464 Workaround a bogus MSVC warning 2020-01-20 06:56:22 -08:00
a844d7ab81 Add namespaces 2020-01-19 19:20:48 -08:00
47d3968092 Add more examples 2020-01-19 19:15:54 -08:00
7800173eb1 Update fill docs 2020-01-19 18:57:32 -08:00
b4218aa0f8 Test invalid fill 2020-01-19 16:52:36 -08:00
8a3a8177d6 Bump version 2020-01-19 15:34:30 -08:00
e5f2f8ce7a Add variable-width fill support (#1109) 2020-01-19 14:49:51 -08:00
75765bfad5 Avoid unnecessary unsigned overflows (#1515) 2020-01-18 08:19:27 -08:00
9bd9738da0 Remove static and simplify names 2020-01-18 07:43:59 -08:00
bd5f903f28 Add a locale example 2020-01-18 07:11:45 -08:00
06e437fd98 Move docs to the proper place 2020-01-18 06:59:21 -08:00
1bd4f54fa6 update format 2020-01-17 11:07:55 -08:00
11cc2903e4 re-fix url link 2020-01-17 11:07:55 -08:00
b124e3e8e7 fix url link 2020-01-17 11:07:55 -08:00
ffd5f3469f Correct display format 2020-01-17 11:07:55 -08:00
0f0e5ddf5f Add vcpkg installation instructions 2020-01-17 11:07:55 -08:00
1f110702a1 Remove redundant braces 2020-01-15 15:07:30 -08:00
4ccbe4b5f2 Avoid namespace clash for fmt
## Problem

In the case of an existing `fmt` namespace (in my project this looks like `Project::fmt`) it is possible to get a namespace clash in debug builds (MSVC 2017)

## Proposed Solution

When referencing `fmt` internally, be explicit that it is relative to the global namespace using `::fmt`
2020-01-15 11:23:24 -08:00
40638a75b3 Use C++11 compatible std::is_same operations
The `operator()` member function of `std::is_same` was added in C++14.  For C++11, the `::value` needs to be used instead.
2020-01-15 11:20:47 -08:00
c8dd9cc99d Use type_identity to block unnecessary template argument deduction (thanks Tim Song) 2020-01-15 10:27:50 -08:00
4bbe57cebf Work-around for nvcc
The nvcc compiler (at least up to 9.2) defines `__SIZEOF_INT128__`, but doesn't support 128-bit integers on device code:
```
error: "fmt::v6::format_arg_store<fmt::v6::basic_format_context<std::back_insert_iterator<fmt::v6::internal::buffer<char>>, char>, const char *, int, const char *>" contains a 128-bit integer, which is not supported in device code
```
2020-01-15 07:31:58 -08:00
55b6130055 Use C++11-compatible operations
The `std::is_base_of<T,U>()` and `std::is_reference<T>()` member functions were added in C++14.  To maintain C++11 compatibility, use the `::value` instead.

Current code fails on intel-17 and other compilers if using strict C++11
2020-01-15 07:23:39 -08:00
ae3ea156ea Fix for older versions of intel compiler
The intel-17 and intel-18 compilers seem to require that `u` be `const`:
```
/src/fmt/format.h(226): warning #437: reference to local variable of enclosing function is not allowed
        char data[sizeof(u)];
```
If `u` is declared as `const auto u =1u` instead of just `auto u=1u`, the file compiles with no warnings.
2020-01-14 17:56:06 -08:00
77165fdf85 Use FMT_NOEXCEPT instead of noexcept directly
Otherwise breaks on compilers without noexcept support
2020-01-14 09:31:31 -08:00
65ac626c58 Improve join docs 2020-01-12 07:26:16 -08:00
cd0b3f9695 check if _SECURE_SCL is defined not equal to 0 2020-01-09 15:01:48 -08:00
cef1e4354b Optimize grisu_gen_digits 2020-01-07 16:11:18 -10:00
0201c8db21 Restructure float_format 2020-01-07 14:41:30 -10:00
9e3f3e8cff Fix handling of output iterators in format_to_n (#1506) 2020-01-05 09:59:01 -10:00
aa07c57654 Move vprint_mojibake to the internal namespace 2020-01-04 08:31:18 -10:00
a73d89e9c7 Catch invalid uses of fmt::arg 2020-01-04 07:11:35 -10:00
cb8e7caf7c Convert 'char8_t' character sequences to 'char' sequences
Otherwise, Google Test will insist on inserting 'char8_t' NTBS into 'char' streams, but basic_ostream<char>::operator<< overloads taking 'char8_t' arguments are defined as deleted by P1423.
Handling individual 'char8_t's is done inline.

This fixes the compilation errors seen in C++20 mode beginning with VS2019 Update 2.

Signed-off-by: Daniela Engert <dani@ngrt.de>
2020-01-04 07:01:48 -10:00
b3fd0005dd Suppress a bogus -Wdouble-promotion warning 2020-01-03 06:57:14 -10:00
7b478f9dec Simplify example 2020-01-02 07:31:45 -10:00
c85efef312 More showpoint fixes and tests (#1498) 2019-12-30 13:08:35 -10:00
455a7c0787 Clarify lifetime of basic_format_args 2019-12-30 08:51:47 -10:00
674c326d7c Update syntax.rst 2019-12-29 07:25:34 -10:00
061a9897fe Update syntax.rst 2019-12-26 16:49:40 -10:00
d2d1c9c560 warning C4267: 'argument': conversion from 'size_t' to 'DWORD', possible loss of data 2019-12-26 08:07:24 -08:00
b6e19e5953 Update apidoc 2019-12-24 12:08:37 -08:00
f219dcd59b Add fmt::bytes 2019-12-24 10:45:15 -08:00
dea7fde8b7 Deprecate u8string_view 2019-12-24 09:44:57 -08:00
5390e29d42 Enable mojibake 2019-12-24 08:42:29 -08:00
9f6434dcde Improve UTF-8 handling on Windows 2019-12-23 16:19:11 -08:00
dac9a7f99d Improve UTF-8 handling on Windows 2019-12-22 12:05:28 -08:00
3ca9533f38 Flatten forward 2019-12-22 08:23:54 -08:00
7eec036d9a Improve UTF-8 support 2019-12-21 19:53:52 -08:00
e6b37b4aff Handle block boundaries in utf8_to_utf16 2019-12-21 16:33:34 -08:00
8cf4c52068 Apply clang-format 2019-12-21 13:10:45 -08:00
74532c23a3 Make type a scoped enum 2019-12-21 12:22:17 -08:00
b308159be5 Make round_direction a scoped enum 2019-12-21 09:24:42 -08:00
162995fedd Add os.h to docs 2019-12-18 14:17:49 -08:00
8b41362a0a Add trailing decimal point if # is specified (#1476) 2019-12-18 12:41:56 -08:00
1b1c70108a trailing_zeros -> showpoint 2019-12-18 12:12:09 -08:00
d7e72a09e0 Simplify FMT_STRING_IMPL 2019-12-18 11:50:47 -08:00
2201890d7a Apply clang-format and update inclusion guards 2019-12-18 11:17:36 -08:00
6100ed4bb3 Eliminate NVCC NVidia compiler emits unreachable code warnings
Similar to the MSC Compiler, the NVidia NVCC compiler also
emits unreachable code warnings when there is a return
statement following an exception.  These changes eliminate
those warnings.
2019-12-18 10:39:40 -08:00
1afe201ae8 Handle block boundaries in utf8_to_utf16 2019-12-18 10:35:51 -08:00
cd2b99032f Chore(readme): use https (#1481) 2019-12-17 06:48:27 -08:00
9acf89fef6 Mitigate MSVC issue with min/max macros (#1480) 2019-12-16 08:24:00 -08:00
9ea42fb26e Rename posix-test to os-test 2019-12-15 16:43:40 -08:00
da2569827e posix.cc -> os.cc 2019-12-15 12:36:15 -08:00
35959a31d7 Move OS-specific APIs to a separate header 2019-12-15 11:46:45 -08:00
ec2463c905 Implement utf8_to_utf16 using utf8_decode 2019-12-15 09:35:26 -08:00
0012917f69 Add a UTF-8 decoder 2019-12-15 07:28:19 -08:00
9e450911fa Give an error on precision overflow 2019-12-14 07:45:27 -08:00
068d20bc31 Avoid shadowing warnings in FMT_STRING 2019-12-14 07:00:08 -08:00
a99fbe67b9 Apply a typo fix retroactively 2019-12-14 06:50:53 -08:00
adbed11ed4 Fix a typo 2019-12-13 15:49:40 -08:00
8ab1c5c6e8 Squelch MSVC warning exporting subclasses of runtime_error (fix for PR #1433) (#1470)
* Squelch MSVC warning exporting subclasses of runtime_error

When compiling {fmt} as a DLL, MSVC complains that we are exporting
classes that inherit from "std::runtime_error", which we are not
exporting.

In this case, it's not really a problem because that symbol is already
exported via the C++ stdlib. So we just add a pragma to silence the
warning.

* Fix compilation with MinGW

Commit 3bc28fcc6b ("Squelch MSVC warning exporting subclasses of
runtime_error", 2019-11-29) silenced a MSVC warning under. The MinGW
compiler also defines _WIN32, but does not support the "warning" pragma.

Introduce a helper macro to squelch the MSVC warning only when using the
Microsoft compiler.

Signed-off-by: Beat Bolli <dev@drbeat.li>

* Fix compilation with VS2015 (#1450)

VS2015 does not support the __pragma(...) syntax in the midst of a
class declaration, so move it to just before the declaration.
2019-12-13 12:16:36 -08:00
a770009fcc Improve error reporting 2019-12-13 11:34:03 -08:00
598e6042d1 warning C4468: 'fallthrough': attribute must be followed by a case label or a default label 2019-12-12 06:25:33 -08:00
e09814dc93 Merge branch 'master' of github.com:fmtlib/fmt 2019-12-11 15:44:44 -08:00
b272fb3605 Extend FMT_FALLTHROUGH compatibily to gcc and clang pre-C++17 (#1469) 2019-12-11 14:28:20 -08:00
f94b7364b9 Update version 2019-12-11 06:16:42 -08:00
7abec071b5 Update changelog 2019-12-11 06:15:06 -08:00
b7eb8c8921 Prepare for the next release 2019-12-10 21:50:14 -08:00
ae7c50185d Reintroduce sprintf_format for ABI compatibility 2019-12-10 20:44:08 -08:00
9f2e7edaeb Fix handling of types convertible to std::string_view 2019-12-09 13:25:08 -08:00
fd52de0c6b Add FMT_CUDA_TEST CMake option to enable cuda-test 2019-12-09 07:30:34 -08:00
f675cb887e Remove redundant cast 2019-12-08 18:01:59 -08:00
73a16b827f Fix handling of int128_t in format-impl-test (#1461) 2019-12-08 17:07:20 -08:00
72879db40e Clean-up sign-conversion warnings in public headers 2019-12-08 16:07:55 -08:00
d3aa0c3a28 Clean-up sign-conversion warnings in test code 2019-12-08 16:07:43 -08:00
31de9a1b80 Revert "Clean-up sign-conversion warnings in test code"
This reverts commit 227bfe62dd.
2019-12-08 15:47:24 -08:00
227bfe62dd Clean-up sign-conversion warnings in test code 2019-12-08 15:21:38 -08:00
95dfdc6cc4 Update README.rst 2019-12-07 10:12:56 -08:00
5916ff63c4 Update README.rst 2019-12-07 10:12:15 -08:00
1ab80aa92c Fix handling of types with custom formatters that are convertible to std::string_view 2019-12-06 11:40:21 -08:00
4f4d876616 Remove '%' from the docs 2019-12-06 07:06:19 -08:00
f443bd3baf Ditch decimal_formatter (#1363) 2019-12-05 19:07:45 -08:00
1219b65f21 Relax fallthrough attribute detection 2019-12-05 10:40:15 -08:00
139 changed files with 56649 additions and 52342 deletions

8
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: "github-actions" # Necessary to update action hashs
directory: "/"
schedule:
interval: "weekly"
# Allow up to 3 opened pull requests for github-actions versions
open-pull-requests-limit: 3

6
.github/issue_template.md vendored Normal file
View File

@ -0,0 +1,6 @@
<!--
Please make sure that the problem reproduces on the current master before
submitting an issue.
If possible please provide a repro on Compiler Explorer:
https://godbolt.org/z/fxccbh53W.
-->

View File

@ -1,6 +1,7 @@
<!-- Please read the contribution guidelines before submitting a pull request. -->
<!-- By submitting this pull request, you agree that your contributions are licensed under the {fmt} license,
and agree to future changes to the licensing. -->
<!-- If you're a first-time contributor, please acknowledge it by leaving the statement below. -->
I agree that my contributions are licensed under the {fmt} license, and agree to future changes to the licensing.
<!--
Please read the contribution guidelines before submitting a pull request:
https://github.com/fmtlib/fmt/blob/master/CONTRIBUTING.md.
By submitting this pull request, you agree to license your contribution(s)
under the terms outlined in LICENSE.rst and represent that you have the right
to do so.
-->

30
.github/workflows/cifuzz.yml vendored Normal file
View File

@ -0,0 +1,30 @@
name: CIFuzz
on: [pull_request]
permissions:
contents: read
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'fmt'
dry-run: false
language: c++
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'fmt'
fuzz-seconds: 300
dry-run: false
language: c++
- name: Upload Crash
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts

35
.github/workflows/doc.yml vendored Normal file
View File

@ -0,0 +1,35 @@
name: doc
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
# Use Ubuntu 20.04 because doxygen 1.8.13 from Ubuntu 18.04 is broken.
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- name: Add ubuntu mirrors
run: |
# Github Actions caching proxy is at times unreliable
# see https://github.com/actions/runner-images/issues/7048
printf 'http://azure.archive.ubuntu.com/ubuntu\tpriority:1\n' | sudo tee /etc/apt/mirrors.txt
curl http://mirrors.ubuntu.com/mirrors.txt | sudo tee --append /etc/apt/mirrors.txt
sudo sed -i 's~http://azure.archive.ubuntu.com/ubuntu/~mirror+file:/etc/apt/mirrors.txt~' /etc/apt/sources.list
- name: Create Build Environment
run: |
sudo apt update
sudo apt install doxygen python3-virtualenv
sudo npm install -g less clean-css
cmake -E make_directory ${{runner.workspace}}/build
- name: Build
working-directory: ${{runner.workspace}}/build
env:
KEY: ${{secrets.KEY}}
run: $GITHUB_WORKSPACE/support/build-docs.py

111
.github/workflows/linux.yml vendored Normal file
View File

@ -0,0 +1,111 @@
name: linux
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-20.04
strategy:
matrix:
cxx: [g++-4.8, g++-10, clang++-9]
build_type: [Debug, Release]
std: [11]
include:
- cxx: g++-4.8
install: sudo apt install g++-4.8
- cxx: g++-8
build_type: Debug
std: 14
install: sudo apt install g++-8
- cxx: g++-8
build_type: Debug
std: 17
install: sudo apt install g++-8
- cxx: g++-9
build_type: Debug
std: 17
- cxx: g++-10
build_type: Debug
std: 17
- cxx: g++-11
build_type: Debug
std: 20
install: sudo apt install g++-11
- cxx: clang++-8
build_type: Debug
std: 17
cxxflags: -stdlib=libc++
install: sudo apt install clang-8 libc++-8-dev libc++abi-8-dev
- cxx: clang++-9
install: sudo apt install clang-9
- cxx: clang++-9
build_type: Debug
fuzz: -DFMT_FUZZ=ON -DFMT_FUZZ_LINKMAIN=ON
std: 17
install: sudo apt install clang-9
- cxx: clang++-11
build_type: Debug
std: 20
- cxx: clang++-11
build_type: Debug
std: 20
cxxflags: -stdlib=libc++
install: sudo apt install libc++-11-dev libc++abi-11-dev
- shared: -DBUILD_SHARED_LIBS=ON
steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- name: Set timezone
run: sudo timedatectl set-timezone 'Asia/Yekaterinburg'
- name: Add repositories for older GCC
run: |
# Below two repos provide GCC 4.8, 5.5 and 6.4
sudo apt-add-repository 'deb http://azure.archive.ubuntu.com/ubuntu/ bionic main'
sudo apt-add-repository 'deb http://azure.archive.ubuntu.com/ubuntu/ bionic universe'
# Below two repos additionally update GCC 6 to 6.5
# sudo apt-add-repository 'deb http://azure.archive.ubuntu.com/ubuntu/ bionic-updates main'
# sudo apt-add-repository 'deb http://azure.archive.ubuntu.com/ubuntu/ bionic-updates universe'
if: ${{ matrix.cxx == 'g++-4.8' }}
- name: Add ubuntu mirrors
run: |
# Github Actions caching proxy is at times unreliable
# see https://github.com/actions/runner-images/issues/7048
printf 'http://azure.archive.ubuntu.com/ubuntu\tpriority:1\n' | sudo tee /etc/apt/mirrors.txt
curl http://mirrors.ubuntu.com/mirrors.txt | sudo tee --append /etc/apt/mirrors.txt
sudo sed -i 's~http://azure.archive.ubuntu.com/ubuntu/~mirror+file:/etc/apt/mirrors.txt~' /etc/apt/sources.list
- name: Create Build Environment
run: |
sudo apt update
${{matrix.install}}
sudo apt install locales-all
cmake -E make_directory ${{runner.workspace}}/build
- name: Configure
working-directory: ${{runner.workspace}}/build
env:
CXX: ${{matrix.cxx}}
CXXFLAGS: ${{matrix.cxxflags}}
run: |
cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ${{matrix.fuzz}} ${{matrix.shared}} \
-DCMAKE_CXX_STANDARD=${{matrix.std}} -DFMT_DOC=OFF \
-DCMAKE_CXX_VISIBILITY_PRESET=hidden -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON \
-DFMT_PEDANTIC=ON -DFMT_WERROR=ON $GITHUB_WORKSPACE
- name: Build
working-directory: ${{runner.workspace}}/build
run: |
threads=`nproc`
cmake --build . --config ${{matrix.build_type}} --parallel $threads
- name: Test
working-directory: ${{runner.workspace}}/build
run: ctest -C ${{matrix.build_type}}
env:
CTEST_OUTPUT_ON_FAILURE: True

55
.github/workflows/macos.yml vendored Normal file
View File

@ -0,0 +1,55 @@
name: macos
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
strategy:
matrix:
os: [macos-11, macos-13]
build_type: [Debug, Release]
std: [11, 17, 20]
exclude:
- { os: macos-11, std: 20 }
- { os: macos-13, std: 11 }
- { os: macos-13, std: 17 }
include:
- shared: -DBUILD_SHARED_LIBS=ON
runs-on: '${{ matrix.os }}'
steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- name: Set timezone
run: sudo systemsetup -settimezone 'Asia/Yekaterinburg'
- name: Select Xcode 14.3 (macOS 13)
run: sudo xcode-select -s "/Applications/Xcode_14.3.app"
if: ${{ matrix.os == 'macos-13' }}
- name: Create Build Environment
run: cmake -E make_directory ${{runner.workspace}}/build
- name: Configure
working-directory: ${{runner.workspace}}/build
run: |
cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ${{matrix.shared}} \
-DCMAKE_CXX_STANDARD=${{matrix.std}} \
-DCMAKE_CXX_VISIBILITY_PRESET=hidden -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON \
-DFMT_DOC=OFF -DFMT_PEDANTIC=ON -DFMT_WERROR=ON $GITHUB_WORKSPACE
- name: Build
working-directory: ${{runner.workspace}}/build
run: |
threads=`sysctl -n hw.logicalcpu`
cmake --build . --config ${{matrix.build_type}} --parallel $threads
- name: Test
working-directory: ${{runner.workspace}}/build
run: ctest -C ${{matrix.build_type}}
env:
CTEST_OUTPUT_ON_FAILURE: True

100
.github/workflows/windows.yml vendored Normal file
View File

@ -0,0 +1,100 @@
name: windows
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ${{matrix.os}}
strategy:
matrix:
# windows-2019 has MSVC 2019 installed;
# windows-2022 has MSVC 2022 installed:
# https://github.com/actions/virtual-environments.
os: [windows-2019]
platform: [Win32, x64]
toolset: [v140, v141, v142]
standard: [14, 17, 20]
shared: ["", -DBUILD_SHARED_LIBS=ON]
build_type: [Debug, Release]
exclude:
- { toolset: v140, standard: 17 }
- { toolset: v140, standard: 20 }
- { toolset: v141, standard: 14 }
- { toolset: v141, standard: 20 }
- { toolset: v142, standard: 14 }
- { platform: Win32, toolset: v140 }
- { platform: Win32, toolset: v141 }
- { platform: Win32, standard: 14 }
- { platform: Win32, standard: 20 }
- { platform: x64, toolset: v140, shared: -DBUILD_SHARED_LIBS=ON }
- { platform: x64, toolset: v141, shared: -DBUILD_SHARED_LIBS=ON }
- { platform: x64, standard: 14, shared: -DBUILD_SHARED_LIBS=ON }
- { platform: x64, standard: 20, shared: -DBUILD_SHARED_LIBS=ON }
include:
- os: windows-2022
platform: x64
toolset: v143
build_type: Debug
standard: 20
steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- name: Set timezone
run: tzutil /s "Ekaterinburg Standard Time"
- name: Create Build Environment
run: cmake -E make_directory ${{runner.workspace}}/build
- name: Configure
# Use a bash shell for $GITHUB_WORKSPACE.
shell: bash
working-directory: ${{runner.workspace}}/build
run: |
cmake -A ${{matrix.platform}} -T ${{matrix.toolset}} \
-DCMAKE_CXX_STANDARD=${{matrix.standard}} \
${{matrix.shared}} -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
$GITHUB_WORKSPACE
- name: Build
working-directory: ${{runner.workspace}}/build
run: |
$threads = (Get-CimInstance Win32_ComputerSystem).NumberOfLogicalProcessors
cmake --build . --config ${{matrix.build_type}} --parallel $threads
- name: Test
working-directory: ${{runner.workspace}}/build
run: ctest -C ${{matrix.build_type}} -V
env:
CTEST_OUTPUT_ON_FAILURE: True
mingw:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
strategy:
matrix:
sys: [ mingw64, ucrt64 ]
steps:
- name: Set timezone
run: tzutil /s "Ekaterinburg Standard Time"
shell: cmd
- uses: msys2/setup-msys2@7efe20baefed56359985e327d329042cde2434ff # v2
with:
release: false
msystem: ${{matrix.sys}}
pacboy: cc:p cmake:p ninja:p lld:p
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- name: Configure
run: cmake -B ../build -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Debug
env: { LDFLAGS: -fuse-ld=lld }
- name: Build
run: cmake --build ../build
- name: Test
run: ctest -j `nproc` --test-dir ../build
env:
CTEST_OUTPUT_ON_FAILURE: True

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
.vscode/
.vs/
*.iml
.idea/
@ -8,12 +9,14 @@ gradle/
gradlew*
local.properties
build/
support/.cxx
bin/
/_CPack_Packages
/CMakeScripts
/doc/doxyxml
/doc/html
/doc/node_modules
virtualenv
/Testing
/install_manifest.txt

View File

@ -1,101 +0,0 @@
language: cpp
dist: trusty
sudo: false
os: linux
git:
depth: 1
env:
global:
- secure: |-
a1eovNn4uol9won7ghr67eD3/59oeESN+G9bWE+ecI1V6yRseG9whniGhIpC/YfMW/Qz5I
5sxSmFjaw9bxCISNwUIrL1O5x2AmRYTnFcXk4dFsUvlZg+WeF/aKyBYCNRM8C2ndbBmtAO
o1F2EwFbiso0EmtzhAPs19ujiVxkLn4=
matrix:
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
# g++ 8 on Linux with C++17
- env: COMPILER=g++-8 BUILD=Debug STANDARD=17
compiler: gcc
addons:
apt:
update: true
sources:
- ubuntu-toolchain-r-test
packages:
- g++-8
- env: COMPILER=g++-8 BUILD=Release STANDARD=17
compiler: gcc
addons:
apt:
update: true
sources:
- ubuntu-toolchain-r-test
packages:
- g++-8
# 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 (builds the fuzzers as well)
- env: COMPILER=clang++-6.0 BUILD=Debug STANDARD=14 ENABLE_FUZZING=1
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
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,49 +1,171 @@
cmake_minimum_required(VERSION 3.1.0)
cmake_minimum_required(VERSION 3.8...3.26)
# Use newer policies if available, up to most recent tested version of CMake.
if(${CMAKE_VERSION} VERSION_LESS 3.11)
# Fallback for using newer policies on CMake <3.12.
if(${CMAKE_VERSION} VERSION_LESS 3.12)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.11)
endif()
# Determine if fmt is built as a subproject (using add_subdirectory)
# or if it is the master project.
set(MASTER_PROJECT OFF)
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(MASTER_PROJECT ON)
message(STATUS "CMake version: ${CMAKE_VERSION}")
if (NOT DEFINED FMT_MASTER_PROJECT)
set(FMT_MASTER_PROJECT OFF)
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(FMT_MASTER_PROJECT ON)
message(STATUS "CMake version: ${CMAKE_VERSION}")
endif ()
endif ()
# Joins arguments and places the results in ${result_var}.
function(join result_var)
set(result )
set(result "")
foreach (arg ${ARGN})
set(result "${result}${arg}")
endforeach ()
set(${result_var} "${result}" PARENT_SCOPE)
endfunction()
# DEPRECATED! Should be merged into add_module_library.
function(enable_module target)
if (MSVC)
set(BMI ${CMAKE_CURRENT_BINARY_DIR}/${target}.ifc)
target_compile_options(${target}
PRIVATE /interface /ifcOutput ${BMI}
INTERFACE /reference fmt=${BMI})
set_target_properties(${target} PROPERTIES ADDITIONAL_CLEAN_FILES ${BMI})
set_source_files_properties(${BMI} PROPERTIES GENERATED ON)
endif ()
endfunction()
# Adds a library compiled with C++20 module support.
# `enabled` is a CMake variables that specifies if modules are enabled.
# If modules are disabled `add_module_library` falls back to creating a
# non-modular library.
#
# Usage:
# add_module_library(<name> [sources...] FALLBACK [sources...] [IF enabled])
function(add_module_library name)
cmake_parse_arguments(AML "" "IF" "FALLBACK" ${ARGN})
set(sources ${AML_UNPARSED_ARGUMENTS})
add_library(${name})
set_target_properties(${name} PROPERTIES LINKER_LANGUAGE CXX)
if (NOT ${${AML_IF}})
# Create a non-modular library.
target_sources(${name} PRIVATE ${AML_FALLBACK})
return()
endif ()
# Modules require C++20.
target_compile_features(${name} PUBLIC cxx_std_20)
if (CMAKE_COMPILER_IS_GNUCXX)
target_compile_options(${name} PUBLIC -fmodules-ts)
endif ()
# `std` is affected by CMake options and may be higher than C++20.
get_target_property(std ${name} CXX_STANDARD)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(pcms)
foreach (src ${sources})
get_filename_component(pcm ${src} NAME_WE)
set(pcm ${pcm}.pcm)
# Propagate -fmodule-file=*.pcm to targets that link with this library.
target_compile_options(
${name} PUBLIC -fmodule-file=${CMAKE_CURRENT_BINARY_DIR}/${pcm})
# Use an absolute path to prevent target_link_libraries prepending -l
# to it.
set(pcms ${pcms} ${CMAKE_CURRENT_BINARY_DIR}/${pcm})
add_custom_command(
OUTPUT ${pcm}
COMMAND ${CMAKE_CXX_COMPILER}
-std=c++${std} -x c++-module --precompile -c
-o ${pcm} ${CMAKE_CURRENT_SOURCE_DIR}/${src}
"-I$<JOIN:$<TARGET_PROPERTY:${name},INCLUDE_DIRECTORIES>,;-I>"
# Required by the -I generator expression above.
COMMAND_EXPAND_LISTS
DEPENDS ${src})
endforeach ()
# Add .pcm files as sources to make sure they are built before the library.
set(sources)
foreach (pcm ${pcms})
get_filename_component(pcm_we ${pcm} NAME_WE)
set(obj ${pcm_we}.o)
# Use an absolute path to prevent target_link_libraries prepending -l.
set(sources ${sources} ${pcm} ${CMAKE_CURRENT_BINARY_DIR}/${obj})
add_custom_command(
OUTPUT ${obj}
COMMAND ${CMAKE_CXX_COMPILER} $<TARGET_PROPERTY:${name},COMPILE_OPTIONS>
-c -o ${obj} ${pcm}
DEPENDS ${pcm})
endforeach ()
endif ()
target_sources(${name} PRIVATE ${sources})
endfunction()
include(CMakeParseArguments)
# Sets a cache variable with a docstring joined from multiple arguments:
# set(<variable> <value>... CACHE <type> <docstring>...)
# This allows splitting a long docstring for readability.
function(set_verbose)
# cmake_parse_arguments is broken in CMake 3.4 (cannot parse CACHE) so use
# list instead.
list(GET ARGN 0 var)
list(REMOVE_AT ARGN 0)
list(GET ARGN 0 val)
list(REMOVE_AT ARGN 0)
list(REMOVE_AT ARGN 0)
list(GET ARGN 0 type)
list(REMOVE_AT ARGN 0)
join(doc ${ARGN})
set(${var} ${val} CACHE ${type} ${doc})
endfunction()
# Set the default CMAKE_BUILD_TYPE to Release.
# This should be done before the project command since the latter can set
# CMAKE_BUILD_TYPE itself (it does so for nmake).
if (MASTER_PROJECT AND NOT CMAKE_BUILD_TYPE)
join(doc "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or "
"CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
set(CMAKE_BUILD_TYPE Release CACHE STRING ${doc})
if (FMT_MASTER_PROJECT AND NOT CMAKE_BUILD_TYPE)
set_verbose(CMAKE_BUILD_TYPE Release CACHE STRING
"Choose the type of build, options are: None(CMAKE_CXX_FLAGS or "
"CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
endif ()
project(FMT CXX)
include(GNUInstallDirs)
set_verbose(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE STRING
"Installation directory for include files, a relative path that "
"will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute path.")
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_DOC "Generate the doc target." ${FMT_MASTER_PROJECT})
option(FMT_INSTALL "Generate the install target." ON)
option(FMT_TEST "Generate the test target." ${FMT_MASTER_PROJECT})
option(FMT_FUZZ "Generate the fuzz target." OFF)
option(FMT_CUDA_TEST "Generate the cuda-test target." OFF)
option(FMT_OS "Include core requiring OS (Windows/Posix) " ON)
option(FMT_MODULE "Build a module instead of a traditional library." OFF)
option(FMT_SYSTEM_HEADERS "Expose headers with marking them as system." OFF)
project(FMT CXX)
if (FMT_TEST AND FMT_MODULE)
# The tests require {fmt} to be compiled as traditional library
message(STATUS "Testing is incompatible with build mode 'module'.")
endif ()
set(FMT_SYSTEM_HEADERS_ATTRIBUTE "")
if (FMT_SYSTEM_HEADERS)
set(FMT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
endif ()
if(CMAKE_SYSTEM_NAME STREQUAL "MSDOS")
set(FMT_TEST OFF)
message(STATUS "MSDOS is incompatible with gtest")
endif()
# Get version from core.h
file(READ include/fmt/core.h core_h)
@ -60,34 +182,46 @@ message(STATUS "Version: ${FMT_VERSION}")
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
endif ()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${CMAKE_CURRENT_SOURCE_DIR}/support/cmake")
include(cxx14)
include(CheckCXXCompilerFlag)
include(JoinPaths)
set(FMT_REQUIRED_FEATURES cxx_auto_type cxx_variadic_templates)
if (FMT_MASTER_PROJECT AND NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET)
set_verbose(CMAKE_CXX_VISIBILITY_PRESET hidden CACHE STRING
"Preset for the export of private symbols")
set_property(CACHE CMAKE_CXX_VISIBILITY_PRESET PROPERTY STRINGS
hidden default)
endif ()
if (FMT_MASTER_PROJECT AND NOT DEFINED CMAKE_VISIBILITY_INLINES_HIDDEN)
set_verbose(CMAKE_VISIBILITY_INLINES_HIDDEN ON CACHE BOOL
"Whether to add a compile flag to hide symbols of inline functions")
endif ()
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(PEDANTIC_COMPILE_FLAGS -pedantic-errors -Wall -Wextra -pedantic
-Wold-style-cast -Wundef
-Wredundant-decls -Wwrite-strings -Wpointer-arith
-Wcast-qual -Wformat=2 -Wmissing-include-dirs
-Wcast-align -Wnon-virtual-dtor
-Wcast-align
-Wctor-dtor-privacy -Wdisabled-optimization
-Winvalid-pch -Woverloaded-virtual
-Wconversion -Wswitch-enum
-Wno-ctor-dtor-privacy -Wno-format-nonliteral -Wno-shadow)
-Wconversion -Wundef
-Wno-ctor-dtor-privacy -Wno-format-nonliteral)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnoexcept
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
-Wno-dangling-else -Wno-unused-local-typedefs)
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)
-Wvector-operation-performance -Wsized-deallocation -Wshadow)
endif ()
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wshift-overflow=2
@ -97,8 +231,9 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
endif ()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -pedantic -Wconversion
-Wno-sign-conversion -Wdeprecated -Wweak-vtables)
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -pedantic -Wconversion -Wundef
-Wdeprecated -Wweak-vtables -Wshadow
-Wno-gnu-zero-variadic-macro-arguments)
check_cxx_compiler_flag(-Wzero-as-null-pointer-constant HAS_NULLPTR_WARNING)
if (HAS_NULLPTR_WARNING)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
@ -112,7 +247,7 @@ if (MSVC)
set(WERROR_FLAG /WX)
endif ()
if (MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
if (FMT_MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
# If Microsoft SDK is installed create script run-msbuild.bat that
# calls SetEnv.cmd to set up build environment and runs msbuild.
# It is useful when building Visual Studio projects with the SDK
@ -122,24 +257,14 @@ if (MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
set(MSBUILD_SETUP "call \"${WINSDK_SETENV}\"")
endif ()
# Set FrameworkPathOverride to get rid of MSB3644 warnings.
set(netfxpath "C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.0")
join(netfxpath
"C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\"
".NETFramework\\v4.0")
file(WRITE run-msbuild.bat "
${MSBUILD_SETUP}
${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*")
endif ()
set(strtod_l_headers stdlib.h)
if (APPLE)
set(strtod_l_headers ${strtod_l_headers} xlocale.h)
endif ()
include(CheckSymbolExists)
if (WIN32)
check_symbol_exists(_strtod_l "${strtod_l_headers}" HAVE_STRTOD_L)
else ()
check_symbol_exists(strtod_l "${strtod_l_headers}" HAVE_STRTOD_L)
endif ()
function(add_headers VAR)
set(headers ${${VAR}})
foreach (header ${ARGN})
@ -149,15 +274,20 @@ function(add_headers VAR)
endfunction()
# Define the fmt library, its includes and the needed defines.
add_headers(FMT_HEADERS chrono.h color.h compile.h core.h format.h format-inl.h
locale.h ostream.h posix.h printf.h ranges.h)
set(FMT_SOURCES src/format.cc src/posix.cc)
add_headers(FMT_HEADERS args.h chrono.h color.h compile.h core.h format.h
format-inl.h os.h ostream.h printf.h ranges.h std.h
xchar.h)
set(FMT_SOURCES src/format.cc)
if (FMT_OS)
set(FMT_SOURCES ${FMT_SOURCES} src/os.cc)
endif ()
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst)
add_module_library(fmt src/fmt.cc FALLBACK
${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst
IF FMT_MODULE)
add_library(fmt::fmt ALIAS fmt)
if (HAVE_STRTOD_L)
target_compile_definitions(fmt PUBLIC FMT_LOCALE)
if (FMT_MODULE)
enable_module(fmt)
endif ()
if (FMT_WERROR)
@ -167,23 +297,32 @@ if (FMT_PEDANTIC)
target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
target_compile_features(fmt INTERFACE ${FMT_REQUIRED_FEATURES})
if (cxx_std_11 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
target_compile_features(fmt PUBLIC cxx_std_11)
else ()
message(WARNING "Feature cxx_std_11 is unknown for the CXX compiler")
endif ()
target_include_directories(fmt PUBLIC
target_include_directories(fmt ${FMT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
set(FMT_DEBUG_POSTFIX d CACHE STRING "Debug library postfix.")
set_target_properties(fmt PROPERTIES
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
DEBUG_POSTFIX d)
PUBLIC_HEADER "${FMT_HEADERS}"
DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}")
# Set FMT_LIB_NAME for pkg-config fmt.pc. We cannot use the OUTPUT_NAME target
# property because it's not set by default.
set(FMT_LIB_NAME fmt)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(FMT_LIB_NAME ${FMT_LIB_NAME}${FMT_DEBUG_POSTFIX})
endif ()
if (BUILD_SHARED_LIBS)
if (UNIX AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
# 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)
target_compile_definitions(fmt PRIVATE FMT_LIB_EXPORT INTERFACE FMT_SHARED)
endif ()
if (FMT_SAFE_DURATION_CAST)
target_compile_definitions(fmt PUBLIC FMT_SAFE_DURATION_CAST)
@ -193,43 +332,42 @@ 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_compile_features(fmt-header-only INTERFACE cxx_std_11)
target_compile_features(fmt-header-only INTERFACE ${FMT_REQUIRED_FEATURES})
target_include_directories(fmt-header-only INTERFACE
target_include_directories(fmt-header-only ${FMT_SYSTEM_HEADERS_ATTRIBUTE} INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
# 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_verbose(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING
"Installation directory for cmake files, a relative path that "
"will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute "
"path.")
set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake)
set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake)
set(pkgconfig ${PROJECT_BINARY_DIR}/fmt.pc)
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_verbose(FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING
"Installation directory for libraries, a relative path that "
"will be joined to ${CMAKE_INSTALL_PREFIX} or an absolute path.")
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}.")
set(FMT_PKGCONFIG_DIR ${CMAKE_INSTALL_LIBDIR}/pkgconfig CACHE PATH
"Installation directory for pkgconfig (.pc) files, relative to ${CMAKE_INSTALL_PREFIX}.")
set_verbose(FMT_PKGCONFIG_DIR ${CMAKE_INSTALL_LIBDIR}/pkgconfig CACHE STRING
"Installation directory for pkgconfig (.pc) files, a relative "
"path that will be joined with ${CMAKE_INSTALL_PREFIX} or an "
"absolute path.")
# Generate the version, config and target files into the build directory.
write_basic_package_version_file(
${version_config}
VERSION ${FMT_VERSION}
COMPATIBILITY AnyNewerVersion)
join_paths(libdir_for_pc_file "\${exec_prefix}" "${FMT_LIB_DIR}")
join_paths(includedir_for_pc_file "\${prefix}" "${FMT_INC_DIR}")
configure_file(
"${PROJECT_SOURCE_DIR}/support/cmake/fmt.pc.in"
"${pkgconfig}"
@ -238,6 +376,16 @@ if (FMT_INSTALL)
${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in
${project_config}
INSTALL_DESTINATION ${FMT_CMAKE_DIR})
set(INSTALL_TARGETS fmt fmt-header-only)
# Install the library and headers.
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
LIBRARY DESTINATION ${FMT_LIB_DIR}
ARCHIVE DESTINATION ${FMT_LIB_DIR}
PUBLIC_HEADER DESTINATION "${FMT_INC_DIR}/fmt"
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
# Use a namespace because CMake provides better diagnostics for namespaced
# imported targets.
export(TARGETS ${INSTALL_TARGETS} NAMESPACE fmt::
@ -250,15 +398,6 @@ if (FMT_INSTALL)
install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR}
NAMESPACE fmt::)
# Install the library and headers.
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
LIBRARY DESTINATION ${FMT_LIB_DIR}
ARCHIVE DESTINATION ${FMT_LIB_DIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install(FILES $<TARGET_PDB_FILE:${INSTALL_TARGETS}>
DESTINATION ${FMT_LIB_DIR} OPTIONAL)
install(FILES ${FMT_HEADERS} DESTINATION ${FMT_INC_DIR})
install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}")
endif ()
@ -274,13 +413,20 @@ endif ()
# Control fuzzing independent of the unit tests.
if (FMT_FUZZ)
add_subdirectory(test/fuzzing)
# The FMT_FUZZ macro is used to prevent resource exhaustion in fuzzing
# mode and make fuzzing practically possible. It is similar to
# FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION but uses a different name to
# avoid interfering with fuzzing of projects that use {fmt}.
# See also https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode.
target_compile_definitions(fmt PUBLIC FMT_FUZZ)
endif ()
set(gitignore ${PROJECT_SOURCE_DIR}/.gitignore)
if (MASTER_PROJECT AND EXISTS ${gitignore})
if (FMT_MASTER_PROJECT AND EXISTS ${gitignore})
# Get the list of ignored files from .gitignore.
file (STRINGS ${gitignore} lines)
LIST(REMOVE_ITEM lines /doc/html)
list(REMOVE_ITEM lines /doc/html)
foreach (line ${lines})
string(REPLACE "." "[.]" line "${line}")
string(REPLACE "*" ".*" line "${line}")

View File

@ -14,4 +14,7 @@ exceptions:
* snake_case should be used instead of UpperCamelCase for function and type
names
All documentation must adhere to the [Google Developer Documentation Style
Guide](https://developers.google.com/style).
Thanks for contributing!

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
Copyright (c) 2012 - present, Victor Zverovich
Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@ -1,159 +1,188 @@
{fmt}
=====
.. image:: https://user-images.githubusercontent.com/
576385/156254208-f5b743a9-88cf-439d-b0c0-923d53e8d551.png
:width: 25%
:alt: {fmt}
.. image:: https://travis-ci.org/fmtlib/fmt.png?branch=master
:target: https://travis-ci.org/fmtlib/fmt
.. image:: https://github.com/fmtlib/fmt/workflows/linux/badge.svg
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux
.. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v
:target: https://ci.appveyor.com/project/vitaut/fmt
.. image:: https://github.com/fmtlib/fmt/workflows/macos/badge.svg
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Amacos
.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/libfmt.svg
:alt: fmt is continuously fuzzed att oss-fuzz
:target: https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dlibfmt&can=1
.. image:: https://github.com/fmtlib/fmt/workflows/windows/badge.svg
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows
.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/fmt.svg
:alt: fmt is continuously fuzzed at oss-fuzz
:target: https://bugs.chromium.org/p/oss-fuzz/issues/list?\
colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20\
Summary&q=proj%3Dfmt&can=1
.. image:: https://img.shields.io/badge/stackoverflow-fmt-blue.svg
:alt: Ask questions at StackOverflow with the tag fmt
:target: http://stackoverflow.com/questions/tagged/fmt
:target: https://stackoverflow.com/questions/tagged/fmt
**{fmt}** is an open-source formatting library for C++.
It can be used as a safe and fast alternative to (s)printf and iostreams.
**{fmt}** is an open-source formatting library providing a fast and safe
alternative to C stdio and C++ iostreams.
`Documentation <https://fmt.dev/latest/>`__
If you like this project, please consider donating to one of the funds that
help victims of the war in Ukraine: https://www.stopputin.net/.
Q&A: ask questions on `StackOverflow with the tag fmt <http://stackoverflow.com/questions/tagged/fmt>`_.
`Documentation <https://fmt.dev>`__
`Cheat Sheets <https://hackingcpp.com/cpp/libs/fmt.html>`__
Q&A: ask questions on `StackOverflow with the tag fmt
<https://stackoverflow.com/questions/tagged/fmt>`_.
Try {fmt} in `Compiler Explorer <https://godbolt.org/z/Eq5763>`_.
Features
--------
* Replacement-based `format API <https://fmt.dev/dev/api.html>`_ with
positional arguments for localization.
* `Format string syntax <https://fmt.dev/dev/syntax.html>`_ similar to the one
of `str.format <https://docs.python.org/3/library/stdtypes.html#str.format>`_
in Python.
* Simple `format API <https://fmt.dev/latest/api.html>`_ with positional arguments
for localization
* Implementation of `C++20 std::format
<https://en.cppreference.com/w/cpp/utility/format>`__
* `Format string syntax <https://fmt.dev/latest/syntax.html>`_ similar to Python's
`format <https://docs.python.org/3/library/stdtypes.html#str.format>`_
* Fast IEEE 754 floating-point formatter with correct rounding, shortness and
round-trip guarantees using the `Dragonbox <https://github.com/jk-jeon/dragonbox>`_
algorithm
* Portable Unicode support
* Safe `printf implementation
<https://fmt.dev/latest/api.html#printf-formatting>`_ including
the POSIX extension for positional arguments.
* Implementation of `C++20 std::format <https://fmt.dev/Text%20Formatting.html>`__.
* Support for user-defined types.
<https://fmt.dev/latest/api.html#printf-formatting>`_ including the POSIX
extension for positional arguments
* Extensibility: `support for user-defined types
<https://fmt.dev/latest/api.html#formatting-user-defined-types>`_
* High performance: faster than common standard library implementations of
`printf <http://en.cppreference.com/w/cpp/io/c/fprintf>`_ and
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 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>`_ and is continuously fuzzed.
* Safety: the library is fully type safe, errors in format strings can be
``(s)printf``, iostreams, ``to_string`` and ``to_chars``, see `Speed tests`_
and `Converting a hundred million integers to strings per second
<http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html>`_
* Small code size both in terms of source code with the minimum configuration
consisting of just three files, ``core.h``, ``format.h`` and ``format-inl.h``,
and compiled code; see `Compile time and code bloat`_
* Reliability: the library has an extensive set of `tests
<https://github.com/fmtlib/fmt/tree/master/test>`_ and is `continuously fuzzed
<https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20
Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dfmt&can=1>`_
* Safety: the library is fully type-safe, errors in format strings can be
reported at compile time, automatic memory management prevents buffer overflow
errors.
errors
* Ease of use: small self-contained code base, no external dependencies,
permissive MIT `license
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_
* `Portability <https://fmt.dev/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``).
* Support for wide strings.
* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro.
consistent output across platforms and support for older compilers
* Clean warning-free codebase even on high warning levels such as
``-Wall -Wextra -pedantic``
* Locale independence by default
* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro
See the `documentation <https://fmt.dev/latest/>`_ for more details.
See the `documentation <https://fmt.dev>`_ for more details.
Examples
--------
Print ``Hello, world!`` to ``stdout``:
**Print to stdout** (`run <https://godbolt.org/z/Tevcjh>`_)
.. code:: c++
fmt::print("Hello, {}!", "world"); // Python-like format string syntax
fmt::printf("Hello, %s!", "world"); // printf format string syntax
#include <fmt/core.h>
int main() {
fmt::print("Hello, world!\n");
}
Format a string and use positional arguments:
**Format a string** (`run <https://godbolt.org/z/oK8h33>`_)
.. code:: c++
std::string s = fmt::format("The answer is {}.", 42);
// s == "The answer is 42."
**Format a string using positional arguments** (`run <https://godbolt.org/z/Yn7Txe>`_)
.. code:: c++
std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");
// s == "I'd rather be happy than right."
Check a format string at compile time:
**Print chrono durations** (`run <https://godbolt.org/z/K8s4Mc>`_)
.. code:: c++
// test.cc
#include <fmt/format.h>
std::string s = format(FMT_STRING("{2}"), 42);
#include <fmt/chrono.h>
.. code::
$ c++ -Iinclude -std=c++14 test.cc
...
test.cc:4:17: note: in instantiation of function template specialization 'fmt::v5::format<S, int>' requested here
std::string s = format(FMT_STRING("{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");
^
Use {fmt} 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 with to_string(buf) or buf.data()
Format objects of user-defined types via a simple `extension API
<https://fmt.dev/latest/api.html#formatting-user-defined-types>`_:
.. code:: c++
#include "fmt/format.h"
struct date {
int year, month, day;
};
template <>
struct fmt::formatter<date> {
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const date& d, FormatContext& ctx) {
return format_to(ctx.out(), "{}-{}-{}", d.year, d.month, d.day);
}
};
std::string s = fmt::format("The date is {}", date{2012, 12, 9});
// s == "The date is 2012-12-9"
Create your own functions similar to `format
<https://fmt.dev/latest/api.html#format>`_ and
`print <https://fmt.dev/latest/api.html#print>`_
which take arbitrary arguments (`godbolt <https://godbolt.org/g/MHjHVf>`_):
.. 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...));
int main() {
using namespace std::literals::chrono_literals;
fmt::print("Default format: {} {}\n", 42s, 100ms);
fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s);
}
report_error("file not found: {}", path);
Output::
Note that ``vreport_error`` is not parameterized on argument types which can
improve compile times and reduce code size compared to a fully parameterized
version.
Default format: 42s 100ms
strftime-like format: 03:15:30
**Print a container** (`run <https://godbolt.org/z/MxM1YqjE7>`_)
.. code:: c++
#include <vector>
#include <fmt/ranges.h>
int main() {
std::vector<int> v = {1, 2, 3};
fmt::print("{}\n", v);
}
Output::
[1, 2, 3]
**Check a format string at compile time**
.. code:: c++
std::string s = fmt::format("{:d}", "I am not a number");
This gives a compile-time error in C++20 because ``d`` is an invalid format
specifier for a string.
**Write a file from a single thread**
.. code:: c++
#include <fmt/os.h>
int main() {
auto out = fmt::output_file("guide.txt");
out.print("Don't {}", "Panic");
}
This can be `5 to 9 times faster than fprintf
<http://www.zverovich.net/2020/08/04/optimal-file-buffer-size.html>`_.
**Print with colors and text styles**
.. code:: c++
#include <fmt/color.h>
int main() {
fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold,
"Hello, {}!\n", "world");
fmt::print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) |
fmt::emphasis::underline, "Hello, {}!\n", "мир");
fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::italic,
"Hello, {}!\n", "世界");
}
Output on a modern terminal:
.. image:: https://user-images.githubusercontent.com/
576385/88485597-d312f600-cf2b-11ea-9cbe-61f535a86e28.png
Benchmarks
----------
@ -164,28 +193,30 @@ Speed tests
================= ============= ===========
Library Method Run Time, s
================= ============= ===========
libc printf 1.03
libc++ std::ostream 2.98
{fmt} 4de41a fmt::print 0.76
Boost Format 1.67 boost::format 7.24
Folly Format folly::format 2.23
libc printf 0.91
libc++ std::ostream 2.49
{fmt} 9.1 fmt::print 0.74
Boost Format 1.80 boost::format 6.26
Folly Format folly::format 1.87
================= ============= ===========
{fmt} is the fastest of the benchmarked methods, ~35% faster than ``printf``.
{fmt} is the fastest of the benchmarked methods, ~20% faster than ``printf``.
The above results were generated by building ``tinyformat_test.cpp`` on macOS
10.14.3 with ``clang++ -O3 -DSPEED_TEST -DHAVE_FORMAT``, and taking the best of
three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"``
12.6.1 with ``clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT``, and taking the
best of three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"``
or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for
further details refer to the `source
<https://github.com/fmtlib/format-benchmark/blob/master/tinyformat_test.cpp>`_.
<https://github.com/fmtlib/format-benchmark/blob/master/src/tinyformat-test.cc>`_.
{fmt} is 10x faster than ``std::ostringstream`` and ``sprintf`` on floating-point
formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
and as fast as `double-conversion <https://github.com/google/double-conversion>`_:
{fmt} is up to 20-30x faster than ``std::ostringstream`` and ``sprintf`` on
IEEE754 ``float`` and ``double`` formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
and faster than `double-conversion <https://github.com/google/double-conversion>`_ and
`ryu <https://github.com/ulfjack/ryu>`_:
.. image:: https://user-images.githubusercontent.com/576385/69767160-cdaca400-112f-11ea-9fc5-347c9f83caad.png
:target: https://fmt.dev/unknown_mac64_clang10.0.html
.. image:: https://user-images.githubusercontent.com/576385/
95684665-11719600-0ba8-11eb-8e5b-972ff4e49428.png
:target: https://fmt.dev/unknown_mac64_clang12.0.html
Compile time and code bloat
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -195,7 +226,7 @@ The script `bloat-test.py
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
five times in each to simulate a medium-sized project. The resulting
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.
@ -216,7 +247,7 @@ 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
and Folly Format have the largest overheads.
``printf+string`` is the same as ``printf`` but with extra ``<string>``
``printf+string`` is the same as ``printf`` but with an extra ``<string>``
include to measure the overhead of the latter.
**Non-optimized build**
@ -232,14 +263,14 @@ Boost Format 54.1 365 303
Folly Format 79.9 445 430
============= =============== ==================== ==================
``libc``, ``lib(std)c++`` and ``libfmt`` are all linked as shared libraries to
``libc``, ``lib(std)c++``, and ``libfmt`` are all linked as shared libraries to
compare formatting function overhead only. Boost Format is a
header-only library so it doesn't provide any linkage options.
Running the tests
~~~~~~~~~~~~~~~~~
Please refer to `Building the library`__ for the instructions on how to build
Please refer to `Building the library`__ for instructions on how to build
the library and run the unit tests.
__ https://fmt.dev/latest/usage.html#building-the-library
@ -260,40 +291,49 @@ Then you can run the speed test::
or the bloat test::
$ make bloat-test
Migrating code
--------------
`clang-tidy <https://clang.llvm.org/extra/clang-tidy/>`_ v17 (not yet
released) provides the `modernize-use-std-print
<https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-std-print.html>`_
check that is capable of converting occurrences of ``printf`` and
``fprintf`` to ``fmt::print`` if configured to do so. (By default it
converts to ``std::print``.)
Projects using this library
---------------------------
* `0 A.D. <http://play0ad.com/>`_: A free, open-source, cross-platform real-time
strategy game
* `0 A.D. <https://play0ad.com/>`_: a free, open-source, cross-platform
real-time strategy game
* `AMPL/MP <https://github.com/ampl/mp>`_:
An open-source library for mathematical programming
* `AvioBook <https://www.aviobook.aero/en>`_: A comprehensive aircraft
an open-source library for mathematical programming
* `Aseprite <https://github.com/aseprite/aseprite>`_:
animated sprite editor & pixel art tool
* `AvioBook <https://www.aviobook.aero/en>`_: a comprehensive aircraft
operations suite
* `Celestia <https://celestia.space/>`_: Real-time 3D visualization of space
* `Blizzard Battle.net <https://battle.net/>`_: an online gaming platform
* `Celestia <https://celestia.space/>`_: real-time 3D visualization of space
* `Ceph <https://ceph.com/>`_: A scalable distributed storage system
* `Ceph <https://ceph.com/>`_: a scalable distributed storage system
* `ccache <https://ccache.dev/>`_: A compiler cache
* `ccache <https://ccache.dev/>`_: a compiler cache
* `CUAUV <http://cuauv.org/>`_: Cornell University's autonomous underwater
* `ClickHouse <https://github.com/ClickHouse/ClickHouse>`_: an analytical database
management system
* `Contour <https://github.com/contour-terminal/contour/>`_: a modern terminal emulator
* `CUAUV <https://cuauv.org/>`_: Cornell University's autonomous underwater
vehicle
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
Player vs Player Gaming Network with tweaks
* `KBEngine <http://kbengine.org/>`_: An open-source MMOG server engine
* `Keypirinha <http://keypirinha.com/>`_: A semantic launcher for Windows
* `Kodi <https://kodi.tv/>`_ (formerly xbmc): Home theater software
* `Lifeline <https://github.com/peter-clark/lifeline>`_: A 2D game
* `Drake <http://drake.mit.edu/>`_: A planning, control, and analysis toolbox
* `Drake <https://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
@ -301,49 +341,93 @@ Projects using this library
* `FiveM <https://fivem.net/>`_: a modification framework for GTA V
* `MongoDB <https://mongodb.com/>`_: Distributed document database
* `fmtlog <https://github.com/MengRao/fmtlog>`_: a performant fmtlib-style
logging library with latency in nanoseconds
* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to
* `Folly <https://github.com/facebook/folly>`_: Facebook open-source library
* `GemRB <https://gemrb.org/>`_: a portable open-source implementation of
Biowares Infinity Engine
* `Grand Mountain Adventure
<https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/>`_:
a beautiful open-world ski & snowboarding game
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
Player vs Player Gaming Network with tweaks
* `KBEngine <https://github.com/kbengine/kbengine>`_: an open-source MMOG server
engine
* `Keypirinha <https://keypirinha.com/>`_: a semantic launcher for Windows
* `Kodi <https://kodi.tv/>`_ (formerly xbmc): home theater software
* `Knuth <https://kth.cash/>`_: high-performance Bitcoin full-node
* `libunicode <https://github.com/contour-terminal/libunicode/>`_: a modern C++17 Unicode library
* `MariaDB <https://mariadb.org/>`_: relational database management system
* `Microsoft Verona <https://github.com/microsoft/verona>`_:
research programming language for concurrent ownership
* `MongoDB <https://mongodb.com/>`_: distributed document database
* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: a small tool to
generate randomized datasets
* `OpenSpace <http://openspaceproject.com/>`_: An open-source astrovisualization
framework
* `OpenSpace <https://openspaceproject.com/>`_: an open-source
astrovisualization framework
* `PenUltima Online (POL) <http://www.polserver.com/>`_:
An MMO server, compatible with most Ultima Online clients
* `PenUltima Online (POL) <https://www.polserver.com/>`_:
an MMO server, compatible with most Ultima Online clients
* `quasardb <https://www.quasardb.net/>`_: A distributed, high-performance,
* `PyTorch <https://github.com/pytorch/pytorch>`_: an open-source machine
learning library
* `quasardb <https://www.quasardb.net/>`_: a distributed, high-performance,
associative database
* `Quill <https://github.com/odygrd/quill>`_: asynchronous low-latency logging library
* `readpe <https://bitbucket.org/sys_dev/readpe>`_: Read Portable Executable
* `QKW <https://github.com/ravijanjam/qkw>`_: generalizing aliasing to simplify
navigation, and executing complex multi-line terminal command sequences
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: A Redis cluster
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: a Redis cluster
proxy
* `rpclib <http://rpclib.net/>`_: A modern C++ msgpack-RPC server and client
* `redpanda <https://vectorized.io/redpanda>`_: a 10x faster Kafka® replacement
for mission-critical systems written in C++
* `rpclib <http://rpclib.net/>`_: a modern C++ msgpack-RPC server and client
library
* `Saddy <https://github.com/mamontov-cpp/saddy-graphics-engine-2d>`_:
Small crossplatform 2D graphic engine
* `Salesforce Analytics Cloud
<https://www.salesforce.com/analytics-cloud/overview/>`_:
business intelligence software
* `Salesforce Analytics Cloud <http://www.salesforce.com/analytics-cloud/overview/>`_:
Business intelligence software
* `Scylla <http://www.scylladb.com/>`_: A Cassandra-compatible NoSQL data store
* `Scylla <https://www.scylladb.com/>`_: a Cassandra-compatible NoSQL data store
that can handle 1 million transactions per second on a single server
* `Seastar <http://www.seastar-project.org/>`_: An advanced, open-source C++
* `Seastar <http://www.seastar-project.org/>`_: an advanced, open-source C++
framework for high-performance server applications on modern hardware
* `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging library
* `spdlog <https://github.com/gabime/spdlog>`_: super fast C++ logging library
* `Stellar <https://www.stellar.org/>`_: Financial platform
* `Stellar <https://www.stellar.org/>`_: financial platform
* `Touch Surgery <https://www.touchsurgery.com/>`_: Surgery simulator
* `Touch Surgery <https://www.touchsurgery.com/>`_: surgery simulator
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: Open-source
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: open-source
MMORPG framework
* `🐙 userver framework <https://userver.tech/>`_: open-source asynchronous
framework with a rich set of abstractions and database drivers
* `Windows Terminal <https://github.com/microsoft/terminal>`_: the new Windows
terminal
`More... <https://github.com/search?q=fmtlib&type=Code>`_
If you are aware of other projects using this library, please let me know
@ -368,7 +452,7 @@ The good thing about ``printf`` is that it is pretty fast and readily available
being a part of the C standard library. The main drawback is that it
doesn't support user-defined types. ``printf`` also has safety issues although
they are somewhat mitigated with `__attribute__ ((format (printf, ...))
<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ in GCC.
<https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ in GCC.
There is a POSIX extension that adds positional arguments required for
`i18n <https://en.wikipedia.org/wiki/Internationalization_and_localization>`_
to ``printf`` but it is not a part of C99 and may not be available on some
@ -398,17 +482,17 @@ error handling is awkward.
Boost Format
~~~~~~~~~~~~
This is a very powerful library which supports both ``printf``-like format
This is a very powerful library that supports both ``printf``-like format
strings and positional arguments. Its main drawback is performance. According to
various benchmarks it is much slower than other methods considered here. Boost
various benchmarks, it is much slower than other methods considered here. Boost
Format also has excessive build times and severe code bloat issues (see
`Benchmarks`_).
FastFormat
~~~~~~~~~~
This is an interesting library which is fast, safe and has positional
arguments. However it has significant limitations, citing its author:
This is an interesting library that is fast, safe, and has positional arguments.
However, it has significant limitations, citing its author:
Three features that have no hope of being accommodated within the
current design are:
@ -417,41 +501,18 @@ arguments. However it has significant limitations, citing its author:
* Octal/hexadecimal encoding
* Runtime width/alignment specification
It is also quite big and has a heavy dependency, STLSoft, which might be
too restrictive for using it in some projects.
It is also quite big and has a heavy dependency, STLSoft, which might be too
restrictive for using it in some projects.
Boost Spirit.Karma
~~~~~~~~~~~~~~~~~~
This is not really a formatting library but I decided to include it here for
This is not a formatting library but I decided to include it here for
completeness. As iostreams, it suffers from the problem of mixing verbatim text
with arguments. The library is pretty fast, but slower on integer formatting
than ``fmt::format_int`` on Karma's own benchmark,
see `Fast integer to string conversion in C++
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
FAQ
---
Q: how can I capture formatting arguments and format them later?
A: use ``std::tuple``:
.. code:: c++
template <typename... Args>
auto capture(const Args&... args) {
return std::make_tuple(args...);
}
auto print_message = [](const auto&... args) {
fmt::print(args...);
};
// Capture and store arguments:
auto args = capture("{} {}", 42, "foo");
// Do formatting:
std::apply(print_message, args);
than ``fmt::format_to`` with format string compilation on Karma's own benchmark,
see `Converting a hundred million integers to strings per second
<http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html>`_.
License
-------
@ -459,43 +520,23 @@ License
{fmt} is distributed under the MIT `license
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_.
The `Format String Syntax
<https://fmt.dev/latest/syntax.html>`_
section in the documentation is based on the one from Python `string module
documentation <https://docs.python.org/3/library/string.html#module-string>`_
adapted for the current library. For this reason the documentation is
distributed under the Python Software Foundation license available in
`doc/python-license.txt
<https://raw.github.com/fmtlib/fmt/master/doc/python-license.txt>`_.
It only applies if you distribute the documentation of fmt.
Documentation License
---------------------
Acknowledgments
---------------
The `Format String Syntax <https://fmt.dev/latest/syntax.html>`_
section in the documentation is based on the one from Python `string module
documentation <https://docs.python.org/3/library/string.html#module-string>`_.
For this reason, the documentation is distributed under the Python Software
Foundation license available in `doc/python-license.txt
<https://raw.github.com/fmtlib/fmt/master/doc/python-license.txt>`_.
It only applies if you distribute the documentation of {fmt}.
Maintainers
-----------
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.
<https://github.com/vitaut>`_) 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
written by Chris Foster. Boost Format library is acknowledged transitively
since it had some influence on tinyformat.
Some ideas used in the implementation are borrowed from `Loki
<http://loki-lib.sourceforge.net/>`_ SafeFormat and `Diagnostic API
<http://clang.llvm.org/doxygen/classclang_1_1Diagnostic.html>`_ in
`Clang <http://clang.llvm.org/>`_.
Format string syntax and the documentation are based on Python's `str.format
<https://docs.python.org/3/library/stdtypes.html#str.format>`_.
Thanks `Doug Turnbull <https://github.com/softwaredoug>`_ for his valuable
comments and contribution to the design of the type-safe API and
`Gregory Czajkowski <https://github.com/gcflymoto>`_ for implementing binary
formatting. Thanks `Ruslan Baratov <https://github.com/ruslo>`_ for comprehensive
`comparison of integer formatting algorithms <https://github.com/ruslo/int-dec-format-tests>`_
and useful comments regarding performance, `Boris Kaul <https://github.com/localvoid>`_ for
`C++ counting digits benchmark <https://github.com/localvoid/cxx-benchmark-count-digits>`_.
Thanks to `CarterLi <https://github.com/CarterLi>`_ for contributing various
improvements to the code.

View File

@ -1,12 +1,26 @@
find_program(DOXYGEN doxygen)
find_program(DOXYGEN doxygen
PATHS "$ENV{ProgramFiles}/doxygen/bin"
"$ENV{ProgramFiles\(x86\)}/doxygen/bin")
if (NOT DOXYGEN)
message(STATUS "Target 'doc' disabled (requires doxygen)")
return ()
endif ()
# Find the Python interpreter and set the PYTHON_EXECUTABLE variable.
if (CMAKE_VERSION VERSION_LESS 3.12)
# This logic is deprecated in CMake after 3.12.
find_package(PythonInterp QUIET REQUIRED)
else ()
find_package(Python QUIET REQUIRED)
set(PYTHON_EXECUTABLE ${Python_EXECUTABLE})
endif ()
add_custom_target(doc
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build.py ${FMT_VERSION}
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/build.py
${FMT_VERSION}
SOURCES api.rst syntax.rst usage.rst build.py conf.py _templates/layout.html)
include(GNUInstallDirs)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/
DESTINATION share/doc/fmt OPTIONAL)
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/doc/fmt OPTIONAL
PATTERN ".doctrees" EXCLUDE)

View File

@ -6,14 +6,13 @@
<meta name="author" content="Victor Zverovich">
<link rel="stylesheet" href="_static/fmt.css">
{# Google Analytics #}
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-20116650-4"></script>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();
a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;
a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-20116650-4', 'fmtlib.net');
ga('send', 'pageview');
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-20116650-4');
</script>
{% endblock %}

View File

@ -6,15 +6,20 @@ API Reference
The {fmt} library API consists of the following parts:
* :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/ranges.h <ranges-api>`: additional formatting support for ranges
and tuples
* :ref:`fmt/core.h <core-api>`: the core API providing main formatting functions
for ``char``/UTF-8 with C++20 compile-time checks and minimal dependencies
* :ref:`fmt/format.h <format-api>`: the full format API providing additional
formatting functions and locale support
* :ref:`fmt/ranges.h <ranges-api>`: formatting of ranges and tuples
* :ref:`fmt/chrono.h <chrono-api>`: date and time formatting
* :ref:`fmt/std.h <std-api>`: formatters for standard library types
* :ref:`fmt/compile.h <compile-api>`: format string compilation
* :ref:`fmt/color.h <color-api>`: terminal color and text style
* :ref:`fmt/os.h <os-api>`: system APIs
* :ref:`fmt/ostream.h <ostream-api>`: ``std::ostream`` support
* :ref:`fmt/args.h <args-api>`: dynamic argument lists
* :ref:`fmt/printf.h <printf-api>`: ``printf`` formatting
* :ref:`fmt/xchar.h <xchar-api>`: optional ``wchar_t`` support
All functions and types provided by the library reside in namespace ``fmt`` and
macros have prefix ``FMT_``.
@ -24,101 +29,113 @@ macros have prefix ``FMT_``.
Core API
========
``fmt/core.h`` defines the core API which provides argument handling facilities
and a lightweight subset of formatting functions. In the header-only mode
include ``fmt/format.h`` instead of ``fmt/core.h``.
``fmt/core.h`` defines the core API which provides main formatting functions
for ``char``/UTF-8 with C++20 compile-time checks. It has minimal include
dependencies for better compile times. This header is only beneficial when
using {fmt} as a library (the default) and not in the header-only mode.
It also provides ``formatter`` specializations for built-in and string types.
The following functions use :ref:`format string syntax <syntax>`
similar 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.
<https://docs.python.org/3/library/stdtypes.html#str.format>`_.
They take *fmt* 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. A function taking *format_str* doesn't
participate in an overload resolution if the latter is not a string.
*fmt* 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. `~fmt::format_string` is a format string which can be
implicitly constructed from a string literal or a ``constexpr`` string and is
checked at compile time in C++20. To pass a runtime format string wrap it in
`fmt::runtime`.
*args* is an argument list representing objects to be formatted.
.. _format:
.. doxygenfunction:: format(const S&, Args&&...)
.. doxygenfunction:: vformat(const S&, basic_format_args<buffer_context<Char>>)
.. doxygenfunction:: format(format_string<T...> fmt, T&&... args) -> std::string
.. doxygenfunction:: vformat(string_view fmt, format_args args) -> std::string
.. doxygenfunction:: format_to(OutputIt out, format_string<T...> fmt, T&&... args) -> OutputIt
.. doxygenfunction:: format_to_n(OutputIt out, size_t n, format_string<T...> fmt, T&&... args) -> format_to_n_result<OutputIt>
.. doxygenfunction:: formatted_size(format_string<T...> fmt, T&&... args) -> size_t
.. doxygenstruct:: fmt::format_to_n_result
:members:
.. _print:
.. doxygenfunction:: print(const S&, Args&&...)
.. doxygenfunction:: vprint(string_view, format_args)
.. doxygenfunction:: fmt::print(format_string<T...> fmt, T&&... args)
.. doxygenfunction:: fmt::vprint(string_view fmt, format_args args)
.. doxygenfunction:: print(std::FILE *, const S&, Args&&...)
.. doxygenfunction:: vprint(std::FILE *, string_view, format_args)
.. doxygenfunction:: print(std::FILE *f, format_string<T...> fmt, T&&... args)
.. doxygenfunction:: vprint(std::FILE *f, string_view fmt, format_args args)
Named Arguments
---------------
.. doxygenfunction:: fmt::arg(const S&, const T&)
Named arguments are not supported in compile-time checks at the moment.
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
Compile-Time Format String Checks
---------------------------------
Compile-time checks are supported for built-in and string types as well as
user-defined types with ``constexpr`` ``parse`` functions in their ``formatter``
specializations.
Compile-time format string checks are enabled by default on compilers
that support C++20 ``consteval``. On older compilers you can use the
:ref:`FMT_STRING <legacy-checks>`: macro defined in ``fmt/format.h`` instead.
.. doxygendefine:: FMT_STRING
Unused arguments are allowed as in Python's `str.format` and ordinary functions.
Formatting User-defined Types
.. doxygenclass:: fmt::basic_format_string
:members:
.. doxygentypedef:: fmt::format_string
.. doxygenfunction:: fmt::runtime(string_view) -> runtime_format_string<>
.. _udt:
Formatting User-Defined Types
-----------------------------
To make a user-defined type formattable, specialize the ``formatter<T>`` struct
template and implement ``parse`` and ``format`` methods::
The {fmt} library provides formatters for many standard C++ types.
See :ref:`fmt/ranges.h <ranges-api>` for ranges and tuples including standard
containers such as ``std::vector``, :ref:`fmt/chrono.h <chrono-api>` for date
and time formatting and :ref:`fmt/std.h <std-api>` for other standard library
types.
There are two ways to make a user-defined type formattable: providing a
``format_as`` function or specializing the ``formatter`` struct template.
Use ``format_as`` if you want to make your type formattable as some other type
with the same format specifiers. The ``format_as`` function should take an
object of your type and return an object of a formattable type. It should be
defined in the same namespace as your type.
Example (https://godbolt.org/z/r7vvGE1v7)::
#include <fmt/format.h>
struct point { double x, y; };
namespace kevin_namespacy {
enum class film {
house_of_cards, american_beauty, se7en = 7
};
auto format_as(film f) { return fmt::underlying(f); }
}
template <>
struct fmt::formatter<point> {
int main() {
fmt::print("{}\n", kevin_namespacy::film::se7en); // prints "7"
}
Using the specialization API is more complex but gives you full control over
parsing and formatting. To use this method specialize the ``formatter`` struct
template for your type and implement ``parse`` and ``format`` methods.
For example::
#include <fmt/core.h>
struct point {
double x, y;
};
template <> struct fmt::formatter<point> {
// Presentation format: 'f' - fixed, 'e' - exponential.
char presentation = 'f';
// Parses format specifications of the form ['f' | 'e'].
constexpr auto parse(format_parse_context& ctx) {
constexpr auto parse(format_parse_context& ctx) -> format_parse_context::iterator {
// [ctx.begin(), ctx.end()) is a character range that contains a part of
// the format string starting from the format specifications to be parsed,
// e.g. in
@ -129,14 +146,17 @@ template and implement ``parse`` and ``format`` methods::
// parse specifiers until '}' or the end of the range. In this example
// the formatter should parse the 'f' specifier and return an iterator
// pointing to '}'.
// Please also note that this character range may be empty, in case of
// the "{}" format string, so therefore you should check ctx.begin()
// for equality with ctx.end().
// Parse the presentation format and store it in the formatter:
auto it = ctx.begin(), end = ctx.end();
if (it != end && (*it == 'f' || *it == 'e')) presentation = *it++;
// Check if reached the end of the range:
if (it != end && *it != '}')
throw format_error("invalid format");
if (it != end && *it != '}') throw_format_error("invalid format");
// Return an iterator past the end of the parsed range:
return it;
@ -144,13 +164,11 @@ template and implement ``parse`` and ``format`` methods::
// Formats the point p using the parsed format specification (presentation)
// stored in this formatter.
template <typename FormatContext>
auto format(const point& p, FormatContext& ctx) {
auto format(const point& p, format_context& ctx) const -> format_context::iterator {
// ctx.out() is an output iterator to write to.
return format_to(
ctx.out(),
presentation == 'f' ? "({:.1f}, {:.1f})" : "({:.1e}, {:.1e})",
p.x, p.y);
return presentation == 'f'
? fmt::format_to(ctx.out(), "({:.1f}, {:.1f})", p.x, p.y)
: fmt::format_to(ctx.out(), "({:.1e}, {:.1e})", p.x, p.y);
}
};
@ -163,27 +181,47 @@ Then you can pass objects of type ``point`` to any formatting function::
You can also reuse existing formatters via inheritance or composition, for
example::
// color.h:
#include <fmt/core.h>
enum class color {red, green, blue};
template <>
struct fmt::formatter<color>: formatter<string_view> {
template <> struct fmt::formatter<color>: formatter<string_view> {
// parse is inherited from formatter<string_view>.
template <typename FormatContext>
auto format(color c, FormatContext& ctx) {
string_view name = "unknown";
switch (c) {
case color::red: name = "red"; break;
case color::green: name = "green"; break;
case color::blue: name = "blue"; break;
}
return formatter<string_view>::format(name, ctx);
}
auto format(color c, format_context& ctx) const;
};
// color.cc:
#include "color.h"
#include <fmt/format.h>
auto fmt::formatter<color>::format(color c, format_context& ctx) const {
string_view name = "unknown";
switch (c) {
case color::red: name = "red"; break;
case color::green: name = "green"; break;
case color::blue: name = "blue"; break;
}
return formatter<string_view>::format(name, ctx);
}
Note that ``formatter<string_view>::format`` is defined in ``fmt/format.h`` so
it has to be included in the source file.
Since ``parse`` is inherited from ``formatter<string_view>`` it will recognize
all string format specifications, for example
.. code-block:: c++
fmt::format("{:>10}", color::blue)
will return ``" blue"``.
You can also write a formatter for a hierarchy of classes::
// demo.h:
#include <type_traits>
#include <fmt/format.h>
#include <fmt/core.h>
struct A {
virtual ~A() {}
@ -197,56 +235,133 @@ You can also write a formatter for a hierarchy of classes::
template <typename T>
struct fmt::formatter<T, std::enable_if_t<std::is_base_of<A, T>::value, char>> :
fmt::formatter<std::string> {
template <typename FormatCtx>
auto format(const A& a, FormatCtx& ctx) {
auto format(const A& a, format_context& ctx) const {
return fmt::formatter<std::string>::format(a.name(), ctx);
}
};
// demo.cc:
#include "demo.h"
#include <fmt/format.h>
int main() {
B b;
A& a = b;
fmt::print("{}", a); // prints "B"
}
Providing both a ``formatter`` specialization and a ``format_as`` overload is
disallowed.
Named Arguments
---------------
.. doxygenfunction:: fmt::arg(const S&, const T&)
Named arguments are not supported in compile-time checks at the moment.
Argument Lists
--------------
You can create your own formatting function with compile-time checks and small
binary footprint, for example (https://godbolt.org/z/vajfWEG4b):
.. code:: c++
#include <fmt/core.h>
void vlog(const char* file, int line, fmt::string_view format,
fmt::format_args args) {
fmt::print("{}: {}: ", file, line);
fmt::vprint(format, args);
}
template <typename... T>
void log(const char* file, int line, fmt::format_string<T...> format, T&&... args) {
vlog(file, line, format, fmt::make_format_args(args...));
}
#define MY_LOG(format, ...) log(__FILE__, __LINE__, format, __VA_ARGS__)
MY_LOG("invalid squishiness: {}", 42);
Note that ``vlog`` is not parameterized on argument types which improves compile
times and reduces binary code size compared to a fully parameterized version.
.. doxygenfunction:: fmt::make_format_args(const Args&...)
.. doxygenclass:: fmt::format_arg_store
:members:
.. doxygenclass:: fmt::basic_format_args
:members:
.. doxygentypedef:: fmt::format_args
.. doxygenclass:: fmt::basic_format_arg
:members:
.. doxygenclass:: fmt::basic_format_parse_context
:members:
Output Iterator Support
-----------------------
.. doxygenfunction:: fmt::format_to(OutputIt, const S&, Args&&...)
.. doxygenfunction:: fmt::format_to_n(OutputIt, std::size_t, string_view, Args&&...)
.. doxygenstruct:: fmt::format_to_n_result
.. doxygenclass:: fmt::basic_format_context
:members:
Literal-based API
.. doxygentypedef:: fmt::format_context
.. _args-api:
Dynamic Argument Lists
----------------------
The header ``fmt/args.h`` provides ``dynamic_format_arg_store``, a builder-like
API that can be used to construct format argument lists dynamically.
.. doxygenclass:: fmt::dynamic_format_arg_store
:members:
Compatibility
-------------
.. doxygenclass:: fmt::basic_string_view
:members:
.. doxygentypedef:: fmt::string_view
.. _format-api:
Format API
==========
``fmt/format.h`` defines the full format API providing additional formatting
functions and locale support.
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)
.. doxygenfunction:: operator""_a()
Utilities
---------
.. doxygenstruct:: fmt::is_char
.. doxygenfunction:: fmt::ptr(T p) -> const void*
.. doxygenfunction:: fmt::ptr(const std::unique_ptr<T, Deleter> &p) -> const void*
.. doxygenfunction:: fmt::ptr(const std::shared_ptr<T> &p) -> const void*
.. doxygentypedef:: fmt::char_t
.. doxygenfunction:: fmt::underlying(Enum e) -> typename std::underlying_type<Enum>::type
.. doxygenfunction:: fmt::formatted_size(string_view, const Args&...)
.. doxygenfunction:: fmt::to_string(const T &value) -> std::string
.. doxygenfunction:: fmt::to_string(const T&)
.. doxygenfunction:: fmt::join(Range &&range, string_view sep) -> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>>
.. doxygenfunction:: fmt::to_wstring(const T&)
.. doxygenfunction:: fmt::join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel>
.. doxygenfunction:: fmt::to_string_view(const Char *)
.. doxygenfunction:: fmt::group_digits(T value) -> group_digits_view<T>
.. doxygenfunction:: fmt::join(const Range&, string_view)
.. doxygenfunction:: fmt::join(It, It, string_view)
.. doxygenclass:: fmt::detail::buffer
:members:
.. doxygenclass:: fmt::basic_memory_buffer
:protected-members:
@ -255,20 +370,14 @@ Utilities
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.
{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::system_error
.. doxygenfunction:: fmt::format_system_error
.. doxygenclass:: fmt::windows_error
:members:
.. _formatstrings:
Custom Allocators
-----------------
@ -287,8 +396,8 @@ 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);
auto buf = custom_memory_buffer(alloc);
fmt::vformat_to(std::back_inserter(buf), format_str, args);
return custom_string(buf.data(), buf.size(), alloc);
}
@ -299,59 +408,50 @@ allocator::
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.
The allocator will be used for the output container only. Formatting functions
normally don't do any allocations for built-in and string types except for
non-default floating-point formatting that occasionally falls back on
``sprintf``.
Custom Formatting of Built-in Types
-----------------------------------
Locale
------
It is possible to change the way arguments are formatted by providing a
custom argument formatter class::
All formatting is locale-independent by default. Use the ``'L'`` format
specifier to insert the appropriate number separator characters from the
locale::
using arg_formatter = fmt::arg_formatter<fmt::buffer_range<char>>;
#include <fmt/core.h>
#include <locale>
// 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_parse_context* parse_ctx = nullptr,
fmt::format_specs* spec = nullptr)
: arg_formatter(ctx, parse_ctx, spec) {}
std::locale::global(std::locale("en_US.UTF-8"));
auto s = fmt::format("{:L}", 1000000); // s == "1,000,000"
using arg_formatter::operator();
``fmt/format.h`` provides the following overloads of formatting functions that
take ``std::locale`` as a parameter. The locale type is a template parameter to
avoid the expensive ``<locale>`` include.
auto operator()(int value) {
if (specs() && specs()->type == 'x')
return (*this)(static_cast<unsigned>(value)); // convert to unsigned and format
return arg_formatter::operator()(value);
}
};
.. doxygenfunction:: format(const Locale& loc, format_string<T...> fmt, T&&... args) -> std::string
.. doxygenfunction:: format_to(OutputIt out, const Locale& loc, format_string<T...> fmt, T&&... args) -> OutputIt
.. doxygenfunction:: formatted_size(const Locale& loc, format_string<T...> fmt, T&&... args) -> size_t
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);
}
.. _legacy-checks:
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...));
}
Legacy Compile-Time Format String Checks
----------------------------------------
std::string s = custom_format("{:x}", -42); // s == "ffffffd6"
``FMT_STRING`` enables compile-time checks on older compilers. It requires C++14
or later and is a no-op in C++11.
.. doxygenclass:: fmt::arg_formatter
:members:
.. doxygendefine:: FMT_STRING
To force the use of legacy compile-time checks, define the preprocessor variable
``FMT_ENFORCE_COMPILE_STRING``. When set, functions accepting ``FMT_STRING``
will fail to compile with regular strings.
.. _ranges-api:
Ranges and Tuple Formatting
===========================
Range and Tuple Formatting
==========================
The library also supports convenient formatting of ranges and tuples::
@ -378,18 +478,121 @@ Using ``fmt::join``, you can separate tuple elements with a custom separator::
Date and Time Formatting
========================
The library supports `strftime
<http://en.cppreference.com/w/cpp/chrono/c/strftime>`_-like date and time
formatting::
``fmt/chrono.h`` provides formatters for
* `std::chrono::duration <https://en.cppreference.com/w/cpp/chrono/duration>`_
* `std::chrono::time_point
<https://en.cppreference.com/w/cpp/chrono/time_point>`_
* `std::tm <https://en.cppreference.com/w/cpp/chrono/c/tm>`_
The format syntax is described in :ref:`chrono-specs`.
**Example**::
#include <fmt/chrono.h>
std::time_t t = std::time(nullptr);
// Prints "The date is 2016-04-29." (with the current date)
fmt::print("The date is {:%Y-%m-%d}.", *std::localtime(&t));
int main() {
std::time_t t = std::time(nullptr);
The format string syntax is described in the documentation of
`strftime <http://en.cppreference.com/w/cpp/chrono/c/strftime>`_.
// Prints "The date is 2020-11-07." (with the current date):
fmt::print("The date is {:%Y-%m-%d}.", fmt::localtime(t));
using namespace std::literals::chrono_literals;
// Prints "Default format: 42s 100ms":
fmt::print("Default format: {} {}\n", 42s, 100ms);
// Prints "strftime-like format: 03:15:30":
fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s);
}
.. doxygenfunction:: localtime(std::time_t time)
.. doxygenfunction:: gmtime(std::time_t time)
.. _std-api:
Standard Library Types Formatting
=================================
``fmt/std.h`` provides formatters for:
* `std::filesystem::path <https://en.cppreference.com/w/cpp/filesystem/path>`_
* `std::thread::id <https://en.cppreference.com/w/cpp/thread/thread/id>`_
* `std::monostate <https://en.cppreference.com/w/cpp/utility/variant/monostate>`_
* `std::variant <https://en.cppreference.com/w/cpp/utility/variant/variant>`_
* `std::optional <https://en.cppreference.com/w/cpp/utility/optional>`_
Formatting Variants
-------------------
A ``std::variant`` is only formattable if every variant alternative is formattable, and requires the
``__cpp_lib_variant`` `library feature <https://en.cppreference.com/w/cpp/feature_test>`_.
**Example**::
#include <fmt/std.h>
std::variant<char, float> v0{'x'};
// Prints "variant('x')"
fmt::print("{}", v0);
std::variant<std::monostate, char> v1;
// Prints "variant(monostate)"
.. _compile-api:
Format String Compilation
=========================
``fmt/compile.h`` provides format string compilation enabled via the
``FMT_COMPILE`` macro or the ``_cf`` user-defined literal. Format strings
marked with ``FMT_COMPILE`` or ``_cf`` are parsed, checked and converted into
efficient formatting code at compile-time. This supports arguments of built-in
and string types as well as user-defined types with ``format`` functions taking
the format context type as a template parameter in their ``formatter``
specializations. For example::
template <> struct fmt::formatter<point> {
constexpr auto parse(format_parse_context& ctx);
template <typename FormatContext>
auto format(const point& p, FormatContext& ctx) const;
};
Format string compilation can generate more binary code compared to the default
API and is only recommended in places where formatting is a performance
bottleneck.
.. doxygendefine:: FMT_COMPILE
.. doxygenfunction:: operator""_cf()
.. _color-api:
Terminal Color and Text Style
=============================
``fmt/color.h`` provides support for terminal color and text style output.
.. doxygenfunction:: print(const text_style &ts, const S &format_str, const Args&... args)
.. doxygenfunction:: fg(detail::color_type)
.. doxygenfunction:: bg(detail::color_type)
.. doxygenfunction:: styled(const T& value, text_style ts)
.. _os-api:
System APIs
===========
.. doxygenclass:: fmt::ostream
:members:
.. doxygenfunction:: fmt::windows_error
:members:
.. _ostream-api:
@ -397,24 +600,28 @@ The format string syntax is described in the documentation of
========================
``fmt/ostream.h`` provides ``std::ostream`` support including formatting of
user-defined types that have overloaded ``operator<<``::
user-defined types that have an overloaded insertion operator (``operator<<``).
In order to make a type formattable via ``std::ostream`` you should provide a
``formatter`` specialization inherited from ``ostream_formatter``::
#include <fmt/ostream.h>
class date {
int year_, month_, day_;
public:
date(int year, int month, int day): year_(year), month_(month), day_(day) {}
struct date {
int year, month, day;
friend std::ostream& operator<<(std::ostream& os, const date& d) {
return os << d.year_ << '-' << d.month_ << '-' << d.day_;
return os << d.year << '-' << d.month << '-' << d.day;
}
};
std::string s = fmt::format("The date is {}", date(2012, 12, 9));
template <> struct fmt::formatter<date> : ostream_formatter {};
std::string s = fmt::format("The date is {}", date{2012, 12, 9});
// s == "The date is 2012-12-9"
.. doxygenfunction:: print(std::basic_ostream<Char>&, const S&, Args&&...)
.. doxygenfunction:: streamed(const T &)
.. doxygenfunction:: print(std::ostream &os, format_string<T...> fmt, T&&... args)
.. _printf-api:
@ -423,15 +630,42 @@ user-defined types that have overloaded ``operator<<``::
The header ``fmt/printf.h`` provides ``printf``-like formatting functionality.
The following functions use `printf format string syntax
<http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html>`_ with
<https://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html>`_ with
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(const S&, const Args&...)
.. doxygenfunction:: printf(string_view fmt, const T&... args) -> int
.. doxygenfunction:: fprintf(std::FILE *, const S&, const Args&...)
.. doxygenfunction:: fprintf(std::FILE *f, const S &fmt, const T&... args) -> int
.. doxygenfunction:: fprintf(std::basic_ostream<Char>&, const S&, const Args&...)
.. doxygenfunction:: sprintf(const S&, const T&...)
.. doxygenfunction:: sprintf(const S&, const Args&...)
.. _xchar-api:
``wchar_t`` Support
===================
The optional header ``fmt/xchar.h`` provides support for ``wchar_t`` and exotic
character types.
.. doxygenstruct:: fmt::is_char
.. doxygentypedef:: fmt::wstring_view
.. doxygentypedef:: fmt::wformat_context
.. doxygenfunction:: fmt::to_wstring(const T &value)
Compatibility with C++20 ``std::format``
========================================
{fmt} implements nearly all of the `C++20 formatting library
<https://en.cppreference.com/w/cpp/utility/format>`_ with the following
differences:
* Names are defined in the ``fmt`` namespace instead of ``std`` to avoid
collisions with standard library implementations.
* Width calculation doesn't use grapheme clusterization. The latter has been
implemented in a separate branch but hasn't been integrated yet.
* Most C++20 chrono types are not supported yet.

View File

@ -90,12 +90,14 @@
VERSION: '{{ release|e }}',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
LINK_SUFFIX: '{{ link_suffix }}',
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}',
HAS_SOURCE: {{ has_source|lower }},
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
};
</script>
{%- for scriptfile in script_files %}
<script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
{{ js_tag(scriptfile) }}
{%- endfor %}
{%- endmacro %}

View File

@ -1,63 +1,38 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# Build the documentation.
from __future__ import print_function
import errno, os, shutil, sys, tempfile
from subprocess import check_call, check_output, CalledProcessError, Popen, PIPE
from distutils.version import LooseVersion
import errno, os, re, sys
from subprocess import check_call, CalledProcessError, Popen, PIPE, STDOUT
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', '5.2.0', '5.2.1', '5.3.0', '6.0.0', '6.1.0', '6.1.1']
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', '5.2.0', '5.2.1', '5.3.0', '6.0.0', '6.1.0', '6.1.1', '6.1.2', '6.2.0', '6.2.1', '7.0.0', '7.0.1', '7.0.2', '7.0.3', '7.1.0', '7.1.1', '7.1.2', '7.1.3', '8.0.0', '8.0.1', '8.1.0', '8.1.1', '9.0.0', '9.1.0', '10.0.0', '10.1.0']
def pip_install(package, commit=None, **kwargs):
"Install package using pip."
min_version = kwargs.get('min_version')
if min_version:
from pkg_resources import get_distribution, DistributionNotFound
try:
installed_version = get_distribution(os.path.basename(package)).version
if LooseVersion(installed_version) >= min_version:
print('{} {} already installed'.format(package, min_version))
return
except DistributionNotFound:
pass
if commit:
package = 'git+https://github.com/{0}.git@{1}'.format(package, commit)
print('Installing {0}'.format(package))
check_call(['pip', 'install', package])
class Pip:
def __init__(self, venv_dir):
self.path = os.path.join(venv_dir, 'bin', 'pip')
def create_build_env(dirname='virtualenv'):
def install(self, package, commit=None):
"Install package using pip."
if commit:
package = 'git+https://github.com/{0}.git@{1}'.format(package, commit)
print('Installing {0}'.format(package))
check_call([self.path, 'install', package])
def create_build_env(venv_dir='virtualenv'):
# Create virtualenv.
if not os.path.exists(dirname):
check_call(['virtualenv', dirname])
import sysconfig
scripts_dir = os.path.basename(sysconfig.get_path('scripts'))
activate_this_file = os.path.join(dirname, scripts_dir, 'activate_this.py')
with open(activate_this_file) as f:
exec(f.read(), dict(__file__=activate_this_file))
# Import get_distribution after activating virtualenv to get info about
# the correct packages.
from pkg_resources import get_distribution, DistributionNotFound
# Upgrade pip because installation of sphinx with pip 1.1 available on Travis
# is broken (see #207) and it doesn't support the show command.
pip_version = get_distribution('pip').version
if LooseVersion(pip_version) < LooseVersion('1.5.4'):
print("Updating pip")
check_call(['pip', 'install', '--upgrade', 'pip'])
# Upgrade distribute because installation of sphinx with distribute 0.6.24
# available on Travis is broken (see #207).
try:
distribute_version = get_distribution('distribute').version
if LooseVersion(distribute_version) <= LooseVersion('0.6.24'):
print("Updating distribute")
check_call(['pip', 'install', '--upgrade', 'distribute'])
except DistributionNotFound:
pass
# Install Sphinx and Breathe.
pip_install('sphinx-doc/sphinx', '12b83372ac9316e8cbe86e7fed889296a4cc29ee',
min_version='1.4.1.dev20160531')
pip_install('michaeljones/breathe',
'129222318f7c8f865d2631e7da7b033567e7f56a',
min_version='4.2.0')
if not os.path.exists(venv_dir):
check_call(['python3', '-m', 'venv', venv_dir])
# Install Sphinx and Breathe. Require the exact version of Sphinx which is
# compatible with Breathe.
pip = Pip(venv_dir)
pip.install('wheel')
pip.install('six')
# See: https://github.com/sphinx-doc/sphinx/issues/9777
pip.install('docutils==0.17.1')
# Jinja2 >= 3.1 incompatible with sphinx 3.3.0
# See: https://github.com/sphinx-doc/sphinx/issues/10291
pip.install('Jinja2<3.1')
pip.install('sphinx-doc/sphinx', 'v3.3.0')
pip.install('michaeljones/breathe', 'v4.25.0')
def build_docs(version='dev', **kwargs):
doc_dir = kwargs.get('doc_dir', os.path.dirname(os.path.realpath(__file__)))
@ -66,16 +41,17 @@ def build_docs(version='dev', **kwargs):
'include_dir', os.path.join(os.path.dirname(doc_dir), 'include', 'fmt'))
# Build docs.
cmd = ['doxygen', '-']
p = Popen(cmd, stdin=PIPE)
p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
doxyxml_dir = os.path.join(work_dir, 'doxyxml')
p.communicate(input=r'''
out, _ = p.communicate(input=r'''
PROJECT_NAME = fmt
GENERATE_LATEX = NO
GENERATE_MAN = NO
GENERATE_RTF = NO
CASE_SENSE_NAMES = NO
INPUT = {0}/core.h {0}/format.h {0}/ostream.h \
{0}/printf.h {0}/time.h
INPUT = {0}/args.h {0}/chrono.h {0}/color.h {0}/core.h \
{0}/compile.h {0}/format.h {0}/os.h {0}/ostream.h \
{0}/printf.h {0}/xchar.h
QUIET = YES
JAVADOC_AUTOBRIEF = YES
AUTOLINK_SUPPORT = NO
@ -86,28 +62,49 @@ def build_docs(version='dev', **kwargs):
ALIASES += "endrst=\endverbatim"
MACRO_EXPANSION = YES
PREDEFINED = _WIN32=1 \
__linux__=1 \
FMT_ENABLE_IF(...)= \
FMT_USE_VARIADIC_TEMPLATES=1 \
FMT_USE_RVALUE_REFERENCES=1 \
FMT_USE_USER_DEFINED_LITERALS=1 \
FMT_USE_ALIAS_TEMPLATES=1 \
FMT_USE_NONTYPE_TEMPLATE_ARGS=1 \
FMT_API= \
"FMT_BEGIN_NAMESPACE=namespace fmt {{" \
"FMT_END_NAMESPACE=}}" \
"FMT_STRING_ALIAS=1" \
"FMT_ENABLE_IF(B)="
EXCLUDE_SYMBOLS = fmt::internal::* StringValue write_str
"FMT_VARIADIC(...)=" \
"FMT_VARIADIC_W(...)=" \
"FMT_DOC=1"
EXCLUDE_SYMBOLS = fmt::formatter fmt::printf_formatter fmt::arg_join \
fmt::basic_format_arg::handle
'''.format(include_dir, doxyxml_dir).encode('UTF-8'))
out = out.decode('utf-8')
internal_symbols = [
'fmt::detail::.*',
'basic_data<>',
'fmt::type_identity'
]
noisy_warnings = [
'warning: (Compound|Member .* of class) (' + '|'.join(internal_symbols) + \
') is not documented.',
'warning: Internal inconsistency: .* does not belong to any container!'
]
for w in noisy_warnings:
out = re.sub('.*' + w + '\n', '', out)
print(out)
if p.returncode != 0:
raise CalledProcessError(p.returncode, cmd)
html_dir = os.path.join(work_dir, 'html')
main_versions = reversed(versions[-3:])
check_call(['sphinx-build',
check_call([os.path.join(work_dir, 'virtualenv', 'bin', 'sphinx-build'),
'-Dbreathe_projects.format=' + os.path.abspath(doxyxml_dir),
'-Dversion=' + version, '-Drelease=' + version,
'-Aversion=' + version, '-Aversions=' + ','.join(main_versions),
'-b', 'html', doc_dir, html_dir])
try:
check_call(['lessc', '--clean-css',
check_call(['lessc', '--verbose', '--clean-css',
'--include-path=' + os.path.join(doc_dir, 'bootstrap'),
os.path.join(doc_dir, 'fmt.less'),
os.path.join(html_dir, '_static', 'fmt.css')])

View File

@ -56,6 +56,11 @@ div.sphinxsidebar {
padding: 0;
}
// Override center alignment in tables.
td {
text-align: left;
}
p.rubric {
margin-top: 10px;
}

View File

@ -10,7 +10,7 @@ alternative to C stdio and C++ iostreams.
<div class="panel-heading">What users say:</div>
<div class="panel-body">
Thanks for creating this library. Its been a hole in C++ for
aa long time. Ive used both <code>boost::format</code> and
a long time. Ive used both <code>boost::format</code> and
<code>loki::SPrintf</code>, and neither felt like the right answer.
This does.
</div>
@ -22,25 +22,27 @@ Format API
----------
The format API is similar in spirit to the C ``printf`` family of function but
is safer, simpler and serveral times `faster
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_
is safer, simpler and several times `faster
<https://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html>`_
than common standard library implementations.
The `format string syntax <syntax.html>`_ is similar to the one used by
`str.format <http://docs.python.org/3/library/stdtypes.html#str.format>`_ in
`str.format <https://docs.python.org/3/library/stdtypes.html#str.format>`_ in
Python:
.. code:: c++
fmt::format("The answer is {}.", 42);
std::string s = fmt::format("The answer is {}.", 42);
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::memory_buffer out;
format_to(out, "For a moment, {} happened.", "nothing");
out.data(); // returns a pointer to the formatted data
auto out = fmt::memory_buffer();
fmt::format_to(std::back_inserter(out),
"For a moment, {} happened.", "nothing");
auto data = out.data(); // pointer to the formatted data
auto size = out.size(); // size of the formatted data
The ``fmt::print`` function performs formatting and writes the result to a stream:
@ -48,21 +50,19 @@ The ``fmt::print`` function performs formatting and writes the result to a strea
fmt::print(stderr, "System error code = {}\n", errno);
The file argument can be omitted in which case the function prints to
``stdout``:
If you omit the file argument the function will print to ``stdout``:
.. code:: c++
fmt::print("Don't {}\n", "panic");
The Format API also supports positional arguments useful for localization:
The format API also supports positional arguments useful for localization:
.. code:: c++
fmt::print("I'd rather be {1} than {0}.", "right", "happy");
Named arguments can be created with ``fmt::arg``. This makes it easier to track
what goes where when multiple arguments are being formatted:
You can pass named arguments with ``fmt::arg``:
.. code:: c++
@ -91,16 +91,17 @@ time. For example, the code
fmt::format("The answer is {:d}", "forty-two");
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
throws the ``format_error`` exception because the argument ``"forty-two"`` is a
string while the format code ``d`` only applies to integers.
The code
.. code:: c++
format(FMT_STRING("The answer is {:d}"), "forty-two");
reports a compile-time error for the same reason on compilers that support
relaxed ``constexpr``. See `here <api.html#c.fmt>`_ for details.
reports a compile-time error on compilers that support relaxed ``constexpr``.
See `here <api.html#compile-time-format-string-checks>`_ for details.
The following code
@ -109,21 +110,15 @@ The following code
fmt::format("Cyrillic letter {}", L'\x42e');
produces a compile-time error because wide character ``L'\x42e'`` cannot be
formatted into a narrow string. You can use a wide format string instead:
.. code:: c++
fmt::format(L"Cyrillic letter {}", L'\x42e');
For comparison, writing a wide character to ``std::ostream`` results in
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.
formatted into a narrow string. For comparison, writing a wide character to
``std::ostream`` results in 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 desirable.
Compact Binary Code
-------------------
The library is designed to produce compact per-call compiled code. For example
The library produces compact per-call compiled code. For example
(`godbolt <https://godbolt.org/g/TZU4KF>`_),
.. code:: c++
@ -144,8 +139,8 @@ compiles to just
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)
mov edx, 1
call fmt::v7::vprint(fmt::v7::basic_string_view<char>, fmt::v7::format_args)
xor eax, eax
add rsp, 24
ret
@ -167,20 +162,19 @@ The library is highly portable and relies only on a small set of C++11 features:
* deleted functions
* alias templates
These are available since GCC 4.8, Clang 3.0 and MSVC 19.0 (2015). 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.
These are available in GCC 4.8, Clang 3.4, MSVC 19.0 (2015) and more recent
compiler version. For older compilers use {fmt} `version 4.x
<https://github.com/fmtlib/fmt/releases/tag/4.1.0>`_ which is 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
output of ``printf`` is platform-dependent. For example,
The output of all formatting functions is consistent across platforms.
For example,
.. code::
fmt::print("{}", std::numeric_limits<double>::infinity());
always prints ``inf``.
always prints ``inf`` while the output of ``printf`` is platform-dependent.
.. _ease-of-use:
@ -192,11 +186,13 @@ just three header files and no external dependencies.
A permissive MIT `license <https://github.com/fmtlib/fmt#license>`_ allows
using the library both in open-source and commercial projects.
`Learn more... <contents.html>`_
.. raw:: html
<a class="btn btn-success" href="https://github.com/fmtlib/fmt">GitHub Repository</a>
<div class="section footer">
<iframe src="http://ghbtns.com/github-btn.html?user=fmtlib&amp;repo=fmt&amp;type=watch&amp;count=true"
<iframe src="https://ghbtns.com/github-btn.html?user=fmtlib&amp;repo=fmt&amp;type=watch&amp;count=true"
class="github-btn" width="100" height="20"></iframe>
</div>

View File

@ -16,7 +16,7 @@ literal text, it can be escaped by doubling: ``{{`` and ``}}``.
The grammar for a replacement field is as follows:
.. productionlist:: sf
replacement_field: "{" [`arg_id`] [":" `format_spec`] "}"
replacement_field: "{" [`arg_id`] [":" (`format_spec` | `chrono_format_spec`)] "}"
arg_id: `integer` | `identifier`
integer: `digit`+
digit: "0"..."9"
@ -27,8 +27,8 @@ The grammar for a replacement field is as follows:
In less formal terms, the replacement field can start with an *arg_id*
that specifies the argument whose value is to be formatted and inserted into
the output instead of the replacement field.
The *arg_id* is optionally followed by a *format_spec*, which is preceded
by a colon ``':'``. These specify a non-default format for the replacement value.
The *arg_id* is optionally followed by a *format_spec*, which is preceded by a
colon ``':'``. These specify a non-default format for the replacement value.
See also the :ref:`formatspec` section.
@ -75,20 +75,20 @@ although some of the formatting options are only supported by the numeric types.
The general form of a *standard format specifier* is:
.. productionlist:: sf
format_spec: [[`fill`]`align`][`sign`]["#"]["0"][`width`]["." `precision`][`type`]
fill: <a character other than '{', '}' or '\0'>
align: "<" | ">" | "=" | "^"
format_spec: [[`fill`]`align`][`sign`]["#"]["0"][`width`]["." `precision`]["L"][`type`]
fill: <a character other than '{' or '}'>
align: "<" | ">" | "^"
sign: "+" | "-" | " "
width: `integer` | "{" `arg_id` "}"
precision: `integer` | "{" `arg_id` "}"
type: `int_type` | "a" | "A" | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s"
int_type: "b" | "B" | "d" | "n" | "o" | "x" | "X"
width: `integer` | "{" [`arg_id`] "}"
precision: `integer` | "{" [`arg_id`] "}"
type: "a" | "A" | "b" | "B" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" |
: "o" | "p" | "s" | "x" | "X"
The *fill* character can be any character other than '{', '}' or '\\0'. The
presence of a fill character is signaled by the character following it, which
must be one of the alignment options. If the second character of *format_spec*
is not a valid alignment option, then it is assumed that both the fill character
and the alignment option are absent.
The *fill* character can be any Unicode code point other than ``'{'`` or
``'}'``. The presence of a fill character is signaled by the character following
it, which must be one of the alignment options. If the second character of
*format_spec* is not a valid alignment option, then it is assumed that both the
fill character and the alignment option are absent.
The meaning of the various alignment options is as follows:
@ -109,21 +109,21 @@ Note that unless a minimum field width is defined, the field width will always
be the same size as the data to fill it, so that the alignment option has no
meaning in this case.
The *sign* option is only valid for number types, and can be one of the
following:
The *sign* option is only valid for floating point and signed integer types,
and can be one of the following:
+---------+----------------------------------------------------------+
| Option | Meaning |
+=========+==========================================================+
| ``'+'`` | indicates that a sign should be used for both |
| | positive as well as negative numbers. |
+---------+----------------------------------------------------------+
| ``'-'`` | indicates that a sign should be used only for negative |
| | numbers (this is the default behavior). |
+---------+----------------------------------------------------------+
| space | indicates that a leading space should be used on |
| | positive numbers, and a minus sign on negative numbers. |
+---------+----------------------------------------------------------+
+---------+------------------------------------------------------------+
| Option | Meaning |
+=========+============================================================+
| ``'+'`` | indicates that a sign should be used for both |
| | nonnegative as well as negative numbers. |
+---------+------------------------------------------------------------+
| ``'-'`` | indicates that a sign should be used only for negative |
| | numbers (this is the default behavior). |
+---------+------------------------------------------------------------+
| space | indicates that a leading space should be used on |
| | nonnegative numbers, and a minus sign on negative numbers. |
+---------+------------------------------------------------------------+
The ``'#'`` option causes the "alternate form" to be used for the
conversion. The alternate form is defined differently for different
@ -143,7 +143,7 @@ conversions, trailing zeros are not removed from the result.
.. ifconfig:: False
The ``','`` option signals the use of a comma for a thousands separator.
For a locale aware separator, use the ``'n'`` integer presentation type
For a locale aware separator, use the ``'L'`` integer presentation type
instead.
*width* is a decimal integer defining the minimum field width. If not
@ -161,7 +161,11 @@ displayed after the decimal point for a floating-point value formatted with
value formatted with ``'g'`` or ``'G'``. For non-number types the field
indicates the maximum field size - in other words, how many characters will be
used from the field content. The *precision* is not allowed for integer,
character, Boolean, and pointer values.
character, Boolean, and pointer values. Note that a C string must be
null-terminated even if precision is specified.
The ``'L'`` option uses the current locale setting to insert the appropriate
number separator characters. This option is only valid for numeric types.
Finally, the *type* determines how the data should be presented.
@ -200,6 +204,8 @@ The available integer presentation types are:
| | ``'#'`` option with this type adds the prefix ``"0B"`` |
| | to the output value. |
+---------+----------------------------------------------------------+
| ``'c'`` | Character format. Outputs the number as a character. |
+---------+----------------------------------------------------------+
| ``'d'`` | Decimal integer. Outputs the number in base 10. |
+---------+----------------------------------------------------------+
| ``'o'`` | Octal format. Outputs the number in base 8. |
@ -214,10 +220,6 @@ The available integer presentation types are:
| | ``'#'`` option with this type adds the prefix ``"0X"`` |
| | to the output value. |
+---------+----------------------------------------------------------+
| ``'n'`` | Number. This is the same as ``'d'``, except that it uses |
| | the current locale setting to insert the appropriate |
| | number separator characters. |
+---------+----------------------------------------------------------+
| none | The same as ``'d'``. |
+---------+----------------------------------------------------------+
@ -261,18 +263,8 @@ The available presentation types for floating-point values are:
| | ``'E'`` if the number gets too large. The |
| | representations of infinity and NaN are uppercased, too. |
+---------+----------------------------------------------------------+
| ``'n'`` | Number. This is the same as ``'g'``, except that it uses |
| | the current locale setting to insert the appropriate |
| | number separator characters. |
+---------+----------------------------------------------------------+
| ``'%'`` | Fixed point as a percentage. This is similar to ``'f'``, |
| | but the argument is multiplied by 100 and a percent sign |
| | ``%`` is appended. |
+---------+----------------------------------------------------------+
| none | Similar to ``'g'``, except that fixed-point notation, |
| | when used, has at least one digit past the decimal |
| | point. The default precision is as high as needed to |
| | represent the particular value. |
| none | Similar to ``'g'``, except that the default precision is |
| | as high as needed to represent the particular value. |
+---------+----------------------------------------------------------+
.. ifconfig:: False
@ -307,6 +299,212 @@ The available presentation types for pointers are:
| none | The same as ``'p'``. |
+---------+----------------------------------------------------------+
.. _chrono-specs:
Chrono Format Specifications
============================
Format specifications for chrono duration and time point types as well as
``std::tm`` have the following syntax:
.. productionlist:: sf
chrono_format_spec: [[`fill`]`align`][`width`]["." `precision`][`chrono_specs`]
chrono_specs: [`chrono_specs`] `conversion_spec` | `chrono_specs` `literal_char`
conversion_spec: "%" [`modifier`] `chrono_type`
literal_char: <a character other than '{', '}' or '%'>
modifier: "E" | "O"
chrono_type: "a" | "A" | "b" | "B" | "c" | "C" | "d" | "D" | "e" | "F" |
: "g" | "G" | "h" | "H" | "I" | "j" | "m" | "M" | "n" | "p" |
: "q" | "Q" | "r" | "R" | "S" | "t" | "T" | "u" | "U" | "V" |
: "w" | "W" | "x" | "X" | "y" | "Y" | "z" | "Z" | "%"
Literal chars are copied unchanged to the output. Precision is valid only for
``std::chrono::duration`` types with a floating-point representation type.
The available presentation types (*chrono_type*) are:
+---------+--------------------------------------------------------------------+
| Type | Meaning |
+=========+====================================================================+
| ``'a'`` | The abbreviated weekday name, e.g. "Sat". If the value does not |
| | contain a valid weekday, an exception of type ``format_error`` is |
| | thrown. |
+---------+--------------------------------------------------------------------+
| ``'A'`` | The full weekday name, e.g. "Saturday". If the value does not |
| | contain a valid weekday, an exception of type ``format_error`` is |
| | thrown. |
+---------+--------------------------------------------------------------------+
| ``'b'`` | The abbreviated month name, e.g. "Nov". If the value does not |
| | contain a valid month, an exception of type ``format_error`` is |
| | thrown. |
+---------+--------------------------------------------------------------------+
| ``'B'`` | The full month name, e.g. "November". If the value does not |
| | contain a valid month, an exception of type ``format_error`` is |
| | thrown. |
+---------+--------------------------------------------------------------------+
| ``'c'`` | The date and time representation, e.g. "Sat Nov 12 22:04:00 1955". |
| | The modified command ``%Ec`` produces the locale's alternate date |
| | and time representation. |
+---------+--------------------------------------------------------------------+
| ``'C'`` | The year divided by 100 using floored division, e.g. "55". If the |
| | result is a single decimal digit, it is prefixed with 0. |
| | The modified command ``%EC`` produces the locale's alternative |
| | representation of the century. |
+---------+--------------------------------------------------------------------+
| ``'d'`` | The day of month as a decimal number. If the result is a single |
| | decimal digit, it is prefixed with 0. The modified command ``%Od`` |
| | produces the locale's alternative representation. |
+---------+--------------------------------------------------------------------+
| ``'D'`` | Equivalent to ``%m/%d/%y``, e.g. "11/12/55". |
+---------+--------------------------------------------------------------------+
| ``'e'`` | The day of month as a decimal number. If the result is a single |
| | decimal digit, it is prefixed with a space. The modified command |
| | ``%Oe`` produces the locale's alternative representation. |
+---------+--------------------------------------------------------------------+
| ``'F'`` | Equivalent to ``%Y-%m-%d``, e.g. "1955-11-12". |
+---------+--------------------------------------------------------------------+
| ``'g'`` | The last two decimal digits of the ISO week-based year. If the |
| | result is a single digit it is prefixed by 0. |
+---------+--------------------------------------------------------------------+
| ``'G'`` | The ISO week-based year as a decimal number. If the result is less |
| | than four digits it is left-padded with 0 to four digits. |
+---------+--------------------------------------------------------------------+
| ``'h'`` | Equivalent to ``%b``, e.g. "Nov". |
+---------+--------------------------------------------------------------------+
| ``'H'`` | The hour (24-hour clock) as a decimal number. If the result is a |
| | single digit, it is prefixed with 0. The modified command ``%OH`` |
| | produces the locale's alternative representation. |
+---------+--------------------------------------------------------------------+
| ``'I'`` | The hour (12-hour clock) as a decimal number. If the result is a |
| | single digit, it is prefixed with 0. The modified command ``%OI`` |
| | produces the locale's alternative representation. |
+---------+--------------------------------------------------------------------+
| ``'j'`` | If the type being formatted is a specialization of duration, the |
| | decimal number of days without padding. Otherwise, the day of the |
| | year as a decimal number. Jan 1 is 001. If the result is less than |
| | three digits, it is left-padded with 0 to three digits. |
+---------+--------------------------------------------------------------------+
| ``'m'`` | The month as a decimal number. Jan is 01. If the result is a |
| | single digit, it is prefixed with 0. The modified command ``%Om`` |
| | produces the locale's alternative representation. |
+---------+--------------------------------------------------------------------+
| ``'M'`` | The minute as a decimal number. If the result is a single digit, |
| | it is prefixed with 0. The modified command ``%OM`` produces the |
| | locale's alternative representation. |
+---------+--------------------------------------------------------------------+
| ``'n'`` | A new-line character. |
+---------+--------------------------------------------------------------------+
| ``'p'`` | The AM/PM designations associated with a 12-hour clock. |
+---------+--------------------------------------------------------------------+
| ``'q'`` | The duration's unit suffix. |
+---------+--------------------------------------------------------------------+
| ``'Q'`` | The duration's numeric value (as if extracted via ``.count()``). |
+---------+--------------------------------------------------------------------+
| ``'r'`` | The 12-hour clock time, e.g. "10:04:00 PM". |
+---------+--------------------------------------------------------------------+
| ``'R'`` | Equivalent to ``%H:%M``, e.g. "22:04". |
+---------+--------------------------------------------------------------------+
| ``'S'`` | Seconds as a decimal number. If the number of seconds is less than |
| | 10, the result is prefixed with 0. If the precision of the input |
| | cannot be exactly represented with seconds, then the format is a |
| | decimal floating-point number with a fixed format and a precision |
| | matching that of the precision of the input (or to a microseconds |
| | precision if the conversion to floating-point decimal seconds |
| | cannot be made within 18 fractional digits). The character for the |
| | decimal point is localized according to the locale. The modified |
| | command ``%OS`` produces the locale's alternative representation. |
+---------+--------------------------------------------------------------------+
| ``'t'`` | A horizontal-tab character. |
+---------+--------------------------------------------------------------------+
| ``'T'`` | Equivalent to ``%H:%M:%S``. |
+---------+--------------------------------------------------------------------+
| ``'u'`` | The ISO weekday as a decimal number (1-7), where Monday is 1. The |
| | modified command ``%Ou`` produces the locale's alternative |
| | representation. |
+---------+--------------------------------------------------------------------+
| ``'U'`` | The week number of the year as a decimal number. The first Sunday |
| | of the year is the first day of week 01. Days of the same year |
| | prior to that are in week 00. If the result is a single digit, it |
| | is prefixed with 0. The modified command ``%OU`` produces the |
| | locale's alternative representation. |
+---------+--------------------------------------------------------------------+
| ``'V'`` | The ISO week-based week number as a decimal number. If the result |
| | is a single digit, it is prefixed with 0. The modified command |
| | ``%OV`` produces the locale's alternative representation. |
+---------+--------------------------------------------------------------------+
| ``'w'`` | The weekday as a decimal number (0-6), where Sunday is 0. |
| | The modified command ``%Ow`` produces the locale's alternative |
| | representation. |
+---------+--------------------------------------------------------------------+
| ``'W'`` | The week number of the year as a decimal number. The first Monday |
| | of the year is the first day of week 01. Days of the same year |
| | prior to that are in week 00. If the result is a single digit, it |
| | is prefixed with 0. The modified command ``%OW`` produces the |
| | locale's alternative representation. |
+---------+--------------------------------------------------------------------+
| ``'x'`` | The date representation, e.g. "11/12/55". The modified command |
| | ``%Ex`` produces the locale's alternate date representation. |
+---------+--------------------------------------------------------------------+
| ``'X'`` | The time representation, e.g. "10:04:00". The modified command |
| | ``%EX`` produces the locale's alternate time representation. |
+---------+--------------------------------------------------------------------+
| ``'y'`` | The last two decimal digits of the year. If the result is a single |
| | digit it is prefixed by 0. The modified command ``%Oy`` produces |
| | the locale's alternative representation. The modified command |
| | ``%Ey`` produces the locale's alternative representation of offset |
| | from ``%EC`` (year only). |
+---------+--------------------------------------------------------------------+
| ``'Y'`` | The year as a decimal number. If the result is less than four |
| | digits it is left-padded with 0 to four digits. The modified |
| | command ``%EY`` produces the locale's alternative full year |
| | representation. |
+---------+--------------------------------------------------------------------+
| ``'z'`` | The offset from UTC in the ISO 8601:2004 format. For example -0430 |
| | refers to 4 hours 30 minutes behind UTC. If the offset is zero, |
| | +0000 is used. The modified commands ``%Ez`` and ``%Oz`` insert a |
| | ``:`` between the hours and minutes: -04:30. If the offset |
| | information is not available, an exception of type |
| | ``format_error`` is thrown. |
+---------+--------------------------------------------------------------------+
| ``'Z'`` | The time zone abbreviation. If the time zone abbreviation is not |
| | available, an exception of type ``format_error`` is thrown. |
+---------+--------------------------------------------------------------------+
| ``'%'`` | A % character. |
+---------+--------------------------------------------------------------------+
Specifiers that have a calendaric component such as ``'d'`` (the day of month)
are valid only for ``std::tm`` and time points but not durations.
.. range-specs:
Range Format Specifications
===========================
Format specifications for range types have the following syntax:
.. productionlist:: sf
range_format_spec: [":" [`underlying_spec`]]
The `underlying_spec` is parsed based on the formatter of the range's
reference type.
By default, a range of characters or strings is printed escaped and quoted. But
if any `underlying_spec` is provided (even if it is empty), then the characters
or strings are printed according to the provided specification.
Examples::
fmt::format("{}", std::vector{10, 20, 30});
// Result: [10, 20, 30]
fmt::format("{::#x}", std::vector{10, 20, 30});
// Result: [0xa, 0x14, 0x1e]
fmt::format("{}", vector{'h', 'e', 'l', 'l', 'o'});
// Result: ['h', 'e', 'l', 'l', 'o']
fmt::format("{::}", vector{'h', 'e', 'l', 'l', 'o'});
// Result: [h, e, l, l, o]
fmt::format("{::d}", vector{'h', 'e', 'l', 'l', 'o'});
// Result: [104, 101, 108, 108, 111]
.. _formatexamples:
Format Examples
@ -324,79 +522,94 @@ following examples.
Accessing arguments by position::
format("{0}, {1}, {2}", 'a', 'b', 'c');
fmt::format("{0}, {1}, {2}", 'a', 'b', 'c');
// Result: "a, b, c"
format("{}, {}, {}", 'a', 'b', 'c');
fmt::format("{}, {}, {}", 'a', 'b', 'c');
// Result: "a, b, c"
format("{2}, {1}, {0}", 'a', 'b', 'c');
fmt::format("{2}, {1}, {0}", 'a', 'b', 'c');
// Result: "c, b, a"
format("{0}{1}{0}", "abra", "cad"); // arguments' indices can be repeated
fmt::format("{0}{1}{0}", "abra", "cad"); // arguments' indices can be repeated
// Result: "abracadabra"
Aligning the text and specifying a width::
format("{:<30}", "left aligned");
fmt::format("{:<30}", "left aligned");
// Result: "left aligned "
format("{:>30}", "right aligned");
fmt::format("{:>30}", "right aligned");
// Result: " right aligned"
format("{:^30}", "centered");
fmt::format("{:^30}", "centered");
// Result: " centered "
format("{:*^30}", "centered"); // use '*' as a fill char
fmt::format("{:*^30}", "centered"); // use '*' as a fill char
// Result: "***********centered***********"
Dynamic width::
format("{:<{}}", "left aligned", 30);
fmt::format("{:<{}}", "left aligned", 30);
// Result: "left aligned "
Dynamic precision::
format("{:.{}f}", 3.14, 1);
fmt::format("{:.{}f}", 3.14, 1);
// Result: "3.1"
Replacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign::
format("{:+f}; {:+f}", 3.14, -3.14); // show it always
fmt::format("{:+f}; {:+f}", 3.14, -3.14); // show it always
// Result: "+3.140000; -3.140000"
format("{: f}; {: f}", 3.14, -3.14); // show a space for positive numbers
fmt::format("{: f}; {: f}", 3.14, -3.14); // show a space for positive numbers
// Result: " 3.140000; -3.140000"
format("{:-f}; {:-f}", 3.14, -3.14); // show only the minus -- same as '{:f}; {:f}'
fmt::format("{:-f}; {:-f}", 3.14, -3.14); // show only the minus -- same as '{:f}; {:f}'
// Result: "3.140000; -3.140000"
As a percentage::
format("{0:f} or {0:%}", .635);
// Result: "0.635000 or 63.500000%"
format("{:*^{}.{}%}", 1., 15, 2); // With fill, dynamic width and dynamic precision.
// Result: "****100.00%****"
Replacing ``%x`` and ``%o`` and converting the value to different bases::
format("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
fmt::format("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
// 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);
fmt::format("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42);
// Result: "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"
Padded hex byte with prefix and always prints both hex characters::
format("{:#04x}", 0);
fmt::format("{:#04x}", 0);
// Result: "0x00"
Box drawing using Unicode fill::
fmt::print(
"┌{0:─^{2}}┐\n"
"│{1: ^{2}}│\n"
"└{0:─^{2}}┘\n", "", "Hello, world!", 20);
prints::
┌────────────────────┐
│ Hello, world! │
└────────────────────┘
Using type-specific formatting::
#include <fmt/chrono.h>
auto t = tm();
t.tm_year = 2010 - 1900;
t.tm_mon = 7;
t.tm_mday = 4;
t.tm_hour = 12;
t.tm_min = 15;
t.tm_sec = 58;
fmt::print("{:%Y-%m-%d %H:%M:%S}", t);
// Prints: 2010-08-04 12:15:58
Using the comma as a thousands separator::
#include <fmt/format.h>
auto s = fmt::format(std::locale("en_US.UTF-8"), "{:L}", 1234567890);
// s == "1,234,567,890"
.. ifconfig:: False
Using the comma as a thousands separator::
format("{:,}", 1234567890);
'1,234,567,890'
Using type-specific formatting::
>>> import datetime
>>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)
Format("{:%Y-%m-%d %H:%M:%S}") << d)
'2010-07-04 12:15:58'
Nesting arguments and more complex examples::
>>> for align, text in zip('<^>', ['left', 'center', 'right']):

View File

@ -15,7 +15,7 @@ Building the Library
The included `CMake build script`__ can be used to build the fmt
library on a wide range of platforms. CMake is freely available for
download from http://www.cmake.org/download/.
download from https://www.cmake.org/download/.
__ https://github.com/fmtlib/fmt/blob/master/CMakeLists.txt
@ -50,7 +50,15 @@ To build a `shared library`__ set the ``BUILD_SHARED_LIBS`` CMake variable to
cmake -DBUILD_SHARED_LIBS=TRUE ...
__ http://en.wikipedia.org/wiki/Library_%28computing%29#Shared_libraries
__ https://en.wikipedia.org/wiki/Library_%28computing%29#Shared_libraries
To build a `static library` with position independent code (required if the main
consumer of the fmt library is a shared library i.e. a Python extension) set the
``CMAKE_POSITION_INDEPENDENT_CODE`` CMake variable to ``TRUE``::
cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE ...
Installing the Library
======================
@ -83,6 +91,49 @@ Setting up your target to use a header-only version of ``fmt`` is equally easy::
target_link_libraries(<your-target> PRIVATE fmt::fmt-header-only)
Usage with build2
=================
You can use `build2 <https://build2.org>`_, a dependency manager and a
build-system combined, to use ``fmt``.
Currently this package is available in these package repositories:
- **https://cppget.org/fmt/** for released and published versions.
- `The git repository with the sources of the build2 package of fmt <https://github.com/build2-packaging/fmt.git>`_
for unreleased or custom revisions of ``fmt``.
**Usage:**
- ``build2`` package name: ``fmt``
- Library target name : ``lib{fmt}``
For example, to make your ``build2`` project depend on ``fmt``:
- Add one of the repositories to your configurations, or in your
``repositories.manifest``, if not already there::
:
role: prerequisite
location: https://pkg.cppget.org/1/stable
- Add this package as a dependency to your ``./manifest`` file
(example for ``v7.0.x``)::
depends: fmt ~7.0.0
- Import the target and use it as a prerequisite to your own target
using `fmt` in the appropriate ``buildfile``::
import fmt = fmt%lib{fmt}
lib{mylib} : cxx{**} ... $fmt
Then build your project as usual with `b` or `bdep update`.
For ``build2`` newcomers or to get more details and use cases, you can read the
``build2``
`toolchain introduction <https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml>`_.
Building the Documentation
==========================
@ -114,6 +165,34 @@ fmt can be installed on Linux, macOS and Windows with
conda install -c conda-forge fmt
Vcpkg
=====
You can download and install fmt using the `vcpkg
<https://github.com/Microsoft/vcpkg>`__ dependency manager::
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install fmt
The fmt port in vcpkg is kept up to date by Microsoft team members and community
contributors. If the version is out of date, please `create an issue or pull
request <https://github.com/Microsoft/vcpkg>`__ on the vcpkg repository.
LHelper
=======
You can download and install fmt using
`lhelper <https://github.com/franko/lhelper>`__ dependency manager::
lhelper activate <some-environment>
lhelper install fmt
All the recipes for lhelper are kept in the
`lhelper's recipe <https://github.com/franko/lhelper-recipes>`__ repository.
Android NDK
===========
@ -123,11 +202,11 @@ For an example of using fmt with Android NDK, see the
`android-ndk-example <https://github.com/fmtlib/android-ndk-example>`_
repository.
__ https://github.com/fmtlib/fmt/blob/master/Android.mk
__ https://github.com/fmtlib/fmt/blob/master/support/Android.mk
Homebrew
========
fmt can be installed on OS X using `Homebrew <http://brew.sh/>`_::
fmt can be installed on OS X using `Homebrew <https://brew.sh/>`_::
brew install fmt

234
include/fmt/args.h Normal file
View File

@ -0,0 +1,234 @@
// Formatting library for C++ - dynamic argument lists
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_ARGS_H_
#define FMT_ARGS_H_
#include <functional> // std::reference_wrapper
#include <memory> // std::unique_ptr
#include <vector>
#include "core.h"
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename T> struct is_reference_wrapper : std::false_type {};
template <typename T>
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
template <typename T> const T& unwrap(const T& v) { return v; }
template <typename T> const T& unwrap(const std::reference_wrapper<T>& v) {
return static_cast<const T&>(v);
}
class dynamic_arg_list {
// Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
// templates it doesn't complain about inability to deduce single translation
// unit for placing vtable. So storage_node_base is made a fake template.
template <typename = void> struct node {
virtual ~node() = default;
std::unique_ptr<node<>> next;
};
template <typename T> struct typed_node : node<> {
T value;
template <typename Arg>
FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
template <typename Char>
FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
: value(arg.data(), arg.size()) {}
};
std::unique_ptr<node<>> head_;
public:
template <typename T, typename Arg> const T& push(const Arg& arg) {
auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
auto& value = new_node->value;
new_node->next = std::move(head_);
head_ = std::move(new_node);
return value;
}
};
} // namespace detail
/**
\rst
A dynamic version of `fmt::format_arg_store`.
It's equipped with a storage to potentially temporary objects which lifetimes
could be shorter than the format arguments object.
It can be implicitly converted into `~fmt::basic_format_args` for passing
into type-erased formatting functions such as `~fmt::vformat`.
\endrst
*/
template <typename Context>
class dynamic_format_arg_store
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround a GCC template argument substitution bug.
: public basic_format_args<Context>
#endif
{
private:
using char_type = typename Context::char_type;
template <typename T> struct need_copy {
static constexpr detail::type mapped_type =
detail::mapped_type_constant<T, Context>::value;
enum {
value = !(detail::is_reference_wrapper<T>::value ||
std::is_same<T, basic_string_view<char_type>>::value ||
std::is_same<T, detail::std_string_view<char_type>>::value ||
(mapped_type != detail::type::cstring_type &&
mapped_type != detail::type::string_type &&
mapped_type != detail::type::custom_type))
};
};
template <typename T>
using stored_type = conditional_t<
std::is_convertible<T, std::basic_string<char_type>>::value &&
!detail::is_reference_wrapper<T>::value,
std::basic_string<char_type>, T>;
// Storage of basic_format_arg must be contiguous.
std::vector<basic_format_arg<Context>> data_;
std::vector<detail::named_arg_info<char_type>> named_info_;
// Storage of arguments not fitting into basic_format_arg must grow
// without relocation because items in data_ refer to it.
detail::dynamic_arg_list dynamic_args_;
friend class basic_format_args<Context>;
unsigned long long get_types() const {
return detail::is_unpacked_bit | data_.size() |
(named_info_.empty()
? 0ULL
: static_cast<unsigned long long>(detail::has_named_args_bit));
}
const basic_format_arg<Context>* data() const {
return named_info_.empty() ? data_.data() : data_.data() + 1;
}
template <typename T> void emplace_arg(const T& arg) {
data_.emplace_back(detail::make_arg<Context>(arg));
}
template <typename T>
void emplace_arg(const detail::named_arg<char_type, T>& arg) {
if (named_info_.empty()) {
constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr};
data_.insert(data_.begin(), {zero_ptr, 0});
}
data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value)));
auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
data->pop_back();
};
std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)>
guard{&data_, pop_one};
named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
data_[0].value_.named_args = {named_info_.data(), named_info_.size()};
guard.release();
}
public:
constexpr dynamic_format_arg_store() = default;
/**
\rst
Adds an argument into the dynamic store for later passing to a formatting
function.
Note that custom types and string types (but not string views) are copied
into the store dynamically allocating memory if necessary.
**Example**::
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(42);
store.push_back("abc");
store.push_back(1.5f);
std::string result = fmt::vformat("{} and {} and {}", store);
\endrst
*/
template <typename T> void push_back(const T& arg) {
if (detail::const_check(need_copy<T>::value))
emplace_arg(dynamic_args_.push<stored_type<T>>(arg));
else
emplace_arg(detail::unwrap(arg));
}
/**
\rst
Adds a reference to the argument into the dynamic store for later passing to
a formatting function.
**Example**::
fmt::dynamic_format_arg_store<fmt::format_context> store;
char band[] = "Rolling Stones";
store.push_back(std::cref(band));
band[9] = 'c'; // Changing str affects the output.
std::string result = fmt::vformat("{}", store);
// result == "Rolling Scones"
\endrst
*/
template <typename T> void push_back(std::reference_wrapper<T> arg) {
static_assert(
need_copy<T>::value,
"objects of built-in types and string views are always copied");
emplace_arg(arg.get());
}
/**
Adds named argument into the dynamic store for later passing to a formatting
function. ``std::reference_wrapper`` is supported to avoid copying of the
argument. The name is always copied into the store.
*/
template <typename T>
void push_back(const detail::named_arg<char_type, T>& arg) {
const char_type* arg_name =
dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str();
if (detail::const_check(need_copy<T>::value)) {
emplace_arg(
fmt::arg(arg_name, dynamic_args_.push<stored_type<T>>(arg.value)));
} else {
emplace_arg(fmt::arg(arg_name, arg.value));
}
}
/** Erase all elements from the store */
void clear() {
data_.clear();
named_info_.clear();
dynamic_args_ = detail::dynamic_arg_list();
}
/**
\rst
Reserves space to store at least *new_cap* arguments including
*new_cap_named* named arguments.
\endrst
*/
void reserve(size_t new_cap, size_t new_cap_named) {
FMT_ASSERT(new_cap >= new_cap_named,
"Set of arguments includes set of named arguments");
data_.reserve(new_cap);
named_info_.reserve(new_cap_named);
}
};
FMT_END_NAMESPACE
#endif // FMT_ARGS_H_

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@
#include "format.h"
FMT_BEGIN_NAMESPACE
FMT_BEGIN_EXPORT
enum class color : uint32_t {
alice_blue = 0xF0F8FF, // rgb(240,248,255)
@ -177,9 +178,13 @@ enum class terminal_color : uint8_t {
enum class emphasis : uint8_t {
bold = 1,
italic = 1 << 1,
underline = 1 << 2,
strikethrough = 1 << 3
faint = 1 << 1,
italic = 1 << 2,
underline = 1 << 3,
blink = 1 << 4,
reverse = 1 << 5,
conceal = 1 << 6,
strikethrough = 1 << 7,
};
// rgb is a struct for red, green and blue colors.
@ -198,21 +203,20 @@ struct rgb {
uint8_t b;
};
namespace internal {
namespace detail {
// color is a struct of either a rgb color or a terminal color.
struct color_type {
FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {}
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true),
value{} {
FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {}
FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} {
value.rgb_color = static_cast<uint32_t>(rgb_color);
}
FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} {
FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} {
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
}
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(),
value{} {
FMT_CONSTEXPR color_type(terminal_color term_color) noexcept
: is_rgb(), value{} {
value.term_color = static_cast<uint8_t>(term_color);
}
bool is_rgb;
@ -221,15 +225,13 @@ struct color_type {
uint32_t rgb_color;
} value;
};
} // namespace internal
} // namespace detail
// Experimental text formatting support.
/** A text style consisting of foreground and background colors and emphasis. */
class text_style {
public:
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
: set_foreground_color(),
set_background_color(),
ems(em) {}
FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept
: set_foreground_color(), set_background_color(), ems(em) {}
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
if (!set_foreground_color) {
@ -260,63 +262,32 @@ class text_style {
return lhs |= rhs;
}
FMT_CONSTEXPR text_style& operator&=(const text_style& rhs) {
if (!set_foreground_color) {
set_foreground_color = rhs.set_foreground_color;
foreground_color = rhs.foreground_color;
} else if (rhs.set_foreground_color) {
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
FMT_THROW(format_error("can't AND a terminal color"));
foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
}
if (!set_background_color) {
set_background_color = rhs.set_background_color;
background_color = rhs.background_color;
} else if (rhs.set_background_color) {
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
FMT_THROW(format_error("can't AND a terminal color"));
background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
}
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
static_cast<uint8_t>(rhs.ems));
return *this;
}
friend FMT_CONSTEXPR text_style operator&(text_style lhs,
const text_style& rhs) {
return lhs &= rhs;
}
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
FMT_CONSTEXPR bool has_foreground() const noexcept {
return set_foreground_color;
}
FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {
FMT_CONSTEXPR bool has_background() const noexcept {
return set_background_color;
}
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
FMT_CONSTEXPR bool has_emphasis() const noexcept {
return static_cast<uint8_t>(ems) != 0;
}
FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT {
FMT_CONSTEXPR detail::color_type get_foreground() const noexcept {
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
return foreground_color;
}
FMT_CONSTEXPR internal::color_type get_background() const FMT_NOEXCEPT {
FMT_CONSTEXPR detail::color_type get_background() const noexcept {
FMT_ASSERT(has_background(), "no background specified for this style");
return background_color;
}
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
FMT_CONSTEXPR emphasis get_emphasis() const noexcept {
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
return ems;
}
private:
FMT_CONSTEXPR text_style(bool is_foreground,
internal::color_type text_color) FMT_NOEXCEPT
: set_foreground_color(),
set_background_color(),
ems() {
detail::color_type text_color) noexcept
: set_foreground_color(), set_background_color(), ems() {
if (is_foreground) {
foreground_color = text_color;
set_foreground_color = true;
@ -326,45 +297,46 @@ class text_style {
}
}
friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground)
FMT_NOEXCEPT;
friend FMT_CONSTEXPR_DECL text_style bg(internal::color_type background)
FMT_NOEXCEPT;
friend FMT_CONSTEXPR text_style fg(detail::color_type foreground) noexcept;
internal::color_type foreground_color;
internal::color_type background_color;
friend FMT_CONSTEXPR text_style bg(detail::color_type background) noexcept;
detail::color_type foreground_color;
detail::color_type background_color;
bool set_foreground_color;
bool set_background_color;
emphasis ems;
};
FMT_CONSTEXPR text_style fg(internal::color_type foreground) FMT_NOEXCEPT {
return text_style(/*is_foreground=*/true, foreground);
/** Creates a text style from the foreground (text) color. */
FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) noexcept {
return text_style(true, foreground);
}
FMT_CONSTEXPR text_style bg(internal::color_type background) FMT_NOEXCEPT {
return text_style(/*is_foreground=*/false, background);
/** Creates a text style from the background color. */
FMT_CONSTEXPR inline text_style bg(detail::color_type background) noexcept {
return text_style(false, background);
}
FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
FMT_CONSTEXPR inline text_style operator|(emphasis lhs, emphasis rhs) noexcept {
return text_style(lhs) | rhs;
}
namespace internal {
namespace detail {
template <typename Char> struct ansi_color_escape {
FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color,
const char* esc) FMT_NOEXCEPT {
FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
const char* esc) noexcept {
// If we have a terminal color, we need to output another escape code
// sequence.
if (!text_color.is_rgb) {
bool is_background = esc == internal::data::background_color;
bool is_background = esc == string_view("\x1b[48;2;");
uint32_t value = text_color.value.term_color;
// Background ASCII codes are the same as the foreground ones but with
// 10 more.
if (is_background) value += 10u;
std::size_t index = 0;
size_t index = 0;
buffer[index++] = static_cast<Char>('\x1b');
buffer[index++] = static_cast<Char>('[');
@ -389,17 +361,19 @@ template <typename Char> struct ansi_color_escape {
to_esc(color.b, buffer + 15, 'm');
buffer[19] = static_cast<Char>(0);
}
FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
uint8_t em_codes[4] = {};
uint8_t em_bits = static_cast<uint8_t>(em);
if (em_bits & static_cast<uint8_t>(emphasis::bold)) em_codes[0] = 1;
if (em_bits & static_cast<uint8_t>(emphasis::italic)) em_codes[1] = 3;
if (em_bits & static_cast<uint8_t>(emphasis::underline)) em_codes[2] = 4;
if (em_bits & static_cast<uint8_t>(emphasis::strikethrough))
em_codes[3] = 9;
FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept {
uint8_t em_codes[num_emphases] = {};
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3;
if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4;
if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5;
if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7;
if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8;
if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9;
std::size_t index = 0;
for (int i = 0; i < 4; ++i) {
size_t index = 0;
for (size_t i = 0; i < num_emphases; ++i) {
if (!em_codes[i]) continue;
buffer[index++] = static_cast<Char>('\x1b');
buffer[index++] = static_cast<Char>('[');
@ -408,131 +382,129 @@ template <typename Char> struct ansi_color_escape {
}
buffer[index++] = static_cast<Char>(0);
}
FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; }
FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; }
FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
FMT_CONSTEXPR const Char* end() const FMT_NOEXCEPT {
return buffer + std::strlen(buffer);
FMT_CONSTEXPR const Char* begin() const noexcept { return buffer; }
FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const noexcept {
return buffer + std::char_traits<Char>::length(buffer);
}
private:
Char buffer[7u + 3u * 4u + 1u];
static constexpr size_t num_emphases = 8;
Char buffer[7u + 3u * num_emphases + 1u];
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
char delimiter) FMT_NOEXCEPT {
char delimiter) noexcept {
out[0] = static_cast<Char>('0' + c / 100);
out[1] = static_cast<Char>('0' + c / 10 % 10);
out[2] = static_cast<Char>('0' + c % 10);
out[3] = static_cast<Char>(delimiter);
}
static FMT_CONSTEXPR bool has_emphasis(emphasis em, emphasis mask) noexcept {
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
}
};
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
internal::color_type foreground) FMT_NOEXCEPT {
return ansi_color_escape<Char>(foreground, internal::data::foreground_color);
detail::color_type foreground) noexcept {
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
}
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
internal::color_type background) FMT_NOEXCEPT {
return ansi_color_escape<Char>(background, internal::data::background_color);
detail::color_type background) noexcept {
return ansi_color_escape<Char>(background, "\x1b[48;2;");
}
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) FMT_NOEXCEPT {
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) noexcept {
return ansi_color_escape<Char>(em);
}
template <typename Char>
inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT {
std::fputs(chars, stream);
template <typename Char> inline void reset_color(buffer<Char>& buffer) {
auto reset_color = string_view("\x1b[0m");
buffer.append(reset_color.begin(), reset_color.end());
}
template <>
inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT {
std::fputws(chars, stream);
}
template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT {
fputs(internal::data::reset_color, stream);
}
template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
fputs(internal::data::wreset_color, stream);
}
template <typename T> struct styled_arg {
const T& value;
text_style style;
};
template <typename Char>
inline void reset_color(basic_memory_buffer<Char>& buffer) FMT_NOEXCEPT {
const char* begin = data::reset_color;
const char* end = begin + sizeof(data::reset_color) - 1;
buffer.append(begin, end);
}
template <typename Char>
void vformat_to(basic_memory_buffer<Char>& buf, const text_style& ts,
void vformat_to(buffer<Char>& buf, const text_style& ts,
basic_string_view<Char> format_str,
basic_format_args<buffer_context<Char>> args) {
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
bool has_style = false;
if (ts.has_emphasis()) {
has_style = true;
auto emphasis = internal::make_emphasis<Char>(ts.get_emphasis());
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
buf.append(emphasis.begin(), emphasis.end());
}
if (ts.has_foreground()) {
has_style = true;
auto foreground =
internal::make_foreground_color<Char>(ts.get_foreground());
auto foreground = detail::make_foreground_color<Char>(ts.get_foreground());
buf.append(foreground.begin(), foreground.end());
}
if (ts.has_background()) {
has_style = true;
auto background =
internal::make_background_color<Char>(ts.get_background());
auto background = detail::make_background_color<Char>(ts.get_background());
buf.append(background.begin(), background.end());
}
vformat_to(buf, format_str, args);
if (has_style) {
internal::reset_color<Char>(buf);
}
detail::vformat_to(buf, format_str, args, {});
if (has_style) detail::reset_color<Char>(buf);
}
} // namespace internal
template <typename S, typename Char = char_t<S>>
void vprint(std::FILE* f, const text_style& ts, const S& format,
basic_format_args<buffer_context<Char>> args) {
basic_memory_buffer<Char> buf;
internal::vformat_to(buf, ts, to_string_view(format), args);
buf.push_back(Char(0));
internal::fputs(buf.data(), f);
} // namespace detail
inline void vprint(std::FILE* f, const text_style& ts, string_view fmt,
format_args args) {
// Legacy wide streams are not supported.
auto buf = memory_buffer();
detail::vformat_to(buf, ts, fmt, args);
if (detail::is_utf8()) {
detail::print(f, string_view(buf.begin(), buf.size()));
return;
}
buf.push_back('\0');
int result = std::fputs(buf.data(), f);
if (result < 0)
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
}
/**
\rst
Formats a string and prints it to the specified file stream using ANSI
escape sequences to specify text formatting.
Example:
**Example**::
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
template <typename S, typename... Args,
FMT_ENABLE_IF(internal::is_string<S>::value)>
FMT_ENABLE_IF(detail::is_string<S>::value)>
void print(std::FILE* f, const text_style& ts, const S& format_str,
const Args&... args) {
internal::check_format_string<Args...>(format_str);
using context = buffer_context<char_t<S>>;
format_arg_store<context, Args...> as{args...};
vprint(f, ts, format_str, basic_format_args<context>(as));
vprint(f, ts, format_str,
fmt::make_format_args<buffer_context<char_t<S>>>(args...));
}
/**
\rst
Formats a string and prints it to stdout using ANSI escape sequences to
specify text formatting.
Example:
**Example**::
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
template <typename S, typename... Args,
FMT_ENABLE_IF(internal::is_string<S>::value)>
FMT_ENABLE_IF(detail::is_string<S>::value)>
void print(const text_style& ts, const S& format_str, const Args&... args) {
return print(stdout, ts, format_str, args...);
}
@ -540,9 +512,9 @@ void print(const text_style& ts, const S& format_str, const Args&... args) {
template <typename S, typename Char = char_t<S>>
inline std::basic_string<Char> vformat(
const text_style& ts, const S& format_str,
basic_format_args<buffer_context<Char>> args) {
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
basic_memory_buffer<Char> buf;
internal::vformat_to(buf, ts, to_string_view(format_str), args);
detail::vformat_to(buf, ts, detail::to_string_view(format_str), args);
return fmt::to_string(buf);
}
@ -561,10 +533,100 @@ inline std::basic_string<Char> vformat(
template <typename S, typename... Args, typename Char = char_t<S>>
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
const Args&... args) {
return vformat(ts, to_string_view(format_str),
{internal::make_args_checked<Args...>(format_str, args...)});
return fmt::vformat(ts, detail::to_string_view(format_str),
fmt::make_format_args<buffer_context<Char>>(args...));
}
/**
Formats a string with the given text_style and writes the output to ``out``.
*/
template <typename OutputIt, typename Char,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
OutputIt vformat_to(
OutputIt out, const text_style& ts, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
auto&& buf = detail::get_buffer<Char>(out);
detail::vformat_to(buf, ts, format_str, args);
return detail::get_iterator(buf, out);
}
/**
\rst
Formats arguments with the given text_style, writes the result to the output
iterator ``out`` and returns the iterator past the end of the output range.
**Example**::
std::vector<char> out;
fmt::format_to(std::back_inserter(out),
fmt::emphasis::bold | fg(fmt::color::red), "{}", 42);
\endrst
*/
template <typename OutputIt, typename S, typename... Args,
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value&&
detail::is_string<S>::value>
inline auto format_to(OutputIt out, const text_style& ts, const S& format_str,
Args&&... args) ->
typename std::enable_if<enable, OutputIt>::type {
return vformat_to(out, ts, detail::to_string_view(format_str),
fmt::make_format_args<buffer_context<char_t<S>>>(args...));
}
template <typename T, typename Char>
struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> {
template <typename FormatContext>
auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const
-> decltype(ctx.out()) {
const auto& ts = arg.style;
const auto& value = arg.value;
auto out = ctx.out();
bool has_style = false;
if (ts.has_emphasis()) {
has_style = true;
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
out = std::copy(emphasis.begin(), emphasis.end(), out);
}
if (ts.has_foreground()) {
has_style = true;
auto foreground =
detail::make_foreground_color<Char>(ts.get_foreground());
out = std::copy(foreground.begin(), foreground.end(), out);
}
if (ts.has_background()) {
has_style = true;
auto background =
detail::make_background_color<Char>(ts.get_background());
out = std::copy(background.begin(), background.end(), out);
}
out = formatter<T, Char>::format(value, ctx);
if (has_style) {
auto reset_color = string_view("\x1b[0m");
out = std::copy(reset_color.begin(), reset_color.end(), out);
}
return out;
}
};
/**
\rst
Returns an argument that will be formatted using ANSI escape sequences,
to be used in a formatting function.
**Example**::
fmt::print("Elapsed time: {0:.2f} seconds",
fmt::styled(1.23, fmt::fg(fmt::color::green) |
fmt::bg(fmt::color::blue)));
\endrst
*/
template <typename T>
FMT_CONSTEXPR auto styled(const T& value, text_style ts)
-> detail::styled_arg<remove_cvref_t<T>> {
return detail::styled_arg<remove_cvref_t<T>>{value, ts};
}
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_COLOR_H_

View File

@ -8,416 +8,218 @@
#ifndef FMT_COMPILE_H_
#define FMT_COMPILE_H_
#include <vector>
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace internal {
namespace detail {
// Part of a compiled format string. It can be either literal text or a
// replacement field.
template <typename Char> struct format_part {
enum class kind { arg_index, arg_name, text, replacement };
struct replacement {
arg_ref<Char> arg_id;
dynamic_format_specs<Char> specs;
};
kind part_kind;
union value {
unsigned arg_index;
basic_string_view<Char> str;
replacement repl;
FMT_CONSTEXPR value(unsigned index = 0) : arg_index(index) {}
FMT_CONSTEXPR value(basic_string_view<Char> s) : str(s) {}
FMT_CONSTEXPR value(replacement r) : repl(r) {}
} val;
// Position past the end of the argument id.
const Char* arg_id_end = nullptr;
FMT_CONSTEXPR format_part(kind k = kind::arg_index, value v = {})
: part_kind(k), val(v) {}
static FMT_CONSTEXPR format_part make_arg_index(unsigned index) {
return format_part(kind::arg_index, index);
}
static FMT_CONSTEXPR format_part make_arg_name(basic_string_view<Char> name) {
return format_part(kind::arg_name, name);
}
static FMT_CONSTEXPR format_part make_text(basic_string_view<Char> text) {
return format_part(kind::text, text);
}
static FMT_CONSTEXPR format_part make_replacement(replacement repl) {
return format_part(kind::replacement, repl);
}
};
template <typename Char> struct part_counter {
unsigned num_parts = 0;
FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
if (begin != end) ++num_parts;
}
FMT_CONSTEXPR void on_arg_id() { ++num_parts; }
FMT_CONSTEXPR void on_arg_id(unsigned) { ++num_parts; }
FMT_CONSTEXPR void on_arg_id(basic_string_view<Char>) { ++num_parts; }
FMT_CONSTEXPR void on_replacement_field(const Char*) {}
FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
const Char* end) {
// Find the matching brace.
unsigned brace_counter = 0;
for (; begin != end; ++begin) {
if (*begin == '{') {
++brace_counter;
} else if (*begin == '}') {
if (brace_counter == 0u) break;
--brace_counter;
}
}
return begin;
}
FMT_CONSTEXPR void on_error(const char*) {}
};
// Counts the number of parts in a format string.
template <typename Char>
FMT_CONSTEXPR unsigned count_parts(basic_string_view<Char> format_str) {
part_counter<Char> counter;
parse_format_string<true>(format_str, counter);
return counter.num_parts;
template <typename Char, typename InputIt>
FMT_CONSTEXPR inline counting_iterator copy_str(InputIt begin, InputIt end,
counting_iterator it) {
return it + (end - begin);
}
template <typename Char, typename PartHandler>
class format_string_compiler : public error_handler {
private:
using part = format_part<Char>;
PartHandler handler_;
part part_;
basic_string_view<Char> format_str_;
basic_format_parse_context<Char> parse_context_;
public:
FMT_CONSTEXPR format_string_compiler(basic_string_view<Char> format_str,
PartHandler handler)
: handler_(handler),
format_str_(format_str),
parse_context_(format_str) {}
FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
if (begin != end)
handler_(part::make_text({begin, to_unsigned(end - begin)}));
}
FMT_CONSTEXPR void on_arg_id() {
part_ = part::make_arg_index(parse_context_.next_arg_id());
}
FMT_CONSTEXPR void on_arg_id(unsigned id) {
parse_context_.check_arg_id(id);
part_ = part::make_arg_index(id);
}
FMT_CONSTEXPR void on_arg_id(basic_string_view<Char> id) {
part_ = part::make_arg_name(id);
}
FMT_CONSTEXPR void on_replacement_field(const Char* ptr) {
part_.arg_id_end = ptr;
handler_(part_);
}
FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
const Char* end) {
auto repl = typename part::replacement();
dynamic_specs_handler<basic_format_parse_context<Char>> handler(
repl.specs, parse_context_);
auto it = parse_format_specs(begin, end, handler);
if (*it != '}') on_error("missing '}' in format string");
repl.arg_id = part_.part_kind == part::kind::arg_index
? arg_ref<Char>(part_.val.arg_index)
: arg_ref<Char>(part_.val.str);
auto part = part::make_replacement(repl);
part.arg_id_end = begin;
handler_(part);
return it;
}
};
// Compiles a format string and invokes handler(part) for each parsed part.
template <bool IS_CONSTEXPR, typename Char, typename PartHandler>
FMT_CONSTEXPR void compile_format_string(basic_string_view<Char> format_str,
PartHandler handler) {
parse_format_string<IS_CONSTEXPR>(
format_str,
format_string_compiler<Char, PartHandler>(format_str, handler));
}
template <typename Range, typename Context, typename Id>
void format_arg(
basic_format_parse_context<typename Range::value_type>& parse_ctx,
Context& ctx, Id arg_id) {
ctx.advance_to(
visit_format_arg(arg_formatter<Range>(ctx, &parse_ctx), ctx.arg(arg_id)));
}
// vformat_to is defined in a subnamespace to prevent ADL.
namespace cf {
template <typename Context, typename Range, typename CompiledFormat>
auto vformat_to(Range out, CompiledFormat& cf, basic_format_args<Context> args)
-> typename Context::iterator {
using char_type = typename Context::char_type;
basic_format_parse_context<char_type> parse_ctx(
to_string_view(cf.format_str_));
Context ctx(out.begin(), args);
const auto& parts = cf.parts();
for (auto part_it = std::begin(parts); part_it != std::end(parts);
++part_it) {
const auto& part = *part_it;
const auto& value = part.val;
using format_part_t = format_part<char_type>;
switch (part.part_kind) {
case format_part_t::kind::text: {
const auto text = value.str;
auto output = ctx.out();
auto&& it = reserve(output, text.size());
it = std::copy_n(text.begin(), text.size(), it);
ctx.advance_to(output);
break;
}
case format_part_t::kind::arg_index:
advance_to(parse_ctx, part.arg_id_end);
internal::format_arg<Range>(parse_ctx, ctx, value.arg_index);
break;
case format_part_t::kind::arg_name:
advance_to(parse_ctx, part.arg_id_end);
internal::format_arg<Range>(parse_ctx, ctx, value.str);
break;
case format_part_t::kind::replacement: {
const auto& arg_id_value = value.repl.arg_id.val;
const auto arg = value.repl.arg_id.kind == arg_id_kind::index
? ctx.arg(arg_id_value.index)
: ctx.arg(arg_id_value.name);
auto specs = value.repl.specs;
handle_dynamic_spec<width_checker>(specs.width, specs.width_ref, ctx);
handle_dynamic_spec<precision_checker>(specs.precision,
specs.precision_ref, ctx);
error_handler h;
numeric_specs_checker<error_handler> checker(h, arg.type());
if (specs.align == align::numeric) checker.require_numeric_argument();
if (specs.sign != sign::none) checker.check_sign();
if (specs.alt) checker.require_numeric_argument();
if (specs.precision >= 0) checker.check_precision();
advance_to(parse_ctx, part.arg_id_end);
ctx.advance_to(
visit_format_arg(arg_formatter<Range>(ctx, nullptr, &specs), arg));
break;
}
}
}
return ctx.out();
}
} // namespace cf
struct basic_compiled_format {};
template <typename S, typename = void>
struct compiled_format_base : basic_compiled_format {
using char_type = char_t<S>;
using parts_container = std::vector<internal::format_part<char_type>>;
parts_container compiled_parts;
explicit compiled_format_base(basic_string_view<char_type> format_str) {
compile_format_string<false>(format_str,
[this](const format_part<char_type>& part) {
compiled_parts.push_back(part);
});
}
const parts_container& parts() const { return compiled_parts; }
};
template <typename Char, unsigned N> struct format_part_array {
format_part<Char> data[N] = {};
FMT_CONSTEXPR format_part_array() = default;
};
template <typename Char, unsigned N>
FMT_CONSTEXPR format_part_array<Char, N> compile_to_parts(
basic_string_view<Char> format_str) {
format_part_array<Char, N> parts;
unsigned counter = 0;
// This is not a lambda for compatibility with older compilers.
struct {
format_part<Char>* parts;
unsigned* counter;
FMT_CONSTEXPR void operator()(const format_part<Char>& part) {
parts[(*counter)++] = part;
}
} collector{parts.data, &counter};
compile_format_string<true>(format_str, collector);
if (counter < N) {
parts.data[counter] =
format_part<Char>::make_text(basic_string_view<Char>());
}
return parts;
}
template <typename T> constexpr const T& constexpr_max(const T& a, const T& b) {
return (a < b) ? b : a;
}
// A compile-time string which is compiled into fast formatting code.
class compiled_string {};
template <typename S>
struct compiled_format_base<S, enable_if_t<is_compile_string<S>::value>>
: basic_compiled_format {
using char_type = char_t<S>;
struct is_compiled_string : std::is_base_of<compiled_string, S> {};
FMT_CONSTEXPR explicit compiled_format_base(basic_string_view<char_type>) {}
/**
\rst
Converts a string literal *s* into a format string that will be parsed at
compile time and converted into efficient formatting code. Requires C++17
``constexpr if`` compiler support.
// Workaround for old compilers. Format string compilation will not be
// performed there anyway.
#if FMT_USE_CONSTEXPR
static FMT_CONSTEXPR_DECL const unsigned num_format_parts =
constexpr_max(count_parts(to_string_view(S())), 1u);
**Example**::
// Converts 42 into std::string using the most efficient method and no
// runtime format string processing.
std::string s = fmt::format(FMT_COMPILE("{}"), 42);
\endrst
*/
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
# define FMT_COMPILE(s) \
FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit)
#else
static const unsigned num_format_parts = 1;
# define FMT_COMPILE(s) FMT_STRING(s)
#endif
using parts_container = format_part<char_type>[num_format_parts];
const parts_container& parts() const {
static FMT_CONSTEXPR_DECL const auto compiled_parts =
compile_to_parts<char_type, num_format_parts>(
internal::to_string_view(S()));
return compiled_parts.data;
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
template <typename Char, size_t N,
fmt::detail_exported::fixed_string<Char, N> Str>
struct udl_compiled_string : compiled_string {
using char_type = Char;
explicit constexpr operator basic_string_view<char_type>() const {
return {Str.data, N - 1};
}
};
#endif
template <typename S, typename... Args>
class compiled_format : private compiled_format_base<S> {
public:
using typename compiled_format_base<S>::char_type;
template <typename T, typename... Tail>
const T& first(const T& value, const Tail&...) {
return value;
}
private:
basic_string_view<char_type> format_str_;
template <typename Context, typename Range, typename CompiledFormat>
friend auto cf::vformat_to(Range out, CompiledFormat& cf,
basic_format_args<Context> args) ->
typename Context::iterator;
public:
compiled_format() = delete;
explicit constexpr compiled_format(basic_string_view<char_type> format_str)
: compiled_format_base<S>(format_str), format_str_(format_str) {}
};
#ifdef __cpp_if_constexpr
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
template <typename... Args> struct type_list {};
// Returns a reference to the argument at index N from [first, rest...].
template <int N, typename T, typename... Args>
constexpr const auto& get(const T& first, const Args&... rest) {
constexpr const auto& get([[maybe_unused]] const T& first,
[[maybe_unused]] const Args&... rest) {
static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
if constexpr (N == 0)
return first;
else
return get<N - 1>(rest...);
return detail::get<N - 1>(rest...);
}
template <typename Char, typename... Args>
constexpr int get_arg_index_by_name(basic_string_view<Char> name,
type_list<Args...>) {
return get_arg_index_by_name<Args...>(name);
}
template <int N, typename> struct get_type_impl;
template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
using type = remove_cvref_t<decltype(get<N>(std::declval<Args>()...))>;
using type =
remove_cvref_t<decltype(detail::get<N>(std::declval<Args>()...))>;
};
template <int N, typename T>
using get_type = typename get_type_impl<N, T>::type;
template <typename T> struct is_compiled_format : std::false_type {};
template <typename Char> struct text {
basic_string_view<Char> data;
using char_type = Char;
template <typename OutputIt, typename... Args>
OutputIt format(OutputIt out, const Args&...) const {
// TODO: reserve
return copy_str<Char>(data.begin(), data.end(), out);
constexpr OutputIt format(OutputIt out, const Args&...) const {
return write<Char>(out, data);
}
};
template <typename Char>
struct is_compiled_format<text<Char>> : std::true_type {};
template <typename Char>
constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
size_t size) {
return {{&s[pos], size}};
}
template <typename Char, typename OutputIt, typename T,
std::enable_if_t<std::is_integral_v<T>, int> = 0>
OutputIt format_default(OutputIt out, T value) {
// TODO: reserve
format_int fi(value);
return std::copy(fi.data(), fi.data() + fi.size(), out);
template <typename Char> struct code_unit {
Char value;
using char_type = Char;
template <typename OutputIt, typename... Args>
constexpr OutputIt format(OutputIt out, const Args&...) const {
*out++ = value;
return out;
}
};
// This ensures that the argument type is convertible to `const T&`.
template <typename T, int N, typename... Args>
constexpr const T& get_arg_checked(const Args&... args) {
const auto& arg = detail::get<N>(args...);
if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) {
return arg.value;
} else {
return arg;
}
}
template <typename Char, typename OutputIt>
OutputIt format_default(OutputIt out, double value) {
writer w(out);
w.write(value);
return w.out();
}
template <typename Char, typename OutputIt>
OutputIt format_default(OutputIt out, Char value) {
*out++ = value;
return out;
}
template <typename Char, typename OutputIt>
OutputIt format_default(OutputIt out, const Char* value) {
auto length = std::char_traits<Char>::length(value);
return copy_str<Char>(value, value + length, out);
}
template <typename Char>
struct is_compiled_format<code_unit<Char>> : std::true_type {};
// A replacement field that refers to argument N.
template <typename Char, typename T, int N> struct field {
using char_type = Char;
template <typename OutputIt, typename... Args>
OutputIt format(OutputIt out, const Args&... args) const {
// This ensures that the argument type is convertile to `const T&`.
const T& arg = get<N>(args...);
return format_default<Char>(out, arg);
constexpr OutputIt format(OutputIt out, const Args&... args) const {
const T& arg = get_arg_checked<T, N>(args...);
if constexpr (std::is_convertible_v<T, basic_string_view<Char>>) {
auto s = basic_string_view<Char>(arg);
return copy_str<Char>(s.begin(), s.end(), out);
}
return write<Char>(out, arg);
}
};
template <typename Char, typename T, int N>
struct is_compiled_format<field<Char, T, N>> : std::true_type {};
// A replacement field that refers to argument with name.
template <typename Char> struct runtime_named_field {
using char_type = Char;
basic_string_view<Char> name;
template <typename OutputIt, typename T>
constexpr static bool try_format_argument(
OutputIt& out,
// [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9
[[maybe_unused]] basic_string_view<Char> arg_name, const T& arg) {
if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) {
if (arg_name == arg.name) {
out = write<Char>(out, arg.value);
return true;
}
}
return false;
}
template <typename OutputIt, typename... Args>
constexpr OutputIt format(OutputIt out, const Args&... args) const {
bool found = (try_format_argument(out, name, args) || ...);
if (!found) {
FMT_THROW(format_error("argument with specified name is not found"));
}
return out;
}
};
template <typename Char>
struct is_compiled_format<runtime_named_field<Char>> : std::true_type {};
// A replacement field that refers to argument N and has format specifiers.
template <typename Char, typename T, int N> struct spec_field {
using char_type = Char;
formatter<T, Char> fmt;
template <typename OutputIt, typename... Args>
constexpr FMT_INLINE OutputIt format(OutputIt out,
const Args&... args) const {
const auto& vargs =
fmt::make_format_args<basic_format_context<OutputIt, Char>>(args...);
basic_format_context<OutputIt, Char> ctx(out, vargs);
return fmt.format(get_arg_checked<T, N>(args...), ctx);
}
};
template <typename Char, typename T, int N>
struct is_compiled_format<spec_field<Char, T, N>> : std::true_type {};
template <typename L, typename R> struct concat {
L lhs;
R rhs;
using char_type = typename L::char_type;
template <typename OutputIt, typename... Args>
OutputIt format(OutputIt out, const Args&... args) const {
constexpr OutputIt format(OutputIt out, const Args&... args) const {
out = lhs.format(out, args...);
return rhs.format(out, args...);
}
};
template <typename L, typename R>
struct is_compiled_format<concat<L, R>> : std::true_type {};
template <typename L, typename R>
constexpr concat<L, R> make_concat(L lhs, R rhs) {
return {lhs, rhs};
@ -438,7 +240,8 @@ constexpr auto compile_format_string(S format_str);
template <typename Args, size_t POS, int ID, typename T, typename S>
constexpr auto parse_tail(T head, S format_str) {
if constexpr (POS != to_string_view(format_str).size()) {
if constexpr (POS !=
basic_string_view<typename S::char_type>(format_str).size()) {
constexpr auto tail = compile_format_string<Args, POS, ID>(format_str);
if constexpr (std::is_same<remove_cvref_t<decltype(tail)>,
unknown_format>())
@ -450,138 +253,282 @@ constexpr auto parse_tail(T head, S format_str) {
}
}
template <typename T, typename Char> struct parse_specs_result {
formatter<T, Char> fmt;
size_t end;
int next_arg_id;
};
enum { manual_indexing_id = -1 };
template <typename T, typename Char>
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
size_t pos, int next_arg_id) {
str.remove_prefix(pos);
auto ctx =
compile_parse_context<Char>(str, max_value<int>(), nullptr, next_arg_id);
auto f = formatter<T, Char>();
auto end = f.parse(ctx);
return {f, pos + fmt::detail::to_unsigned(end - str.data()),
next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()};
}
template <typename Char> struct arg_id_handler {
arg_ref<Char> arg_id;
constexpr int on_auto() {
FMT_ASSERT(false, "handler cannot be used with automatic indexing");
return 0;
}
constexpr int on_index(int id) {
arg_id = arg_ref<Char>(id);
return 0;
}
constexpr int on_name(basic_string_view<Char> id) {
arg_id = arg_ref<Char>(id);
return 0;
}
};
template <typename Char> struct parse_arg_id_result {
arg_ref<Char> arg_id;
const Char* arg_id_end;
};
template <int ID, typename Char>
constexpr auto parse_arg_id(const Char* begin, const Char* end) {
auto handler = arg_id_handler<Char>{arg_ref<Char>{}};
auto arg_id_end = parse_arg_id(begin, end, handler);
return parse_arg_id_result<Char>{handler.arg_id, arg_id_end};
}
template <typename T, typename Enable = void> struct field_type {
using type = remove_cvref_t<T>;
};
template <typename T>
struct field_type<T, enable_if_t<detail::is_named_arg<T>::value>> {
using type = remove_cvref_t<decltype(T::value)>;
};
template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID,
typename S>
constexpr auto parse_replacement_field_then_tail(S format_str) {
using char_type = typename S::char_type;
constexpr auto str = basic_string_view<char_type>(format_str);
constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type();
if constexpr (c == '}') {
return parse_tail<Args, END_POS + 1, NEXT_ID>(
field<char_type, typename field_type<T>::type, ARG_INDEX>(),
format_str);
} else if constexpr (c != ':') {
FMT_THROW(format_error("expected ':'"));
} else {
constexpr auto result = parse_specs<typename field_type<T>::type>(
str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID);
if constexpr (result.end >= str.size() || str[result.end] != '}') {
FMT_THROW(format_error("expected '}'"));
return 0;
} else {
return parse_tail<Args, result.end + 1, result.next_arg_id>(
spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
result.fmt},
format_str);
}
}
}
// Compiles a non-empty format string and returns the compiled representation
// or unknown_format() on unrecognized input.
template <typename Args, size_t POS, int ID, typename S>
constexpr auto compile_format_string(S format_str) {
using char_type = typename S::char_type;
constexpr basic_string_view<char_type> str = format_str;
constexpr auto str = basic_string_view<char_type>(format_str);
if constexpr (str[POS] == '{') {
if (POS + 1 == str.size())
throw format_error("unmatched '{' in format string");
if constexpr (POS + 1 == str.size())
FMT_THROW(format_error("unmatched '{' in format string"));
if constexpr (str[POS + 1] == '{') {
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
} else if constexpr (str[POS + 1] == '}') {
using type = get_type<ID, Args>;
if constexpr (std::is_same<type, int>::value) {
return parse_tail<Args, POS + 2, ID + 1>(field<char_type, type, ID>(),
format_str);
} else {
return unknown_format();
}
} else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') {
static_assert(ID != manual_indexing_id,
"cannot switch from manual to automatic argument indexing");
constexpr auto next_id =
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
return parse_replacement_field_then_tail<get_type<ID, Args>, Args,
POS + 1, ID, next_id>(
format_str);
} else {
return unknown_format();
constexpr auto arg_id_result =
parse_arg_id<ID>(str.data() + POS + 1, str.data() + str.size());
constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data();
constexpr char_type c =
arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type();
static_assert(c == '}' || c == ':', "missing '}' in format string");
if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) {
static_assert(
ID == manual_indexing_id || ID == 0,
"cannot switch from automatic to manual argument indexing");
constexpr auto arg_index = arg_id_result.arg_id.val.index;
return parse_replacement_field_then_tail<get_type<arg_index, Args>,
Args, arg_id_end_pos,
arg_index, manual_indexing_id>(
format_str);
} else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) {
constexpr auto arg_index =
get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{});
if constexpr (arg_index >= 0) {
constexpr auto next_id =
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
return parse_replacement_field_then_tail<
decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos,
arg_index, next_id>(format_str);
} else if constexpr (c == '}') {
return parse_tail<Args, arg_id_end_pos + 1, ID>(
runtime_named_field<char_type>{arg_id_result.arg_id.val.name},
format_str);
} else if constexpr (c == ':') {
return unknown_format(); // no type info for specs parsing
}
}
}
} else if constexpr (str[POS] == '}') {
if (POS + 1 == str.size())
throw format_error("unmatched '}' in format string");
if constexpr (POS + 1 == str.size())
FMT_THROW(format_error("unmatched '}' in format string"));
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
} else {
constexpr auto end = parse_text(str, POS + 1);
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
format_str);
}
}
#endif // __cpp_if_constexpr
} // namespace internal
#if FMT_USE_CONSTEXPR
# ifdef __cpp_if_constexpr
template <typename... Args, typename S,
FMT_ENABLE_IF(is_compile_string<S>::value)>
constexpr auto compile(S format_str) {
constexpr basic_string_view<typename S::char_type> str = format_str;
if constexpr (str.size() == 0) {
return internal::make_text(str, 0, 0);
} else {
constexpr auto result =
internal::compile_format_string<internal::type_list<Args...>, 0, 0>(
format_str);
if constexpr (std::is_same<remove_cvref_t<decltype(result)>,
internal::unknown_format>()) {
return internal::compiled_format<S, Args...>(to_string_view(format_str));
if constexpr (end - POS > 1) {
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
format_str);
} else {
return result;
return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]},
format_str);
}
}
}
template <typename... Args, typename S,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
constexpr auto compile(S format_str) {
constexpr auto str = basic_string_view<typename S::char_type>(format_str);
if constexpr (str.size() == 0) {
return detail::make_text(str, 0, 0);
} else {
constexpr auto result =
detail::compile_format_string<detail::type_list<Args...>, 0, 0>(
format_str);
return result;
}
}
#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
} // namespace detail
FMT_BEGIN_EXPORT
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
template <typename CompiledFormat, typename... Args,
typename Char = typename CompiledFormat::char_type,
FMT_ENABLE_IF(!std::is_base_of<internal::basic_compiled_format,
CompiledFormat>::value)>
std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
basic_memory_buffer<Char> buffer;
using range = buffer_range<Char>;
using context = buffer_context<Char>;
cf.format(std::back_inserter(buffer), args...);
return to_string(buffer);
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
const Args&... args) {
auto s = std::basic_string<Char>();
cf.format(std::back_inserter(s), args...);
return s;
}
template <typename OutputIt, typename CompiledFormat, typename... Args,
FMT_ENABLE_IF(!std::is_base_of<internal::basic_compiled_format,
CompiledFormat>::value)>
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
const Args&... args) {
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf,
const Args&... args) {
return cf.format(out, args...);
}
# else
template <typename... Args, typename S,
FMT_ENABLE_IF(is_compile_string<S>::value)>
constexpr auto compile(S format_str) -> internal::compiled_format<S, Args...> {
return internal::compiled_format<S, Args...>(to_string_view(format_str));
}
# endif // __cpp_if_constexpr
#endif // FMT_USE_CONSTEXPR
// Compiles the format string which must be a string literal.
template <typename... Args, typename Char, size_t N>
auto compile(const Char (&format_str)[N])
-> internal::compiled_format<const Char*, Args...> {
return internal::compiled_format<const Char*, Args...>(
basic_string_view<Char>(format_str, N - 1));
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
Args&&... args) {
if constexpr (std::is_same<typename S::char_type, char>::value) {
constexpr auto str = basic_string_view<typename S::char_type>(S());
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {
const auto& first = detail::first(args...);
if constexpr (detail::is_named_arg<
remove_cvref_t<decltype(first)>>::value) {
return fmt::to_string(first.value);
} else {
return fmt::to_string(first);
}
}
}
constexpr auto compiled = detail::compile<Args...>(S());
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
detail::unknown_format>()) {
return fmt::format(
static_cast<basic_string_view<typename S::char_type>>(S()),
std::forward<Args>(args)...);
} else {
return fmt::format(compiled, std::forward<Args>(args)...);
}
}
template <typename CompiledFormat, typename... Args,
typename Char = typename CompiledFormat::char_type,
FMT_ENABLE_IF(std::is_base_of<internal::basic_compiled_format,
CompiledFormat>::value)>
std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
basic_memory_buffer<Char> buffer;
using range = buffer_range<Char>;
using context = buffer_context<Char>;
internal::cf::vformat_to<context>(range(buffer), cf,
{make_format_args<context>(args...)});
return to_string(buffer);
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
constexpr auto compiled = detail::compile<Args...>(S());
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
detail::unknown_format>()) {
return fmt::format_to(
out, static_cast<basic_string_view<typename S::char_type>>(S()),
std::forward<Args>(args)...);
} else {
return fmt::format_to(out, compiled, std::forward<Args>(args)...);
}
}
#endif
template <typename OutputIt, typename CompiledFormat, typename... Args,
FMT_ENABLE_IF(std::is_base_of<internal::basic_compiled_format,
CompiledFormat>::value)>
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
const Args&... args) {
using char_type = typename CompiledFormat::char_type;
using range = internal::output_range<OutputIt, char_type>;
using context = format_context_t<OutputIt, char_type>;
return internal::cf::vformat_to<context>(
range(out), cf, {make_format_args<context>(args...)});
}
template <typename OutputIt, typename CompiledFormat, typename... Args,
FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value)>
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
const CompiledFormat& cf,
const Args&... args) {
auto it =
format_to(internal::truncating_iterator<OutputIt>(out, n), cf, args...);
return {it.base(), it.count()};
const S& format_str, Args&&... args) {
using traits = detail::fixed_buffer_traits;
auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n);
format_to(std::back_inserter(buf), format_str, std::forward<Args>(args)...);
return {buf.out(), buf.count()};
}
template <typename CompiledFormat, typename... Args>
std::size_t formatted_size(const CompiledFormat& cf, const Args&... args) {
return format_to(internal::counting_iterator(), cf, args...).count();
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_CONSTEXPR20 size_t formatted_size(const S& format_str,
const Args&... args) {
return fmt::format_to(detail::counting_iterator(), format_str, args...)
.count();
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
void print(std::FILE* f, const S& format_str, const Args&... args) {
memory_buffer buffer;
fmt::format_to(std::back_inserter(buffer), format_str, args...);
detail::print(f, {buffer.data(), buffer.size()});
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
void print(const S& format_str, const Args&... args) {
print(stdout, format_str, args...);
}
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
inline namespace literals {
template <detail_exported::fixed_string Str> constexpr auto operator""_cf() {
using char_t = remove_cvref_t<decltype(Str.data[0])>;
return detail::udl_compiled_string<char_t, sizeof(Str.data) / sizeof(char_t),
Str>();
}
} // namespace literals
#endif
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_COMPILE_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,77 +0,0 @@
// Formatting library for C++ - std::locale support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_LOCALE_H_
#define FMT_LOCALE_H_
#include <locale>
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace internal {
template <typename Char>
typename buffer_context<Char>::iterator vformat_to(
const std::locale& loc, buffer<Char>& buf,
basic_string_view<Char> format_str,
basic_format_args<buffer_context<Char>> args) {
using range = buffer_range<Char>;
return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str), args,
internal::locale_ref(loc));
}
template <typename Char>
std::basic_string<Char> vformat(const std::locale& loc,
basic_string_view<Char> format_str,
basic_format_args<buffer_context<Char>> args) {
basic_memory_buffer<Char> buffer;
internal::vformat_to(loc, buffer, format_str, args);
return fmt::to_string(buffer);
}
} // namespace internal
template <typename S, typename Char = char_t<S>>
inline std::basic_string<Char> vformat(
const std::locale& loc, const S& format_str,
basic_format_args<buffer_context<Char>> args) {
return internal::vformat(loc, to_string_view(format_str), args);
}
template <typename S, typename... Args, typename Char = char_t<S>>
inline std::basic_string<Char> format(const std::locale& loc,
const S& format_str, Args&&... args) {
return internal::vformat(
loc, to_string_view(format_str),
{internal::make_args_checked<Args...>(format_str, args...)});
}
template <typename S, typename OutputIt, typename... Args,
typename Char = enable_if_t<
internal::is_output_iterator<OutputIt>::value, char_t<S>>>
inline OutputIt vformat_to(OutputIt out, const std::locale& loc,
const S& format_str,
format_args_t<OutputIt, Char> args) {
using range = internal::output_range<OutputIt, Char>;
return vformat_to<arg_formatter<range>>(
range(out), to_string_view(format_str), args, internal::locale_ref(loc));
}
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value&&
internal::is_string<S>::value)>
inline OutputIt format_to(OutputIt out, const std::locale& loc,
const S& format_str, Args&&... args) {
internal::check_format_string<Args...>(format_str);
using context = format_context_t<OutputIt, char_t<S>>;
format_arg_store<context, Args...> as{args...};
return vformat_to(out, loc, to_string_view(format_str),
basic_format_args<context>(as));
}
FMT_END_NAMESPACE
#endif // FMT_LOCALE_H_

451
include/fmt/os.h Normal file
View File

@ -0,0 +1,451 @@
// Formatting library for C++ - optional OS-specific functionality
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_OS_H_
#define FMT_OS_H_
#include <cerrno>
#include <cstddef>
#include <cstdio>
#include <system_error> // std::system_error
#if defined __APPLE__ || defined(__FreeBSD__)
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
#endif
#include "format.h"
#ifndef FMT_USE_FCNTL
// UWP doesn't provide _pipe.
# if FMT_HAS_INCLUDE("winapifamily.h")
# include <winapifamily.h>
# endif
# if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
defined(__linux__)) && \
(!defined(WINAPI_FAMILY) || \
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
# include <fcntl.h> // for O_RDONLY
# define FMT_USE_FCNTL 1
# else
# define FMT_USE_FCNTL 0
# endif
#endif
#ifndef FMT_POSIX
# if defined(_WIN32) && !defined(__MINGW32__)
// Fix warnings about deprecated symbols.
# define FMT_POSIX(call) _##call
# else
# define FMT_POSIX(call) call
# endif
#endif
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
#ifdef FMT_SYSTEM
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
#else
# define FMT_SYSTEM(call) ::call
# ifdef _WIN32
// Fix warnings about deprecated symbols.
# define FMT_POSIX_CALL(call) ::_##call
# else
# define FMT_POSIX_CALL(call) ::call
# endif
#endif
// Retries the expression while it evaluates to error_result and errno
// equals to EINTR.
#ifndef _WIN32
# define FMT_RETRY_VAL(result, expression, error_result) \
do { \
(result) = (expression); \
} while ((result) == (error_result) && errno == EINTR)
#else
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
#endif
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
FMT_BEGIN_NAMESPACE
FMT_BEGIN_EXPORT
/**
\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 type aliases 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_; }
};
using cstring_view = basic_cstring_view<char>;
using wcstring_view = basic_cstring_view<wchar_t>;
#ifdef _WIN32
FMT_API const std::error_category& system_category() noexcept;
namespace detail {
FMT_API void format_windows_error(buffer<char>& out, int error_code,
const char* message) noexcept;
}
FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
format_args args);
/**
\rst
Constructs a :class:`std::system_error` object with the description
of the form
.. parsed-literal::
*<message>*: *<system-message>*
where *<message>* is the formatted message and *<system-message>* is the
system message corresponding to the error code.
*error_code* is a Windows error code as given by ``GetLastError``.
If *error_code* is not a valid error code such as -1, the system message
will look like "error -1".
**Example**::
// This throws a system_error with the description
// cannot open file 'madeup': The system cannot find the file specified.
// or similar (system message may vary).
const char *filename = "madeup";
LPOFSTRUCT of = LPOFSTRUCT();
HFILE file = OpenFile(filename, &of, OF_READ);
if (file == HFILE_ERROR) {
throw fmt::windows_error(GetLastError(),
"cannot open file '{}'", filename);
}
\endrst
*/
template <typename... Args>
std::system_error windows_error(int error_code, string_view message,
const Args&... args) {
return vwindows_error(error_code, message, fmt::make_format_args(args...));
}
// Reports a Windows error without throwing an exception.
// Can be used to report errors from destructors.
FMT_API void report_windows_error(int error_code, const char* message) noexcept;
#else
inline const std::error_category& system_category() noexcept {
return std::system_category();
}
#endif // _WIN32
// std::system is not available on some platforms such as iOS (#2248).
#ifdef __OSX__
template <typename S, typename... Args, typename Char = char_t<S>>
void say(const S& format_str, Args&&... args) {
std::system(format("say \"{}\"", format(format_str, args...)).c_str());
}
#endif
// A buffered file.
class buffered_file {
private:
FILE* file_;
friend class file;
explicit buffered_file(FILE* f) : file_(f) {}
public:
buffered_file(const buffered_file&) = delete;
void operator=(const buffered_file&) = delete;
// Constructs a buffered_file object which doesn't represent any file.
buffered_file() noexcept : file_(nullptr) {}
// Destroys the object closing the file it represents if any.
FMT_API ~buffered_file() noexcept;
public:
buffered_file(buffered_file&& other) noexcept : file_(other.file_) {
other.file_ = nullptr;
}
buffered_file& operator=(buffered_file&& other) {
close();
file_ = other.file_;
other.file_ = nullptr;
return *this;
}
// Opens a file.
FMT_API buffered_file(cstring_view filename, cstring_view mode);
// Closes the file.
FMT_API void close();
// Returns the pointer to a FILE object representing this file.
FILE* get() const noexcept { return file_; }
FMT_API int descriptor() const;
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, fmt::make_format_args(args...));
}
};
#if FMT_USE_FCNTL
// A file. Closed file is represented by a file object with descriptor -1.
// Methods that are not declared with noexcept may throw
// 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 FMT_API file {
private:
int fd_; // File descriptor.
// Constructs a file object with a given descriptor.
explicit file(int fd) : fd_(fd) {}
public:
// Possible values for the oflag argument to the constructor.
enum {
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing.
CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist.
APPEND = FMT_POSIX(O_APPEND), // Open in append mode.
TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file.
};
// Constructs a file object which doesn't represent any file.
file() noexcept : fd_(-1) {}
// Opens a file and constructs a file object representing this file.
file(cstring_view path, int oflag);
public:
file(const file&) = delete;
void operator=(const file&) = delete;
file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }
// Move assignment is not noexcept because close may throw.
file& operator=(file&& other) {
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
// Destroys the object closing the file it represents if any.
~file() noexcept;
// Returns the file descriptor.
int descriptor() const noexcept { return fd_; }
// Closes the file.
void close();
// Returns the file size. The size has signed type for consistency with
// stat::st_size.
long long size() const;
// Attempts to read count bytes from the file into the specified buffer.
size_t read(void* buffer, size_t count);
// Attempts to write count bytes from the specified buffer to the file.
size_t write(const void* buffer, size_t count);
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
static file dup(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
void dup2(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
void dup2(int fd, std::error_code& ec) noexcept;
// Creates a pipe setting up read_end and write_end file objects for reading
// and writing respectively.
static void pipe(file& read_end, file& write_end);
// Creates a buffered_file object associated with this file and detaches
// this file object from the file.
buffered_file fdopen(const char* mode);
# if defined(_WIN32) && !defined(__MINGW32__)
// Opens a file and constructs a file object representing this file by
// wcstring_view filename. Windows only.
static file open_windows_file(wcstring_view path, int oflag);
# endif
};
// Returns the memory page size.
long getpagesize();
namespace detail {
struct buffer_size {
buffer_size() = default;
size_t value = 0;
buffer_size operator=(size_t val) const {
auto bs = buffer_size();
bs.value = val;
return bs;
}
};
struct ostream_params {
int oflag = file::WRONLY | file::CREATE | file::TRUNC;
size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768;
ostream_params() {}
template <typename... T>
ostream_params(T... params, int new_oflag) : ostream_params(params...) {
oflag = new_oflag;
}
template <typename... T>
ostream_params(T... params, detail::buffer_size bs)
: ostream_params(params...) {
this->buffer_size = bs.value;
}
// Intel has a bug that results in failure to deduce a constructor
// for empty parameter packs.
# if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000
ostream_params(int new_oflag) : oflag(new_oflag) {}
ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {}
# endif
};
class file_buffer final : public buffer<char> {
file file_;
FMT_API void grow(size_t) override;
public:
FMT_API file_buffer(cstring_view path, const ostream_params& params);
FMT_API file_buffer(file_buffer&& other);
FMT_API ~file_buffer();
void flush() {
if (size() == 0) return;
file_.write(data(), size() * sizeof(data()[0]));
clear();
}
void close() {
flush();
file_.close();
}
};
} // namespace detail
// Added {} below to work around default constructor error known to
// occur in Xcode versions 7.2.1 and 8.2.1.
constexpr detail::buffer_size buffer_size{};
/** A fast output stream which is not thread-safe. */
class FMT_API ostream {
private:
FMT_MSC_WARNING(suppress : 4251)
detail::file_buffer buffer_;
ostream(cstring_view path, const detail::ostream_params& params)
: buffer_(path, params) {}
public:
ostream(ostream&& other) : buffer_(std::move(other.buffer_)) {}
~ostream();
void flush() { buffer_.flush(); }
template <typename... T>
friend ostream output_file(cstring_view path, T... params);
void close() { buffer_.close(); }
/**
Formats ``args`` according to specifications in ``fmt`` and writes the
output to the file.
*/
template <typename... T> void print(format_string<T...> fmt, T&&... args) {
vformat_to(detail::buffer_appender<char>(buffer_), fmt,
fmt::make_format_args(args...));
}
};
/**
\rst
Opens a file for writing. Supported parameters passed in *params*:
* ``<integer>``: Flags passed to `open
<https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
(``file::WRONLY | file::CREATE | file::TRUNC`` by default)
* ``buffer_size=<integer>``: Output buffer size
**Example**::
auto out = fmt::output_file("guide.txt");
out.print("Don't {}", "Panic");
\endrst
*/
template <typename... T>
inline ostream output_file(cstring_view path, T... params) {
return {path, detail::ostream_params(params...)};
}
#endif // FMT_USE_FCNTL
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_OS_H_

View File

@ -8,74 +8,72 @@
#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_
#include <ostream>
#include <fstream> // std::filebuf
#if defined(_WIN32) && defined(__GLIBCXX__)
# include <ext/stdio_filebuf.h>
# include <ext/stdio_sync_filebuf.h>
#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
# include <__std_stream>
#endif
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace internal {
template <class Char> class formatbuf : public std::basic_streambuf<Char> {
private:
using int_type = typename std::basic_streambuf<Char>::int_type;
using traits_type = typename std::basic_streambuf<Char>::traits_type;
namespace detail {
buffer<Char>& buffer_;
public:
formatbuf(buffer<Char>& buf) : buffer_(buf) {}
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;
}
// Generate a unique explicit instantion in every translation unit using a tag
// type in an anonymous namespace.
namespace {
struct file_access_tag {};
} // namespace
template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr>
class file_access {
friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
};
template <typename Char> struct test_stream : std::basic_ostream<Char> {
private:
// Hide all operator<< from std::basic_ostream<Char>.
void_t<> operator<<(null<>);
void_t<> operator<<(const Char*);
#if FMT_MSC_VERSION
template class file_access<file_access_tag, std::filebuf,
&std::filebuf::_Myfile>;
auto get_file(std::filebuf&) -> FILE*;
#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
template class file_access<file_access_tag, std::__stdoutbuf<char>,
&std::__stdoutbuf<char>::__file_>;
auto get_file(std::__stdoutbuf<char>&) -> FILE*;
#endif
template <typename T, FMT_ENABLE_IF(std::is_convertible<T, int>::value &&
!std::is_enum<T>::value)>
void_t<> operator<<(T);
};
// 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 bool_constant<!std::is_same<decltype(std::declval<test_stream<Char>&>()
<< std::declval<U>()),
void_t<>>::value>
test(int);
template <typename> static std::false_type test(...);
using result = decltype(test<T>(0));
public:
static const bool value = result::value;
};
inline bool write_ostream_unicode(std::ostream& os, fmt::string_view data) {
#if FMT_MSC_VERSION
if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf()))
if (FILE* f = get_file(*buf)) return write_console(f, data);
#elif defined(_WIN32) && defined(__GLIBCXX__)
auto* rdbuf = os.rdbuf();
FILE* c_file;
if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
c_file = sfbuf->file();
else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
c_file = fbuf->file();
else
return false;
if (c_file) return write_console(c_file, data);
#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
if (auto* buf = dynamic_cast<std::__stdoutbuf<char>*>(os.rdbuf()))
if (FILE* f = get_file(*buf)) return write_console(f, data);
#else
ignore_unused(os, data);
#endif
return false;
}
inline bool write_ostream_unicode(std::wostream&,
fmt::basic_string_view<wchar_t>) {
return false;
}
// Write the content of buf to os.
// It is a separate function rather than a part of vprint to simplify testing.
template <typename Char>
void write(std::basic_ostream<Char>& os, buffer<Char>& buf) {
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
const Char* buf_data = buf.data();
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
unsigned_streamsize size = buf.size();
@ -91,34 +89,80 @@ void write(std::basic_ostream<Char>& os, buffer<Char>& buf) {
template <typename Char, typename T>
void format_value(buffer<Char>& buf, const T& value,
locale_ref loc = locale_ref()) {
formatbuf<Char> format_buf(buf);
std::basic_ostream<Char> output(&format_buf);
auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf);
auto&& output = std::basic_ostream<Char>(&format_buf);
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
if (loc) output.imbue(loc.get<std::locale>());
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
#endif
output << value;
buf.resize(buf.size());
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
}
template <typename T> struct streamed_view { const T& value; };
} // namespace detail
// Formats an object of type T that has an overloaded ostream operator<<.
template <typename T, typename Char>
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
: formatter<basic_string_view<Char>, Char> {
template <typename Context>
auto format(const T& value, Context& ctx) -> decltype(ctx.out()) {
basic_memory_buffer<Char> buffer;
format_value(buffer, value, ctx.locale());
basic_string_view<Char> str(buffer.data(), buffer.size());
return formatter<basic_string_view<Char>, Char>::format(str, ctx);
template <typename Char>
struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
void set_debug_format() = delete;
template <typename T, typename OutputIt>
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const
-> OutputIt {
auto buffer = basic_memory_buffer<Char>();
detail::format_value(buffer, value, ctx.locale());
return formatter<basic_string_view<Char>, Char>::format(
{buffer.data(), buffer.size()}, ctx);
}
};
} // namespace internal
template <typename Char>
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
basic_format_args<buffer_context<Char>> args) {
basic_memory_buffer<Char> buffer;
internal::vformat_to(buffer, format_str, args);
internal::write(os, buffer);
using ostream_formatter = basic_ostream_formatter<char>;
template <typename T, typename Char>
struct formatter<detail::streamed_view<T>, Char>
: basic_ostream_formatter<Char> {
template <typename OutputIt>
auto format(detail::streamed_view<T> view,
basic_format_context<OutputIt, Char>& ctx) const -> OutputIt {
return basic_ostream_formatter<Char>::format(view.value, ctx);
}
};
/**
\rst
Returns a view that formats `value` via an ostream ``operator<<``.
**Example**::
fmt::print("Current thread id: {}\n",
fmt::streamed(std::this_thread::get_id()));
\endrst
*/
template <typename T>
auto streamed(const T& value) -> detail::streamed_view<T> {
return {value};
}
namespace detail {
inline void vprint_directly(std::ostream& os, string_view format_str,
format_args args) {
auto buffer = memory_buffer();
detail::vformat_to(buffer, format_str, args);
detail::write_buffer(os, buffer);
}
} // namespace detail
FMT_EXPORT template <typename Char>
void vprint(std::basic_ostream<Char>& os,
basic_string_view<type_identity_t<Char>> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
auto buffer = basic_memory_buffer<Char>();
detail::vformat_to(buffer, format_str, args);
if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return;
detail::write_buffer(os, buffer);
}
/**
@ -130,12 +174,36 @@ void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
fmt::print(cerr, "Don't {}!", "panic");
\endrst
*/
template <typename S, typename... Args,
typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
vprint(os, to_string_view(format_str),
{internal::make_args_checked<Args...>(format_str, args...)});
FMT_EXPORT template <typename... T>
void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
const auto& vargs = fmt::make_format_args(args...);
if (detail::is_utf8())
vprint(os, fmt, vargs);
else
detail::vprint_directly(os, fmt, vargs);
}
FMT_EXPORT
template <typename... Args>
void print(std::wostream& os,
basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
Args&&... args) {
vprint(os, fmt, fmt::make_format_args<buffer_context<wchar_t>>(args...));
}
FMT_EXPORT template <typename... T>
void println(std::ostream& os, format_string<T...> fmt, T&&... args) {
fmt::print(os, "{}\n", fmt::format(fmt, std::forward<T>(args)...));
}
FMT_EXPORT
template <typename... Args>
void println(std::wostream& os,
basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
Args&&... args) {
print(os, L"{}\n", fmt::format(fmt, std::forward<Args>(args)...));
}
FMT_END_NAMESPACE
#endif // FMT_OSTREAM_H_

View File

@ -1,321 +0,0 @@
// 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_
#if defined(__MINGW32__) || defined(__CYGWIN__)
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
# undef __STRICT_ANSI__
#endif
#include <cerrno>
#include <clocale> // for locale_t
#include <cstdio>
#include <cstdlib> // for strtod_l
#include <cstddef>
#if defined __APPLE__ || defined(__FreeBSD__)
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
#endif
#include "format.h"
// UWP doesn't provide _pipe.
#if FMT_HAS_INCLUDE("winapifamily.h")
# include <winapifamily.h>
#endif
#if FMT_HAS_INCLUDE("fcntl.h") && \
(!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
# include <fcntl.h> // for O_RDONLY
# define FMT_USE_FCNTL 1
#else
# define FMT_USE_FCNTL 0
#endif
#ifndef FMT_POSIX
# if defined(_WIN32) && !defined(__MINGW32__)
// Fix warnings about deprecated symbols.
# define FMT_POSIX(call) _##call
# else
# define FMT_POSIX(call) call
# endif
#endif
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
#ifdef FMT_SYSTEM
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
#else
# define FMT_SYSTEM(call) call
# ifdef _WIN32
// Fix warnings about deprecated symbols.
# define FMT_POSIX_CALL(call) ::_##call
# else
# define FMT_POSIX_CALL(call) ::call
# endif
#endif
// Retries the expression while it evaluates to error_result and errno
// equals to EINTR.
#ifndef _WIN32
# define FMT_RETRY_VAL(result, expression, error_result) \
do { \
(result) = (expression); \
} while ((result) == (error_result) && errno == EINTR)
#else
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
#endif
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
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 type aliases 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_; }
};
using cstring_view = basic_cstring_view<char>;
using wcstring_view = basic_cstring_view<wchar_t>;
// An error code.
class error_code {
private:
int value_;
public:
explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {}
int get() const FMT_NOEXCEPT { return value_; }
};
// A buffered file.
class buffered_file {
private:
FILE* file_;
friend class file;
explicit buffered_file(FILE* f) : file_(f) {}
public:
buffered_file(const buffered_file&) = delete;
void operator=(const buffered_file&) = delete;
// Constructs a buffered_file object which doesn't represent any file.
buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
// Destroys the object closing the file it represents if any.
FMT_API ~buffered_file() FMT_NOEXCEPT;
public:
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
other.file_ = nullptr;
}
buffered_file& operator=(buffered_file&& other) {
close();
file_ = other.file_;
other.file_ = nullptr;
return *this;
}
// Opens a file.
FMT_API buffered_file(cstring_view filename, cstring_view mode);
// Closes the file.
FMT_API void close();
// Returns the pointer to a FILE object representing this file.
FILE* get() const FMT_NOEXCEPT { return file_; }
// We place parentheses around fileno to workaround a bug in some versions
// of MinGW that define fileno as a macro.
FMT_API int(fileno)() const;
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...));
}
};
#if FMT_USE_FCNTL
// A file. Closed file is represented by a file object with descriptor -1.
// Methods that are not declared with FMT_NOEXCEPT may throw
// 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 {
private:
int fd_; // File descriptor.
// Constructs a file object with a given descriptor.
explicit file(int fd) : fd_(fd) {}
public:
// Possible values for the oflag argument to the constructor.
enum {
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
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) {}
// Opens a file and constructs a file object representing this file.
FMT_API file(cstring_view path, int oflag);
public:
file(const file&) = delete;
void operator=(const file&) = delete;
file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
file& operator=(file&& other) FMT_NOEXCEPT {
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
// Destroys the object closing the file it represents if any.
FMT_API ~file() FMT_NOEXCEPT;
// Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT { return fd_; }
// Closes the file.
FMT_API void close();
// Returns the file size. The size has signed type for consistency with
// stat::st_size.
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);
// Attempts to write count bytes from the specified buffer to the file.
FMT_API std::size_t write(const void* buffer, std::size_t count);
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
FMT_API static file dup(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
FMT_API void dup2(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
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);
// 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();
#endif // FMT_USE_FCNTL
#ifdef FMT_LOCALE
// A "C" numeric locale.
class Locale {
private:
# ifdef _WIN32
using locale_t = _locale_t;
enum { LC_NUMERIC_MASK = LC_NUMERIC };
static locale_t newlocale(int category_mask, const char* locale, locale_t) {
return _create_locale(category_mask, locale);
}
static void freelocale(locale_t locale) { _free_locale(locale); }
static double strtod_l(const char* nptr, char** endptr, _locale_t locale) {
return _strtod_l(nptr, endptr, locale);
}
# endif
locale_t locale_;
public:
using type = locale_t;
Locale(const Locale&) = delete;
void operator=(const Locale&) = delete;
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", nullptr)) {
if (!locale_) FMT_THROW(system_error(errno, "cannot create locale"));
}
~Locale() { freelocale(locale_); }
type get() const { return locale_; }
// Converts string to floating-point number and advances str past the end
// of the parsed input.
double strtod(const char*& str) const {
char* end = nullptr;
double result = strtod_l(str, &end, locale_);
str = end;
return result;
}
};
#endif // FMT_LOCALE
FMT_END_NAMESPACE
#endif // FMT_POSIX_H_

View File

@ -11,55 +11,91 @@
#include <algorithm> // std::max
#include <limits> // std::numeric_limits
#include "ostream.h"
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace internal {
FMT_BEGIN_EXPORT
template <typename T> struct printf_formatter { printf_formatter() = delete; };
template <typename Char> class basic_printf_context {
private:
detail::buffer_appender<Char> out_;
basic_format_args<basic_printf_context> args_;
public:
using char_type = Char;
using parse_context_type = basic_format_parse_context<Char>;
template <typename T> using formatter_type = printf_formatter<T>;
/**
\rst
Constructs a ``printf_context`` object. References to the arguments are
stored in the context object so make sure they have appropriate lifetimes.
\endrst
*/
basic_printf_context(detail::buffer_appender<Char> out,
basic_format_args<basic_printf_context> args)
: out_(out), args_(args) {}
auto out() -> detail::buffer_appender<Char> { return out_; }
void advance_to(detail::buffer_appender<Char>) {}
auto locale() -> detail::locale_ref { return {}; }
auto arg(int id) const -> basic_format_arg<basic_printf_context> {
return args_.get(id);
}
FMT_CONSTEXPR void on_error(const char* message) {
detail::error_handler().on_error(message);
}
};
namespace detail {
// 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) {
template <typename T> static auto fits_in_int(T value) -> bool {
unsigned max = max_value<int>();
return value <= max;
}
static bool fits_in_int(bool) { return true; }
static auto fits_in_int(bool) -> 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() &&
template <typename T> static auto fits_in_int(T value) -> bool {
return value >= (std::numeric_limits<int>::min)() &&
value <= max_value<int>();
}
static bool fits_in_int(int) { return true; }
static auto fits_in_int(int) -> bool { return true; }
};
class printf_precision_handler {
public:
struct printf_precision_handler {
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
int operator()(T value) {
auto operator()(T value) -> int {
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
FMT_THROW(format_error("number is too big"));
throw_format_error("number is too big");
return (std::max)(static_cast<int>(value), 0);
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
int operator()(T) {
FMT_THROW(format_error("precision is not integer"));
auto operator()(T) -> int {
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:
struct is_zero_int {
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
bool operator()(T value) {
auto operator()(T value) -> bool {
return value == 0;
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
bool operator()(T) {
auto operator()(T) -> bool {
return false;
}
};
@ -90,22 +126,23 @@ template <typename T, typename Context> class arg_converter {
if (const_check(sizeof(target_type) <= sizeof(int))) {
// Extra casts are used to silence warnings.
if (is_signed) {
arg_ = internal::make_arg<Context>(
static_cast<int>(static_cast<target_type>(value)));
auto n = static_cast<int>(static_cast<target_type>(value));
arg_ = detail::make_arg<Context>(n);
} else {
using unsigned_type = typename make_unsigned_or_bool<target_type>::type;
arg_ = internal::make_arg<Context>(
static_cast<unsigned>(static_cast<unsigned_type>(value)));
auto n = static_cast<unsigned>(static_cast<unsigned_type>(value));
arg_ = detail::make_arg<Context>(n);
}
} 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));
auto n = static_cast<long long>(value);
arg_ = detail::make_arg<Context>(n);
} else {
arg_ = internal::make_arg<Context>(
static_cast<typename make_unsigned_or_bool<U>::type>(value));
auto n = static_cast<typename make_unsigned_or_bool<U>::type>(value);
arg_ = detail::make_arg<Context>(n);
}
}
}
@ -133,245 +170,142 @@ template <typename Context> class char_converter {
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
void operator()(T value) {
arg_ = internal::make_arg<Context>(
static_cast<typename Context::char_type>(value));
auto c = static_cast<typename Context::char_type>(value);
arg_ = detail::make_arg<Context>(c);
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
void operator()(T) {} // No conversion needed for non-integral types.
};
// An argument visitor that return a pointer to a C string if argument is a
// string or null otherwise.
template <typename Char> struct get_cstring {
template <typename T> auto operator()(T) -> const Char* { return nullptr; }
auto operator()(const Char* s) -> const Char* { return s; }
};
// 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 {
private:
using format_specs = basic_format_specs<Char>;
format_specs& specs_;
format_specs<Char>& specs_;
public:
explicit printf_width_handler(format_specs& specs) : specs_(specs) {}
explicit printf_width_handler(format_specs<Char>& specs) : specs_(specs) {}
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
unsigned operator()(T value) {
auto operator()(T value) -> unsigned {
auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
if (internal::is_negative(value)) {
if (detail::is_negative(value)) {
specs_.align = align::left;
width = 0 - width;
}
unsigned int_max = max_value<int>();
if (width > int_max) FMT_THROW(format_error("number is too big"));
if (width > int_max) throw_format_error("number is too big");
return static_cast<unsigned>(width);
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
unsigned operator()(T) {
FMT_THROW(format_error("width is not integer"));
auto operator()(T) -> unsigned {
throw_format_error("width is not integer");
return 0;
}
};
template <typename Char, typename Context>
void printf(buffer<Char>& buf, basic_string_view<Char> format,
basic_format_args<Context> args) {
Context(std::back_inserter(buf), format, args).format();
// Workaround for a bug with the XL compiler when initializing
// printf_arg_formatter's base class.
template <typename Char>
auto make_arg_formatter(buffer_appender<Char> iter, format_specs<Char>& s)
-> arg_formatter<Char> {
return {iter, s, locale_ref()};
}
template <typename OutputIt, typename Char, typename Context>
internal::truncating_iterator<OutputIt> printf(
internal::truncating_iterator<OutputIt> it, basic_string_view<Char> format,
basic_format_args<Context> args) {
return Context(it, format, args).format();
}
} // namespace internal
using internal::printf; // For printing into memory_buffer.
template <typename Range> class printf_arg_formatter;
template <typename OutputIt, typename Char> class basic_printf_context;
/**
\rst
The ``printf`` argument formatter.
\endrst
*/
template <typename Range>
class printf_arg_formatter : public internal::arg_formatter_base<Range> {
public:
using iterator = typename Range::iterator;
// The ``printf`` argument formatter.
template <typename Char>
class printf_arg_formatter : public arg_formatter<Char> {
private:
using char_type = typename Range::value_type;
using base = internal::arg_formatter_base<Range>;
using context_type = basic_printf_context<iterator, char_type>;
using base = arg_formatter<Char>;
using context_type = basic_printf_context<Char>;
context_type& context_;
void write_null_pointer(char) {
this->specs()->type = 0;
this->write("(nil)");
}
void write_null_pointer(wchar_t) {
this->specs()->type = 0;
this->write(L"(nil)");
void write_null_pointer(bool is_string = false) {
auto s = this->specs;
s.type = presentation_type::none;
write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
}
public:
using format_specs = typename base::format_specs;
printf_arg_formatter(buffer_appender<Char> iter, format_specs<Char>& s,
context_type& ctx)
: base(make_arg_formatter(iter, s)), context_(ctx) {}
/**
\rst
Constructs an argument formatter object.
*buffer* is a reference to the output buffer and *specs* contains format
specifier information for standard argument types.
\endrst
*/
printf_arg_formatter(iterator iter, format_specs& specs, context_type& ctx)
: base(Range(iter), &specs, internal::locale_ref()), context_(ctx) {}
void operator()(monostate value) { base::operator()(value); }
template <typename T, FMT_ENABLE_IF(fmt::internal::is_integral<T>::value)>
iterator 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_specs = *this->specs();
if (fmt_specs.type != 's') return base::operator()(value ? 1 : 0);
fmt_specs.type = 0;
this->write(value != 0);
} else if (std::is_same<T, char_type>::value) {
format_specs& fmt_specs = *this->specs();
if (fmt_specs.type && fmt_specs.type != 'c')
return (*this)(static_cast<int>(value));
fmt_specs.sign = sign::none;
fmt_specs.alt = false;
fmt_specs.align = align::right;
return base::operator()(value);
} else {
return base::operator()(value);
template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)>
void operator()(T value) {
// MSVC2013 fails to compile separate overloads for bool and Char so use
// std::is_same instead.
if (!std::is_same<T, Char>::value) {
base::operator()(value);
return;
}
return this->out();
format_specs<Char> fmt_specs = this->specs;
if (fmt_specs.type != presentation_type::none &&
fmt_specs.type != presentation_type::chr) {
return (*this)(static_cast<int>(value));
}
fmt_specs.sign = sign::none;
fmt_specs.alt = false;
fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types.
// align::numeric needs to be overwritten here since the '0' flag is
// ignored for non-numeric types
if (fmt_specs.align == align::none || fmt_specs.align == align::numeric)
fmt_specs.align = align::right;
write<Char>(this->out, static_cast<Char>(value), fmt_specs);
}
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
iterator operator()(T value) {
return base::operator()(value);
void operator()(T value) {
base::operator()(value);
}
/** Formats a null-terminated C string. */
iterator operator()(const char* value) {
void operator()(const char* value) {
if (value)
base::operator()(value);
else if (this->specs()->type == 'p')
write_null_pointer(char_type());
else
this->write("(null)");
return this->out();
write_null_pointer(this->specs.type != presentation_type::pointer);
}
/** Formats a null-terminated wide C string. */
iterator operator()(const wchar_t* value) {
void operator()(const wchar_t* value) {
if (value)
base::operator()(value);
else if (this->specs()->type == 'p')
write_null_pointer(char_type());
else
this->write(L"(null)");
return this->out();
write_null_pointer(this->specs.type != presentation_type::pointer);
}
iterator operator()(basic_string_view<char_type> value) {
return base::operator()(value);
}
iterator operator()(monostate value) { return base::operator()(value); }
void operator()(basic_string_view<Char> value) { base::operator()(value); }
/** Formats a pointer. */
iterator operator()(const void* value) {
if (value) return base::operator()(value);
this->specs()->type = 0;
write_null_pointer(char_type());
return this->out();
void operator()(const void* value) {
if (value)
base::operator()(value);
else
write_null_pointer();
}
/** Formats an argument of a custom (user-defined) type. */
iterator operator()(typename basic_format_arg<context_type>::handle handle) {
handle.format(context_.parse_context(), context_);
return this->out();
void operator()(typename basic_format_arg<context_type>::handle handle) {
auto parse_ctx = basic_format_parse_context<Char>({});
handle.format(parse_ctx, context_);
}
};
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> class basic_printf_context {
public:
/** The character type for the output. */
using char_type = Char;
using format_arg = basic_format_arg<basic_printf_context>;
template <typename T> using formatter_type = printf_formatter<T>;
private:
using format_specs = basic_format_specs<char_type>;
OutputIt out_;
basic_format_args<basic_printf_context> args_;
basic_format_parse_context<Char> parse_ctx_;
static void parse_flags(format_specs& specs, const Char*& it,
const Char* end);
// Returns the argument with specified index or, if arg_index is equal
// to the maximum unsigned value, the next argument.
format_arg get_arg(unsigned arg_index = internal::max_value<unsigned>());
// Parses argument index, flags and width and returns the argument index.
unsigned parse_header(const Char*& it, const Char* end, format_specs& specs);
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)
: out_(out), args_(args), parse_ctx_(format_str) {}
OutputIt out() { return out_; }
void advance_to(OutputIt it) { out_ = it; }
format_arg arg(unsigned id) const { return args_.get(id); }
basic_format_parse_context<Char>& parse_context() { return parse_ctx_; }
FMT_CONSTEXPR void on_error(const char* message) {
parse_ctx_.on_error(message);
}
/** Formats stored arguments and writes the output to the range. */
template <typename ArgFormatter = printf_arg_formatter<buffer_range<Char>>>
OutputIt format();
};
template <typename OutputIt, typename Char>
void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& specs,
const Char*& it,
const Char* end) {
template <typename Char>
void parse_flags(format_specs<Char>& specs, const Char*& it, const Char* end) {
for (; it != end; ++it) {
switch (*it) {
case '-':
@ -384,7 +318,7 @@ void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& specs,
specs.fill[0] = '0';
break;
case ' ':
specs.sign = sign::space;
if (specs.sign != sign::plus) specs.sign = sign::space;
break;
case '#':
specs.alt = true;
@ -395,34 +329,24 @@ void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& specs,
}
}
template <typename OutputIt, typename Char>
typename basic_printf_context<OutputIt, Char>::format_arg
basic_printf_context<OutputIt, Char>::get_arg(unsigned arg_index) {
if (arg_index == internal::max_value<unsigned>())
arg_index = parse_ctx_.next_arg_id();
else
parse_ctx_.check_arg_id(--arg_index);
return internal::get_arg(*this, arg_index);
}
template <typename OutputIt, typename Char>
unsigned basic_printf_context<OutputIt, Char>::parse_header(
const Char*& it, const Char* end, format_specs& specs) {
unsigned arg_index = internal::max_value<unsigned>();
char_type c = *it;
template <typename Char, typename GetArg>
auto parse_header(const Char*& it, const Char* end, format_specs<Char>& specs,
GetArg get_arg) -> int {
int arg_index = -1;
Char 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, end, eh);
int value = parse_nonnegative_int(it, end, -1);
if (it != end && *it == '$') { // value is an argument index
++it;
arg_index = value;
arg_index = value != -1 ? value : max_value<int>();
} else {
if (c == '0') specs.fill[0] = '0';
if (value != 0) {
// Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now.
if (value == -1) throw_format_error("number is too big");
specs.width = value;
return arg_index;
}
@ -432,71 +356,140 @@ unsigned basic_printf_context<OutputIt, Char>::parse_header(
// Parse width.
if (it != end) {
if (*it >= '0' && *it <= '9') {
internal::error_handler eh;
specs.width = parse_nonnegative_int(it, end, eh);
specs.width = parse_nonnegative_int(it, end, -1);
if (specs.width == -1) throw_format_error("number is too big");
} else if (*it == '*') {
++it;
specs.width = visit_format_arg(
internal::printf_width_handler<char_type>(specs), get_arg());
specs.width = static_cast<int>(visit_format_arg(
detail::printf_width_handler<Char>(specs), get_arg(-1)));
}
}
return arg_index;
}
template <typename OutputIt, typename Char>
template <typename ArgFormatter>
OutputIt basic_printf_context<OutputIt, Char>::format() {
auto out = this->out();
const Char* start = parse_ctx_.begin();
const Char* end = parse_ctx_.end();
inline auto parse_printf_presentation_type(char c, type t)
-> presentation_type {
using pt = presentation_type;
constexpr auto integral_set = sint_set | uint_set | bool_set | char_set;
switch (c) {
case 'd':
return in(t, integral_set) ? pt::dec : pt::none;
case 'o':
return in(t, integral_set) ? pt::oct : pt::none;
case 'x':
return in(t, integral_set) ? pt::hex_lower : pt::none;
case 'X':
return in(t, integral_set) ? pt::hex_upper : pt::none;
case 'a':
return in(t, float_set) ? pt::hexfloat_lower : pt::none;
case 'A':
return in(t, float_set) ? pt::hexfloat_upper : pt::none;
case 'e':
return in(t, float_set) ? pt::exp_lower : pt::none;
case 'E':
return in(t, float_set) ? pt::exp_upper : pt::none;
case 'f':
return in(t, float_set) ? pt::fixed_lower : pt::none;
case 'F':
return in(t, float_set) ? pt::fixed_upper : pt::none;
case 'g':
return in(t, float_set) ? pt::general_lower : pt::none;
case 'G':
return in(t, float_set) ? pt::general_upper : pt::none;
case 'c':
return in(t, integral_set) ? pt::chr : pt::none;
case 's':
return in(t, string_set | cstring_set) ? pt::string : pt::none;
case 'p':
return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none;
default:
return pt::none;
}
}
template <typename Char, typename Context>
void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
basic_format_args<Context> args) {
using iterator = buffer_appender<Char>;
auto out = iterator(buf);
auto context = basic_printf_context<Char>(out, args);
auto parse_ctx = basic_format_parse_context<Char>(format);
// Returns the argument with specified index or, if arg_index is -1, the next
// argument.
auto get_arg = [&](int arg_index) {
if (arg_index < 0)
arg_index = parse_ctx.next_arg_id();
else
parse_ctx.check_arg_id(--arg_index);
return detail::get_arg(context, arg_index);
};
const Char* start = parse_ctx.begin();
const Char* end = parse_ctx.end();
auto it = start;
while (it != end) {
char_type c = *it++;
if (c != '%') continue;
if (!find<false, Char>(it, end, '%', it)) {
it = end; // find leaves it == nullptr if it doesn't find '%'.
break;
}
Char c = *it++;
if (it != end && *it == c) {
out = std::copy(start, it, out);
write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
start = ++it;
continue;
}
out = std::copy(start, it - 1, out);
write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start)));
format_specs specs;
auto specs = format_specs<Char>();
specs.align = align::right;
// Parse argument index, flags and width.
unsigned arg_index = parse_header(it, end, specs);
if (arg_index == 0) on_error("argument index out of range");
int arg_index = parse_header(it, end, specs, get_arg);
if (arg_index == 0) throw_format_error("argument not found");
// Parse precision.
if (it != end && *it == '.') {
++it;
c = it != end ? *it : 0;
if ('0' <= c && c <= '9') {
internal::error_handler eh;
specs.precision = static_cast<int>(parse_nonnegative_int(it, end, eh));
specs.precision = parse_nonnegative_int(it, end, 0);
} else if (c == '*') {
++it;
specs.precision =
visit_format_arg(internal::printf_precision_handler(), get_arg());
specs.precision = static_cast<int>(
visit_format_arg(printf_precision_handler(), get_arg(-1)));
} else {
specs.precision = 0;
}
}
format_arg arg = get_arg(arg_index);
if (specs.alt && visit_format_arg(internal::is_zero_int(), arg))
specs.alt = false;
auto arg = get_arg(arg_index);
// For d, i, o, u, x, and X conversion specifiers, if a precision is
// specified, the '0' flag is ignored
if (specs.precision >= 0 && arg.is_integral()) {
// Ignore '0' for non-numeric types or if '-' present.
specs.fill[0] = ' ';
}
if (specs.precision >= 0 && arg.type() == type::cstring_type) {
auto str = visit_format_arg(get_cstring<Char>(), arg);
auto str_end = str + specs.precision;
auto nul = std::find(str, str_end, Char());
auto sv = basic_string_view<Char>(
str, to_unsigned(nul != str_end ? nul - str : specs.precision));
arg = make_arg<basic_printf_context<Char>>(sv);
}
if (specs.alt && visit_format_arg(is_zero_int(), arg)) specs.alt = false;
if (specs.fill[0] == '0') {
if (arg.is_arithmetic())
if (arg.is_arithmetic() && specs.align != align::left)
specs.align = align::numeric;
else
specs.fill[0] = ' '; // Ignore '0' flag for non-numeric types.
specs.fill[0] = ' '; // Ignore '0' flag for non-numeric types or if '-'
// flag is also present.
}
// Parse length and convert the argument to the required type.
c = it != end ? *it++ : 0;
char_type t = it != end ? *it : 0;
using internal::convert_arg;
Char t = it != end ? *it : 0;
switch (c) {
case 'h':
if (t == 'h') {
@ -520,7 +513,7 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
convert_arg<intmax_t>(arg, t);
break;
case 'z':
convert_arg<std::size_t>(arg, t);
convert_arg<size_t>(arg, t);
break;
case 't':
convert_arg<std::ptrdiff_t>(arg, t);
@ -535,37 +528,35 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
}
// Parse type.
if (it == end) FMT_THROW(format_error("invalid format string"));
specs.type = static_cast<char>(*it++);
if (it == end) throw_format_error("invalid format string");
char type = static_cast<char>(*it++);
if (arg.is_integral()) {
// Normalize type.
switch (specs.type) {
switch (type) {
case 'i':
case 'u':
specs.type = 'd';
type = 'd';
break;
case 'c':
visit_format_arg(internal::char_converter<basic_printf_context>(arg),
arg);
visit_format_arg(char_converter<basic_printf_context<Char>>(arg), arg);
break;
}
}
specs.type = parse_printf_presentation_type(type, arg.type());
if (specs.type == presentation_type::none)
throw_format_error("invalid format specifier");
start = it;
// Format argument.
visit_format_arg(ArgFormatter(out, specs, *this), arg);
visit_format_arg(printf_arg_formatter<Char>(out, specs, context), arg);
}
return std::copy(start, it, out);
write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
}
} // namespace detail
template <typename Char>
using basic_printf_context_t =
basic_printf_context<std::back_insert_iterator<internal::buffer<Char>>,
Char>;
using printf_context = basic_printf_context_t<char>;
using wprintf_context = basic_printf_context_t<wchar_t>;
using printf_context = basic_printf_context<char>;
using wprintf_context = basic_printf_context<wchar_t>;
using printf_args = basic_format_args<printf_context>;
using wprintf_args = basic_format_args<wprintf_context>;
@ -576,30 +567,27 @@ using wprintf_args = basic_format_args<wprintf_context>;
arguments and can be implicitly converted to `~fmt::printf_args`.
\endrst
*/
template <typename... Args>
inline format_arg_store<printf_context, Args...> make_printf_args(
const Args&... args) {
template <typename... T>
inline auto make_printf_args(const T&... args)
-> format_arg_store<printf_context, T...> {
return {args...};
}
/**
\rst
Constructs an `~fmt::format_arg_store` object that contains references to
arguments and can be implicitly converted to `~fmt::wprintf_args`.
\endrst
*/
template <typename... Args>
inline format_arg_store<wprintf_context, Args...> make_wprintf_args(
const Args&... args) {
// DEPRECATED!
template <typename... T>
inline auto make_wprintf_args(const T&... args)
-> format_arg_store<wprintf_context, T...> {
return {args...};
}
template <typename S, typename Char = char_t<S>>
inline std::basic_string<Char> vsprintf(
const S& format, basic_format_args<basic_printf_context_t<Char>> args) {
basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args);
return to_string(buffer);
template <typename Char>
inline auto vsprintf(
basic_string_view<Char> fmt,
basic_format_args<basic_printf_context<type_identity_t<Char>>> args)
-> std::basic_string<Char> {
auto buf = basic_memory_buffer<Char>();
detail::vprintf(buf, fmt, args);
return to_string(buf);
}
/**
@ -611,20 +599,22 @@ inline std::basic_string<Char> vsprintf(
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
*/
template <typename S, typename... Args,
typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
inline std::basic_string<Char> sprintf(const S& format, const Args&... args) {
using context = basic_printf_context_t<Char>;
return vsprintf(to_string_view(format), {make_format_args<context>(args...)});
template <typename S, typename... T,
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> {
return vsprintf(detail::to_string_view(fmt),
fmt::make_format_args<basic_printf_context<Char>>(args...));
}
template <typename S, typename Char = char_t<S>>
inline int vfprintf(std::FILE* f, const S& format,
basic_format_args<basic_printf_context_t<Char>> args) {
basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args);
std::size_t size = buffer.size();
return std::fwrite(buffer.data(), sizeof(Char), size, f) < size
template <typename Char>
inline auto vfprintf(
std::FILE* f, basic_string_view<Char> fmt,
basic_format_args<basic_printf_context<type_identity_t<Char>>> args)
-> int {
auto buf = basic_memory_buffer<Char>();
detail::vprintf(buf, fmt, args);
size_t size = buf.size();
return std::fwrite(buf.data(), sizeof(Char), size, f) < size
? -1
: static_cast<int>(size);
}
@ -638,18 +628,18 @@ inline int vfprintf(std::FILE* f, const S& format,
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
template <typename S, typename... Args,
typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
inline int fprintf(std::FILE* f, const S& format, const Args&... args) {
using context = basic_printf_context_t<Char>;
return vfprintf(f, to_string_view(format),
{make_format_args<context>(args...)});
template <typename S, typename... T, typename Char = char_t<S>>
inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int {
return vfprintf(f, detail::to_string_view(fmt),
fmt::make_format_args<basic_printf_context<Char>>(args...));
}
template <typename S, typename Char = char_t<S>>
inline int vprintf(const S& format,
basic_format_args<basic_printf_context_t<Char>> args) {
return vfprintf(stdout, to_string_view(format), args);
template <typename Char>
FMT_DEPRECATED inline auto vprintf(
basic_string_view<Char> fmt,
basic_format_args<basic_printf_context<type_identity_t<Char>>> args)
-> int {
return vfprintf(stdout, fmt, args);
}
/**
@ -661,51 +651,17 @@ inline int vprintf(const S& format,
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
template <typename S, typename... Args,
FMT_ENABLE_IF(internal::is_string<S>::value)>
inline int printf(const S& format_str, const Args&... args) {
using context = basic_printf_context_t<char_t<S>>;
return vprintf(to_string_view(format_str),
{make_format_args<context>(args...)});
template <typename... T>
inline auto printf(string_view fmt, const T&... args) -> int {
return vfprintf(stdout, fmt, make_printf_args(args...));
}
template <typename... T>
FMT_DEPRECATED inline auto printf(basic_string_view<wchar_t> fmt,
const T&... args) -> int {
return vfprintf(stdout, fmt, make_wprintf_args(args...));
}
template <typename S, typename Char = char_t<S>>
inline int vfprintf(std::basic_ostream<Char>& os, const S& format,
basic_format_args<basic_printf_context_t<Char>> args) {
basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args);
internal::write(os, buffer);
return static_cast<int>(buffer.size());
}
/** Formats arguments and writes the output to the range. */
template <typename ArgFormatter, typename Char,
typename Context =
basic_printf_context<typename ArgFormatter::iterator, Char>>
typename ArgFormatter::iterator vprintf(internal::buffer<Char>& out,
basic_string_view<Char> format_str,
basic_format_args<Context> args) {
typename ArgFormatter::iterator iter(out);
Context(iter, format_str, args).template format<ArgFormatter>();
return iter;
}
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fmt::fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
template <typename S, typename... Args, typename Char = char_t<S>>
inline int fprintf(std::basic_ostream<Char>& os, const S& format_str,
const Args&... args) {
using context = basic_printf_context_t<Char>;
return vfprintf(os, to_string_view(format_str),
{make_format_args<context>(args...)});
}
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_PRINTF_H_

View File

@ -12,331 +12,682 @@
#ifndef FMT_RANGES_H_
#define FMT_RANGES_H_
#include <initializer_list>
#include <tuple>
#include <type_traits>
#include "format.h"
// output only up to N items from the range.
#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT
# define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256
#endif
#include "format.h"
FMT_BEGIN_NAMESPACE
template <typename Char> struct formatting_base {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
};
namespace detail {
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>
OutputIterator copy(const RangeT& range, OutputIterator out) {
template <typename Range, typename OutputIt>
auto copy(const Range& range, OutputIt out) -> OutputIt {
for (auto it = range.begin(), end = range.end(); it != end; ++it)
*out++ = *it;
return out;
}
template <typename OutputIterator>
OutputIterator copy(const char* str, OutputIterator out) {
template <typename OutputIt>
auto copy(const char* str, OutputIt out) -> OutputIt {
while (*str) *out++ = *str++;
return out;
}
template <typename OutputIterator>
OutputIterator copy(char ch, OutputIterator out) {
template <typename OutputIt> auto copy(char ch, OutputIt out) -> OutputIt {
*out++ = ch;
return out;
}
/// Return true value if T has std::string interface, like std::string_view.
template <typename T> class is_like_std_string {
template <typename OutputIt> auto copy(wchar_t ch, OutputIt out) -> OutputIt {
*out++ = ch;
return out;
}
// Returns true if T has a std::string-like interface, like std::string_view.
template <typename T> class is_std_string_like {
template <typename U>
static auto check(U* p)
-> decltype((void)p->find('a'), p->length(), (void)p->data(), int());
template <typename> static void check(...);
public:
static FMT_CONSTEXPR_DECL const bool value =
is_string<T>::value || !std::is_void<decltype(check<T>(nullptr))>::value;
static constexpr const bool value =
is_string<T>::value ||
std::is_convertible<T, std_string_view<char>>::value ||
!std::is_void<decltype(check<T>(nullptr))>::value;
};
template <typename Char>
struct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {};
struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
template <typename T> class is_map {
template <typename U> static auto check(U*) -> typename U::mapped_type;
template <typename> static void check(...);
public:
#ifdef FMT_FORMAT_MAP_AS_LIST // DEPRECATED!
static constexpr const bool value = false;
#else
static constexpr const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value;
#endif
};
template <typename T> class is_set {
template <typename U> static auto check(U*) -> typename U::key_type;
template <typename> static void check(...);
public:
#ifdef FMT_FORMAT_SET_AS_LIST // DEPRECATED!
static constexpr const bool value = false;
#else
static constexpr const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
#endif
};
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
#if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1800
# define FMT_DECLTYPE_RETURN(val) \
->decltype(val) { return val; } \
static_assert( \
true, "") // This makes it so that a semicolon is required after the
// macro, which helps clang-format handle the formatting.
// C array overload
template <typename T, std::size_t N>
auto range_begin(const T (&arr)[N]) -> const T* {
return arr;
}
template <typename T, std::size_t N>
auto range_end(const T (&arr)[N]) -> const T* {
return arr + N;
}
template <typename T, typename Enable = void>
struct has_member_fn_begin_end_t : std::false_type {};
template <typename T>
struct is_range_<
T, conditional_t<false,
conditional_helper<decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end())>,
void>> : std::true_type {};
struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end())>>
: std::true_type {};
// Member function overload
template <typename T>
auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin());
template <typename T>
auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end());
// ADL overload. Only participates in overload resolution if member functions
// are not found.
template <typename T>
auto range_begin(T&& rng)
-> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
decltype(begin(static_cast<T&&>(rng)))> {
return begin(static_cast<T&&>(rng));
}
template <typename T>
auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
decltype(end(static_cast<T&&>(rng)))> {
return end(static_cast<T&&>(rng));
}
template <typename T, typename Enable = void>
struct has_const_begin_end : std::false_type {};
template <typename T, typename Enable = void>
struct has_mutable_begin_end : std::false_type {};
template <typename T>
struct has_const_begin_end<
T,
void_t<
decltype(detail::range_begin(std::declval<const remove_cvref_t<T>&>())),
decltype(detail::range_end(std::declval<const remove_cvref_t<T>&>()))>>
: std::true_type {};
template <typename T>
struct has_mutable_begin_end<
T, void_t<decltype(detail::range_begin(std::declval<T>())),
decltype(detail::range_end(std::declval<T>())),
// the extra int here is because older versions of MSVC don't
// SFINAE properly unless there are distinct types
int>> : std::true_type {};
template <typename T>
struct is_range_<T, void>
: std::integral_constant<bool, (has_const_begin_end<T>::value ||
has_mutable_begin_end<T>::value)> {};
# undef FMT_DECLTYPE_RETURN
#endif
/// tuple_size and tuple_element check.
// 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,
(void)std::declval<typename std::tuple_element<0, U>::type>(),
int());
static auto check(U* p) -> decltype(std::tuple_size<U>::value, int());
template <typename> static void check(...);
public:
static FMT_CONSTEXPR_DECL const bool value =
static constexpr const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value;
};
// Check for integer_sequence
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 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>;
template <size_t... N> using index_sequence = std::index_sequence<N...>;
template <size_t N> using make_index_sequence = std::make_index_sequence<N>;
#else
template <typename T, T... N> struct integer_sequence {
using value_type = T;
static FMT_CONSTEXPR std::size_t size() { return sizeof...(N); }
static FMT_CONSTEXPR size_t size() { return sizeof...(N); }
};
template <std::size_t... N>
using index_sequence = integer_sequence<std::size_t, N...>;
template <size_t... N> using index_sequence = integer_sequence<size_t, N...>;
template <typename T, std::size_t N, T... Ns>
template <typename T, 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>;
template <size_t N>
using make_index_sequence = make_integer_sequence<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 <typename T>
using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>;
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_ENABLE_IF(!is_like_std_string<
typename std::decay<Arg>::type>::value)>
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
return add_space ? " {}" : "{}";
}
template <typename Arg, FMT_ENABLE_IF(is_like_std_string<
typename std::decay<Arg>::type>::value)>
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
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 T, typename C, bool = is_tuple_like_<T>::value>
class is_tuple_formattable_ {
public:
static constexpr const bool value = false;
};
template <typename TupleT, typename Char>
struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
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++ = ' ';
}
out = internal::copy(formatting.delimiter, out);
}
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;
};
template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
template <std::size_t... Is>
static std::true_type check2(index_sequence<Is...>,
integer_sequence<bool, (Is == Is)...>);
static std::false_type check2(...);
template <std::size_t... Is>
static decltype(check2(
index_sequence<Is...>{},
integer_sequence<
bool, (is_formattable<typename std::tuple_element<Is, T>::type,
C>::value)...>{})) check(index_sequence<Is...>);
public:
formatting_tuple<Char> formatting;
static constexpr const bool value =
decltype(check(tuple_index_sequence<T>{}))::value;
};
template <typename Tuple, typename F, size_t... Is>
FMT_CONSTEXPR void for_each(index_sequence<Is...>, Tuple&& t, F&& f) {
using std::get;
// Using a free function get<Is>(Tuple) now.
const int unused[] = {0, ((void)f(get<Is>(t)), 0)...};
ignore_unused(unused);
}
template <typename Tuple, typename F>
FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) {
for_each(tuple_index_sequence<remove_cvref_t<Tuple>>(),
std::forward<Tuple>(t), std::forward<F>(f));
}
template <typename Tuple1, typename Tuple2, typename F, size_t... Is>
void for_each2(index_sequence<Is...>, Tuple1&& t1, Tuple2&& t2, F&& f) {
using std::get;
const int unused[] = {0, ((void)f(get<Is>(t1), get<Is>(t2)), 0)...};
ignore_unused(unused);
}
template <typename Tuple1, typename Tuple2, typename F>
void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) {
for_each2(tuple_index_sequence<remove_cvref_t<Tuple1>>(),
std::forward<Tuple1>(t1), std::forward<Tuple2>(t2),
std::forward<F>(f));
}
namespace tuple {
// Workaround a bug in MSVC 2019 (v140).
template <typename Char, typename... T>
using result_t = std::tuple<formatter<remove_cvref_t<T>, Char>...>;
using std::get;
template <typename Tuple, typename Char, std::size_t... Is>
auto get_formatters(index_sequence<Is...>)
-> result_t<Char, decltype(get<Is>(std::declval<Tuple>()))...>;
} // namespace tuple
#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920
// Older MSVC doesn't get the reference type correctly for arrays.
template <typename R> struct range_reference_type_impl {
using type = decltype(*detail::range_begin(std::declval<R&>()));
};
template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> {
using type = T&;
};
template <typename T>
using range_reference_type = typename range_reference_type_impl<T>::type;
#else
template <typename Range>
using range_reference_type =
decltype(*detail::range_begin(std::declval<Range&>()));
#endif
// We don't use the Range's value_type for anything, but we do need the Range's
// reference type, with cv-ref stripped.
template <typename Range>
using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
template <typename Formatter>
FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set)
-> decltype(f.set_debug_format(set)) {
f.set_debug_format(set);
}
template <typename Formatter>
FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {}
// These are not generic lambdas for compatibility with C++11.
template <typename ParseContext> struct parse_empty_specs {
template <typename Formatter> FMT_CONSTEXPR void operator()(Formatter& f) {
f.parse(ctx);
detail::maybe_set_debug_format(f, true);
}
ParseContext& ctx;
};
template <typename FormatContext> struct format_tuple_element {
using char_type = typename FormatContext::char_type;
template <typename T>
void operator()(const formatter<T, char_type>& f, const T& v) {
if (i > 0)
ctx.advance_to(detail::copy_str<char_type>(separator, ctx.out()));
ctx.advance_to(f.format(v, ctx));
++i;
}
int i;
FormatContext& ctx;
basic_string_view<char_type> separator;
};
} // namespace detail
template <typename T> struct is_tuple_like {
static constexpr const bool value =
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
};
template <typename T, typename C> struct is_tuple_formattable {
static constexpr const bool value =
detail::is_tuple_formattable_<T, C>::value;
};
template <typename Tuple, typename Char>
struct formatter<Tuple, Char,
enable_if_t<fmt::is_tuple_like<Tuple>::value &&
fmt::is_tuple_formattable<Tuple, Char>::value>> {
private:
decltype(detail::tuple::get_formatters<Tuple, Char>(
detail::tuple_index_sequence<Tuple>())) formatters_;
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
basic_string_view<Char> opening_bracket_ =
detail::string_literal<Char, '('>{};
basic_string_view<Char> closing_bracket_ =
detail::string_literal<Char, ')'>{};
public:
FMT_CONSTEXPR formatter() {}
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
separator_ = sep;
}
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
basic_string_view<Char> close) {
opening_bracket_ = open;
closing_bracket_ = close;
}
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return formatting.parse(ctx);
auto it = ctx.begin();
if (it != ctx.end() && *it != '}')
FMT_THROW(format_error("invalid format specifier"));
detail::for_each(formatters_, detail::parse_empty_specs<ParseContext>{ctx});
return it;
}
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 FormatContext>
auto format(const Tuple& value, FormatContext& ctx) const
-> decltype(ctx.out()) {
ctx.advance_to(detail::copy_str<Char>(opening_bracket_, ctx.out()));
detail::for_each2(
formatters_, value,
detail::format_tuple_element<FormatContext>{0, ctx, separator_});
return detail::copy_str<Char>(closing_bracket_, ctx.out());
}
};
template <typename T, typename Char> struct is_range {
static FMT_CONSTEXPR_DECL const bool value =
internal::is_range_<T>::value &&
!internal::is_like_std_string<T>::value &&
static constexpr const bool value =
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
!std::is_convertible<T, std::basic_string<Char>>::value &&
!std::is_constructible<internal::std_string_view<Char>, T>::value;
!std::is_convertible<T, detail::std_string_view<Char>>::value;
};
template <typename RangeT, typename Char>
struct formatter<RangeT, Char,
enable_if_t<fmt::is_range<RangeT, Char>::value>> {
formatting_range<Char> formatting;
namespace detail {
template <typename Context> struct range_mapper {
using mapper = arg_mapper<Context>;
template <typename T,
FMT_ENABLE_IF(has_formatter<remove_cvref_t<T>, Context>::value)>
static auto map(T&& value) -> T&& {
return static_cast<T&&>(value);
}
template <typename T,
FMT_ENABLE_IF(!has_formatter<remove_cvref_t<T>, Context>::value)>
static auto map(T&& value)
-> decltype(mapper().map(static_cast<T&&>(value))) {
return mapper().map(static_cast<T&&>(value));
}
};
template <typename Char, typename Element>
using range_formatter_type =
formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map(
std::declval<Element>()))>,
Char>;
template <typename R>
using maybe_const_range =
conditional_t<has_const_begin_end<R>::value, const R, R>;
// Workaround a bug in MSVC 2015 and earlier.
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
template <typename R, typename Char>
struct is_formattable_delayed
: is_formattable<uncvref_type<maybe_const_range<R>>, Char> {};
#endif
} // namespace detail
template <typename T, typename Char, typename Enable = void>
struct range_formatter;
template <typename T, typename Char>
struct range_formatter<
T, Char,
enable_if_t<conjunction<std::is_same<T, remove_cvref_t<T>>,
is_formattable<T, Char>>::value>> {
private:
detail::range_formatter_type<Char, T> underlying_;
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
basic_string_view<Char> opening_bracket_ =
detail::string_literal<Char, '['>{};
basic_string_view<Char> closing_bracket_ =
detail::string_literal<Char, ']'>{};
public:
FMT_CONSTEXPR range_formatter() {}
FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type<Char, T>& {
return underlying_;
}
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
separator_ = sep;
}
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
basic_string_view<Char> close) {
opening_bracket_ = open;
closing_bracket_ = close;
}
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return formatting.parse(ctx);
auto it = ctx.begin();
auto end = ctx.end();
if (it != end && *it == 'n') {
set_brackets({}, {});
++it;
}
if (it != end && *it != '}') {
if (*it != ':') FMT_THROW(format_error("invalid format specifier"));
++it;
} else {
detail::maybe_set_debug_format(underlying_, true);
}
ctx.advance_to(it);
return underlying_.parse(ctx);
}
template <typename FormatContext>
typename FormatContext::iterator format(const RangeT& values,
FormatContext& ctx) {
auto out = internal::copy(formatting.prefix, ctx.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++ = ' ';
out = internal::copy(formatting.delimiter, out);
}
out = format_to(out,
internal::format_str_quoted(
(formatting.add_delimiter_spaces && i > 0), *it),
*it);
if (++i > formatting.range_length_limit) {
out = format_to(out, " ... <other elements>");
break;
}
template <typename R, typename FormatContext>
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
detail::range_mapper<buffer_context<Char>> mapper;
auto out = ctx.out();
out = detail::copy_str<Char>(opening_bracket_, out);
int i = 0;
auto it = detail::range_begin(range);
auto end = detail::range_end(range);
for (; it != end; ++it) {
if (i > 0) out = detail::copy_str<Char>(separator_, out);
ctx.advance_to(out);
out = underlying_.format(mapper.map(*it), ctx);
++i;
}
if (formatting.add_prepostfix_space) *out++ = ' ';
return internal::copy(formatting.postfix, out);
out = detail::copy_str<Char>(closing_bracket_, out);
return out;
}
};
template <typename Char, typename... T> struct tuple_arg_join : internal::view {
enum class range_format { disabled, map, set, sequence, string, debug_string };
namespace detail {
template <typename T>
struct range_format_kind_
: std::integral_constant<range_format,
std::is_same<uncvref_type<T>, T>::value
? range_format::disabled
: is_map<T>::value ? range_format::map
: is_set<T>::value ? range_format::set
: range_format::sequence> {};
template <range_format K, typename R, typename Char, typename Enable = void>
struct range_default_formatter;
template <range_format K>
using range_format_constant = std::integral_constant<range_format, K>;
template <range_format K, typename R, typename Char>
struct range_default_formatter<
K, R, Char,
enable_if_t<(K == range_format::sequence || K == range_format::map ||
K == range_format::set)>> {
using range_type = detail::maybe_const_range<R>;
range_formatter<detail::uncvref_type<range_type>, Char> underlying_;
FMT_CONSTEXPR range_default_formatter() { init(range_format_constant<K>()); }
FMT_CONSTEXPR void init(range_format_constant<range_format::set>) {
underlying_.set_brackets(detail::string_literal<Char, '{'>{},
detail::string_literal<Char, '}'>{});
}
FMT_CONSTEXPR void init(range_format_constant<range_format::map>) {
underlying_.set_brackets(detail::string_literal<Char, '{'>{},
detail::string_literal<Char, '}'>{});
underlying_.underlying().set_brackets({}, {});
underlying_.underlying().set_separator(
detail::string_literal<Char, ':', ' '>{});
}
FMT_CONSTEXPR void init(range_format_constant<range_format::sequence>) {}
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return underlying_.parse(ctx);
}
template <typename FormatContext>
auto format(range_type& range, FormatContext& ctx) const
-> decltype(ctx.out()) {
return underlying_.format(range, ctx);
}
};
} // namespace detail
template <typename T, typename Char, typename Enable = void>
struct range_format_kind
: conditional_t<
is_range<T, Char>::value, detail::range_format_kind_<T>,
std::integral_constant<range_format, range_format::disabled>> {};
template <typename R, typename Char>
struct formatter<
R, Char,
enable_if_t<conjunction<bool_constant<range_format_kind<R, Char>::value !=
range_format::disabled>
// Workaround a bug in MSVC 2015 and earlier.
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
,
detail::is_formattable_delayed<R, Char>
#endif
>::value>>
: detail::range_default_formatter<range_format_kind<R, Char>::value, R,
Char> {
};
template <typename Char, typename... T> struct tuple_join_view : detail::view {
const std::tuple<T...>& tuple;
basic_string_view<Char> sep;
tuple_arg_join(const std::tuple<T...>& t, basic_string_view<Char> s)
: tuple{t}, sep{s} {}
tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s)
: tuple(t), sep{s} {}
};
// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
// support in tuple_join. It is disabled by default because of issues with
// the dynamic width and precision.
#ifndef FMT_TUPLE_JOIN_SPECIFIERS
# define FMT_TUPLE_JOIN_SPECIFIERS 0
#endif
template <typename Char, typename... T>
struct formatter<tuple_arg_join<Char, T...>, Char> {
struct formatter<tuple_join_view<Char, T...>, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
return do_parse(ctx, std::integral_constant<size_t, sizeof...(T)>());
}
template <typename FormatContext>
typename FormatContext::iterator format(
const tuple_arg_join<Char, T...>& value, FormatContext& ctx) {
return format(value, ctx, internal::make_index_sequence<sizeof...(T)>{});
auto format(const tuple_join_view<Char, T...>& value,
FormatContext& ctx) const -> typename FormatContext::iterator {
return do_format(value, ctx,
std::integral_constant<size_t, sizeof...(T)>());
}
private:
template <typename FormatContext, size_t... N>
typename FormatContext::iterator format(
const tuple_arg_join<Char, T...>& value, FormatContext& ctx,
internal::index_sequence<N...>) {
return format_args(value, ctx, std::get<N>(value.tuple)...);
std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_;
template <typename ParseContext>
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
std::integral_constant<size_t, 0>)
-> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename ParseContext, size_t N>
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
std::integral_constant<size_t, N>)
-> decltype(ctx.begin()) {
auto end = ctx.begin();
#if FMT_TUPLE_JOIN_SPECIFIERS
end = std::get<sizeof...(T) - N>(formatters_).parse(ctx);
if (N > 1) {
auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
if (end != end1)
FMT_THROW(format_error("incompatible format specs for tuple elements"));
}
#endif
return end;
}
template <typename FormatContext>
typename FormatContext::iterator format_args(
const tuple_arg_join<Char, T...>&, FormatContext& ctx) {
// NOTE: for compilers that support C++17, this empty function instantiation
// can be replaced with a constexpr branch in the variadic overload.
auto do_format(const tuple_join_view<Char, T...>&, FormatContext& ctx,
std::integral_constant<size_t, 0>) const ->
typename FormatContext::iterator {
return ctx.out();
}
template <typename FormatContext, typename Arg, typename... Args>
typename FormatContext::iterator format_args(
const tuple_arg_join<Char, T...>& value, FormatContext& ctx,
const Arg& arg, const Args&... args) {
using base = formatter<typename std::decay<Arg>::type, Char>;
auto out = ctx.out();
out = base{}.format(arg, ctx);
if (sizeof...(Args) > 0) {
template <typename FormatContext, size_t N>
auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
std::integral_constant<size_t, N>) const ->
typename FormatContext::iterator {
auto out = std::get<sizeof...(T) - N>(formatters_)
.format(std::get<sizeof...(T) - N>(value.tuple), ctx);
if (N > 1) {
out = std::copy(value.sep.begin(), value.sep.end(), out);
ctx.advance_to(out);
return format_args(value, ctx, args...);
return do_format(value, ctx, std::integral_constant<size_t, N - 1>());
}
return out;
}
};
namespace detail {
// Check if T has an interface like a container adaptor (e.g. std::stack,
// std::queue, std::priority_queue).
template <typename T> class is_container_adaptor_like {
template <typename U> static auto check(U* p) -> typename U::container_type;
template <typename> static void check(...);
public:
static constexpr const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value;
};
template <typename Container> struct all {
const Container& c;
auto begin() const -> typename Container::const_iterator { return c.begin(); }
auto end() const -> typename Container::const_iterator { return c.end(); }
};
} // namespace detail
template <typename T, typename Char>
struct formatter<
T, Char,
enable_if_t<conjunction<detail::is_container_adaptor_like<T>,
bool_constant<range_format_kind<T, Char>::value ==
range_format::disabled>>::value>>
: formatter<detail::all<typename T::container_type>, Char> {
using all = detail::all<typename T::container_type>;
template <typename FormatContext>
auto format(const T& t, FormatContext& ctx) const -> decltype(ctx.out()) {
struct getter : T {
static auto get(const T& t) -> all {
return {t.*(&getter::c)}; // Access c through the derived class.
}
};
return formatter<all>::format(getter::get(t), ctx);
}
};
FMT_BEGIN_EXPORT
/**
\rst
Returns an object that formats `tuple` with elements separated by `sep`.
@ -349,17 +700,36 @@ struct formatter<tuple_arg_join<Char, T...>, Char> {
\endrst
*/
template <typename... T>
FMT_CONSTEXPR tuple_arg_join<char, T...> join(const std::tuple<T...>& tuple,
string_view sep) {
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep)
-> tuple_join_view<char, T...> {
return {tuple, sep};
}
template <typename... T>
FMT_CONSTEXPR tuple_arg_join<wchar_t, T...> join(const std::tuple<T...>& tuple,
wstring_view sep) {
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple,
basic_string_view<wchar_t> sep)
-> tuple_join_view<wchar_t, T...> {
return {tuple, sep};
}
/**
\rst
Returns an object that formats `initializer_list` with elements separated by
`sep`.
**Example**::
fmt::print("{}", fmt::join({1, 2, 3}, ", "));
// Output: "1, 2, 3"
\endrst
*/
template <typename T>
auto join(std::initializer_list<T> list, string_view sep)
-> join_view<const T*, const T*> {
return join(std::begin(list), std::end(list), sep);
}
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_RANGES_H_

440
include/fmt/std.h Normal file
View File

@ -0,0 +1,440 @@
// Formatting library for C++ - formatters for standard library types
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_STD_H_
#define FMT_STD_H_
#include <bitset>
#include <cstdlib>
#include <exception>
#include <memory>
#include <thread>
#include <type_traits>
#include <typeinfo>
#include <utility>
#include <vector>
#include "format.h"
#include "ostream.h"
#if FMT_HAS_INCLUDE(<version>)
# include <version>
#endif
// Checking FMT_CPLUSPLUS for warning suppression in MSVC.
#if FMT_CPLUSPLUS >= 201703L
# if FMT_HAS_INCLUDE(<filesystem>)
# include <filesystem>
# endif
# if FMT_HAS_INCLUDE(<variant>)
# include <variant>
# endif
# if FMT_HAS_INCLUDE(<optional>)
# include <optional>
# endif
#endif
// GCC 4 does not support FMT_HAS_INCLUDE.
#if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__)
# include <cxxabi.h>
// Android NDK with gabi++ library on some architectures does not implement
// abi::__cxa_demangle().
# ifndef __GABIXX_CXXABI_H__
# define FMT_HAS_ABI_CXA_DEMANGLE
# endif
#endif
// Check if typeid is available.
#ifndef FMT_USE_TYPEID
// __RTTI is for EDG compilers. In MSVC typeid is available without RTTI.
# if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || FMT_MSC_VERSION || \
defined(__INTEL_RTTI__) || defined(__RTTI)
# define FMT_USE_TYPEID 1
# else
# define FMT_USE_TYPEID 0
# endif
#endif
#ifdef __cpp_lib_filesystem
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename Char> auto get_path_string(const std::filesystem::path& p) {
return p.string<Char>();
}
template <typename Char>
void write_escaped_path(basic_memory_buffer<Char>& quoted,
const std::filesystem::path& p) {
write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
}
# ifdef _WIN32
template <>
inline auto get_path_string<char>(const std::filesystem::path& p) {
return to_utf8<wchar_t>(p.native(), to_utf8_error_policy::replace);
}
template <>
inline void write_escaped_path<char>(memory_buffer& quoted,
const std::filesystem::path& p) {
auto buf = basic_memory_buffer<wchar_t>();
write_escaped_string<wchar_t>(std::back_inserter(buf), p.native());
bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()});
FMT_ASSERT(valid, "invalid utf16");
}
# endif // _WIN32
template <>
inline void write_escaped_path<std::filesystem::path::value_type>(
basic_memory_buffer<std::filesystem::path::value_type>& quoted,
const std::filesystem::path& p) {
write_escaped_string<std::filesystem::path::value_type>(
std::back_inserter(quoted), p.native());
}
} // namespace detail
FMT_EXPORT
template <typename Char> struct formatter<std::filesystem::path, Char> {
private:
format_specs<Char> specs_;
detail::arg_ref<Char> width_ref_;
bool debug_ = false;
public:
FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; }
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
auto it = ctx.begin(), end = ctx.end();
if (it == end) return it;
it = detail::parse_align(it, end, specs_);
if (it == end) return it;
it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
if (it != end && *it == '?') {
debug_ = true;
++it;
}
return it;
}
template <typename FormatContext>
auto format(const std::filesystem::path& p, FormatContext& ctx) const {
auto specs = specs_;
detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
ctx);
if (!debug_) {
auto s = detail::get_path_string<Char>(p);
return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
}
auto quoted = basic_memory_buffer<Char>();
detail::write_escaped_path(quoted, p);
return detail::write(ctx.out(),
basic_string_view<Char>(quoted.data(), quoted.size()),
specs);
}
};
FMT_END_NAMESPACE
#endif
FMT_BEGIN_NAMESPACE
FMT_EXPORT
template <typename Char>
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
FMT_END_NAMESPACE
#ifdef __cpp_lib_optional
FMT_BEGIN_NAMESPACE
FMT_EXPORT
template <typename T, typename Char>
struct formatter<std::optional<T>, Char,
std::enable_if_t<is_formattable<T, Char>::value>> {
private:
formatter<T, Char> underlying_;
static constexpr basic_string_view<Char> optional =
detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l',
'('>{};
static constexpr basic_string_view<Char> none =
detail::string_literal<Char, 'n', 'o', 'n', 'e'>{};
template <class U>
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set)
-> decltype(u.set_debug_format(set)) {
u.set_debug_format(set);
}
template <class U>
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
public:
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
maybe_set_debug_format(underlying_, true);
return underlying_.parse(ctx);
}
template <typename FormatContext>
auto format(std::optional<T> const& opt, FormatContext& ctx) const
-> decltype(ctx.out()) {
if (!opt) return detail::write<Char>(ctx.out(), none);
auto out = ctx.out();
out = detail::write<Char>(out, optional);
ctx.advance_to(out);
out = underlying_.format(*opt, ctx);
return detail::write(out, ')');
}
};
FMT_END_NAMESPACE
#endif // __cpp_lib_optional
#ifdef __cpp_lib_variant
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename T>
using variant_index_sequence =
std::make_index_sequence<std::variant_size<T>::value>;
template <typename> struct is_variant_like_ : std::false_type {};
template <typename... Types>
struct is_variant_like_<std::variant<Types...>> : std::true_type {};
// formattable element check.
template <typename T, typename C> class is_variant_formattable_ {
template <std::size_t... Is>
static std::conjunction<
is_formattable<std::variant_alternative_t<Is, T>, C>...>
check(std::index_sequence<Is...>);
public:
static constexpr const bool value =
decltype(check(variant_index_sequence<T>{}))::value;
};
template <typename Char, typename OutputIt, typename T>
auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt {
if constexpr (is_string<T>::value)
return write_escaped_string<Char>(out, detail::to_string_view(v));
else if constexpr (std::is_same_v<T, Char>)
return write_escaped_char(out, v);
else
return write<Char>(out, v);
}
} // namespace detail
template <typename T> struct is_variant_like {
static constexpr const bool value = detail::is_variant_like_<T>::value;
};
template <typename T, typename C> struct is_variant_formattable {
static constexpr const bool value =
detail::is_variant_formattable_<T, C>::value;
};
FMT_EXPORT
template <typename Char> struct formatter<std::monostate, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const std::monostate&, FormatContext& ctx) const
-> decltype(ctx.out()) {
return detail::write<Char>(ctx.out(), "monostate");
}
};
FMT_EXPORT
template <typename Variant, typename Char>
struct formatter<
Variant, Char,
std::enable_if_t<std::conjunction_v<
is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const Variant& value, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = detail::write<Char>(out, "variant(");
FMT_TRY {
std::visit(
[&](const auto& v) {
out = detail::write_variant_alternative<Char>(out, v);
},
value);
}
FMT_CATCH(const std::bad_variant_access&) {
detail::write<Char>(out, "valueless by exception");
}
*out++ = ')';
return out;
}
};
FMT_END_NAMESPACE
#endif // __cpp_lib_variant
FMT_BEGIN_NAMESPACE
FMT_EXPORT
template <typename Char> struct formatter<std::error_code, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = detail::write_bytes(out, ec.category().name(), format_specs<Char>());
out = detail::write<Char>(out, Char(':'));
out = detail::write<Char>(out, ec.value());
return out;
}
};
FMT_EXPORT
template <typename T, typename Char>
struct formatter<
T, Char,
typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
private:
bool with_typename_ = false;
public:
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
-> decltype(ctx.begin()) {
auto it = ctx.begin();
auto end = ctx.end();
if (it == end || *it == '}') return it;
if (*it == 't') {
++it;
with_typename_ = FMT_USE_TYPEID != 0;
}
return it;
}
template <typename OutputIt>
auto format(const std::exception& ex,
basic_format_context<OutputIt, Char>& ctx) const -> OutputIt {
format_specs<Char> spec;
auto out = ctx.out();
if (!with_typename_)
return detail::write_bytes(out, string_view(ex.what()), spec);
#if FMT_USE_TYPEID
const std::type_info& ti = typeid(ex);
# ifdef FMT_HAS_ABI_CXA_DEMANGLE
int status = 0;
std::size_t size = 0;
std::unique_ptr<char, decltype(&std::free)> demangled_name_ptr(
abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free);
string_view demangled_name_view;
if (demangled_name_ptr) {
demangled_name_view = demangled_name_ptr.get();
// Normalization of stdlib inline namespace names.
// libc++ inline namespaces.
// std::__1::* -> std::*
// std::__1::__fs::* -> std::*
// libstdc++ inline namespaces.
// std::__cxx11::* -> std::*
// std::filesystem::__cxx11::* -> std::filesystem::*
if (demangled_name_view.starts_with("std::")) {
char* begin = demangled_name_ptr.get();
char* to = begin + 5; // std::
for (char *from = to, *end = begin + demangled_name_view.size();
from < end;) {
// This is safe, because demangled_name is NUL-terminated.
if (from[0] == '_' && from[1] == '_') {
char* next = from + 1;
while (next < end && *next != ':') next++;
if (next[0] == ':' && next[1] == ':') {
from = next + 2;
continue;
}
}
*to++ = *from++;
}
demangled_name_view = {begin, detail::to_unsigned(to - begin)};
}
} else {
demangled_name_view = string_view(ti.name());
}
out = detail::write_bytes(out, demangled_name_view, spec);
# elif FMT_MSC_VERSION
string_view demangled_name_view(ti.name());
if (demangled_name_view.starts_with("class "))
demangled_name_view.remove_prefix(6);
else if (demangled_name_view.starts_with("struct "))
demangled_name_view.remove_prefix(7);
out = detail::write_bytes(out, demangled_name_view, spec);
# else
out = detail::write_bytes(out, string_view(ti.name()), spec);
# endif
*out++ = ':';
*out++ = ' ';
return detail::write_bytes(out, string_view(ex.what()), spec);
#endif
}
};
namespace detail {
template <typename T, typename Enable = void>
struct has_flip : std::false_type {};
template <typename T>
struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
: std::true_type {};
template <typename T> struct is_bit_reference_like {
static constexpr const bool value =
std::is_convertible<T, bool>::value &&
std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value;
};
#ifdef _LIBCPP_VERSION
// Workaround for libc++ incompatibility with C++ standard.
// According to the Standard, `bitset::operator[] const` returns bool.
template <typename C>
struct is_bit_reference_like<std::__bit_const_reference<C>> {
static constexpr const bool value = true;
};
#endif
} // namespace detail
// We can't use std::vector<bool, Allocator>::reference and
// std::bitset<N>::reference because the compiler can't deduce Allocator and N
// in partial specialization.
FMT_EXPORT
template <typename BitRef, typename Char>
struct formatter<BitRef, Char,
enable_if_t<detail::is_bit_reference_like<BitRef>::value>>
: formatter<bool, Char> {
template <typename FormatContext>
FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const
-> decltype(ctx.out()) {
return formatter<bool, Char>::format(v, ctx);
}
};
FMT_END_NAMESPACE
#endif // FMT_STD_H_

258
include/fmt/xchar.h Normal file
View File

@ -0,0 +1,258 @@
// Formatting library for C++ - optional wchar_t and exotic character support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_XCHAR_H_
#define FMT_XCHAR_H_
#include <cwchar>
#include "format.h"
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
# include <locale>
#endif
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename T>
using is_exotic_char = bool_constant<!std::is_same<T, char>::value>;
inline auto write_loc(std::back_insert_iterator<detail::buffer<wchar_t>> out,
loc_value value, const format_specs<wchar_t>& specs,
locale_ref loc) -> bool {
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
auto& numpunct =
std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>());
auto separator = std::wstring();
auto grouping = numpunct.grouping();
if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep());
return value.visit(loc_writer<wchar_t>{out, specs, separator, grouping, {}});
#endif
return false;
}
} // namespace detail
FMT_BEGIN_EXPORT
using wstring_view = basic_string_view<wchar_t>;
using wformat_parse_context = basic_format_parse_context<wchar_t>;
using wformat_context = buffer_context<wchar_t>;
using wformat_args = basic_format_args<wformat_context>;
using wmemory_buffer = basic_memory_buffer<wchar_t>;
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround broken conversion on older gcc.
template <typename... Args> using wformat_string = wstring_view;
inline auto runtime(wstring_view s) -> wstring_view { return s; }
#else
template <typename... Args>
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> {
return {{s}};
}
#endif
template <> struct is_char<wchar_t> : std::true_type {};
template <> struct is_char<detail::char8_type> : std::true_type {};
template <> struct is_char<char16_t> : std::true_type {};
template <> struct is_char<char32_t> : std::true_type {};
template <typename... T>
constexpr format_arg_store<wformat_context, T...> make_wformat_args(
const T&... args) {
return {args...};
}
inline namespace literals {
#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS
constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) {
return {s};
}
#endif
} // namespace literals
template <typename It, typename Sentinel>
auto join(It begin, Sentinel end, wstring_view sep)
-> join_view<It, Sentinel, wchar_t> {
return {begin, end, sep};
}
template <typename Range>
auto join(Range&& range, wstring_view sep)
-> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>,
wchar_t> {
return join(std::begin(range), std::end(range), sep);
}
template <typename T>
auto join(std::initializer_list<T> list, wstring_view sep)
-> join_view<const T*, const T*, wchar_t> {
return join(std::begin(list), std::end(list), sep);
}
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
auto vformat(basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> std::basic_string<Char> {
auto buf = basic_memory_buffer<Char>();
detail::vformat_to(buf, format_str, args);
return to_string(buf);
}
template <typename... T>
auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring {
return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...));
}
// Pass char_t as a default template parameter instead of using
// std::basic_string<char_t<S>> to reduce the symbol size.
template <typename S, typename... T, typename Char = char_t<S>,
FMT_ENABLE_IF(!std::is_same<Char, char>::value &&
!std::is_same<Char, wchar_t>::value)>
auto format(const S& format_str, T&&... args) -> std::basic_string<Char> {
return vformat(detail::to_string_view(format_str),
fmt::make_format_args<buffer_context<Char>>(args...));
}
template <typename Locale, typename S, typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat(
const Locale& loc, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> std::basic_string<Char> {
return detail::vformat(loc, detail::to_string_view(format_str), args);
}
template <typename Locale, typename S, typename... T, typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto format(const Locale& loc, const S& format_str, T&&... args)
-> std::basic_string<Char> {
return detail::vformat(loc, detail::to_string_view(format_str),
fmt::make_format_args<buffer_context<Char>>(args...));
}
template <typename OutputIt, typename S, typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
auto vformat_to(OutputIt out, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> OutputIt {
auto&& buf = detail::get_buffer<Char>(out);
detail::vformat_to(buf, detail::to_string_view(format_str), args);
return detail::get_iterator(buf, out);
}
template <typename OutputIt, typename S, typename... T,
typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt {
return vformat_to(out, detail::to_string_view(fmt),
fmt::make_format_args<buffer_context<Char>>(args...));
}
template <typename Locale, typename S, typename OutputIt, typename... Args,
typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat_to(
OutputIt out, const Locale& loc, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) -> OutputIt {
auto&& buf = detail::get_buffer<Char>(out);
vformat_to(buf, detail::to_string_view(format_str), args,
detail::locale_ref(loc));
return detail::get_iterator(buf, out);
}
template <
typename OutputIt, typename Locale, typename S, typename... T,
typename Char = char_t<S>,
bool enable = detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_locale<Locale>::value&& detail::is_exotic_char<Char>::value>
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
T&&... args) ->
typename std::enable_if<enable, OutputIt>::type {
return vformat_to(out, loc, detail::to_string_view(format_str),
fmt::make_format_args<buffer_context<Char>>(args...));
}
template <typename OutputIt, typename Char, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat_to_n(
OutputIt out, size_t n, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> format_to_n_result<OutputIt> {
using traits = detail::fixed_buffer_traits;
auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n);
detail::vformat_to(buf, format_str, args);
return {buf.out(), buf.count()};
}
template <typename OutputIt, typename S, typename... T,
typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args)
-> format_to_n_result<OutputIt> {
return vformat_to_n(out, n, detail::to_string_view(fmt),
fmt::make_format_args<buffer_context<Char>>(args...));
}
template <typename S, typename... T, typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
inline auto formatted_size(const S& fmt, T&&... args) -> size_t {
auto buf = detail::counting_buffer<Char>();
detail::vformat_to(buf, detail::to_string_view(fmt),
fmt::make_format_args<buffer_context<Char>>(args...));
return buf.count();
}
inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
auto buf = wmemory_buffer();
detail::vformat_to(buf, fmt, args);
buf.push_back(L'\0');
if (std::fputws(buf.data(), f) == -1)
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
}
inline void vprint(wstring_view fmt, wformat_args args) {
vprint(stdout, fmt, args);
}
template <typename... T>
void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...));
}
template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
return vprint(wstring_view(fmt), fmt::make_wformat_args(args...));
}
template <typename... T>
void println(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
return print(f, L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
}
template <typename... T> void println(wformat_string<T...> fmt, T&&... args) {
return print(L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
}
/**
Converts *value* to ``std::wstring`` using the default format for type *T*.
*/
template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
return format(FMT_STRING(L"{}"), value);
}
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_XCHAR_H_

110
src/fmt.cc Normal file
View File

@ -0,0 +1,110 @@
module;
// Put all implementation-provided headers into the global module fragment
// to prevent attachment to this module.
#include <algorithm>
#include <cerrno>
#include <chrono>
#include <climits>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <exception>
#include <filesystem>
#include <fstream>
#include <functional>
#include <iterator>
#include <limits>
#include <locale>
#include <memory>
#include <optional>
#include <ostream>
#include <stdexcept>
#include <string>
#include <string_view>
#include <system_error>
#include <thread>
#include <type_traits>
#include <typeinfo>
#include <utility>
#include <variant>
#include <vector>
#include <version>
#if __has_include(<cxxabi.h>)
# include <cxxabi.h>
#endif
#if defined(_MSC_VER) || defined(__MINGW32__)
# include <intrin.h>
#endif
#if defined __APPLE__ || defined(__FreeBSD__)
# include <xlocale.h>
#endif
#if __has_include(<winapifamily.h>)
# include <winapifamily.h>
#endif
#if (__has_include(<fcntl.h>) || defined(__APPLE__) || \
defined(__linux__)) && \
(!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
# include <fcntl.h>
# include <sys/stat.h>
# include <sys/types.h>
# ifndef _WIN32
# include <unistd.h>
# else
# include <io.h>
# endif
#endif
#ifdef _WIN32
# if defined(__GLIBCXX__)
# include <ext/stdio_filebuf.h>
# include <ext/stdio_sync_filebuf.h>
# elif defined(_LIBCPP_VERSION)
# include <__std_stream>
# endif
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#endif
export module fmt;
#define FMT_EXPORT export
#define FMT_BEGIN_EXPORT export {
#define FMT_END_EXPORT }
// If you define FMT_ATTACH_TO_GLOBAL_MODULE
// - all declarations are detached from module 'fmt'
// - the module behaves like a traditional static library, too
// - all library symbols are mangled traditionally
// - you can mix TUs with either importing or #including the {fmt} API
#ifdef FMT_ATTACH_TO_GLOBAL_MODULE
extern "C++" {
#endif
// All library-provided declarations and definitions must be in the module
// purview to be exported.
#include "fmt/args.h"
#include "fmt/chrono.h"
#include "fmt/color.h"
#include "fmt/compile.h"
#include "fmt/format.h"
#include "fmt/os.h"
#include "fmt/printf.h"
#include "fmt/std.h"
#include "fmt/xchar.h"
#ifdef FMT_ATTACH_TO_GLOBAL_MODULE
}
#endif
// gcc doesn't yet implement private module fragments
#if !FMT_GCC_VERSION
module : private;
#endif
#include "format.cc"
#include "os.cc"

View File

@ -8,56 +8,36 @@
#include "fmt/format-inl.h"
FMT_BEGIN_NAMESPACE
template struct FMT_API internal::basic_data<void>;
namespace detail {
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
int (*instantiate_format_float)(double, int, internal::float_specs,
internal::buffer<char>&) =
internal::format_float;
template FMT_API auto dragonbox::to_decimal(float x) noexcept
-> dragonbox::decimal_fp<float>;
template FMT_API auto dragonbox::to_decimal(double x) noexcept
-> dragonbox::decimal_fp<double>;
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
template FMT_API internal::locale_ref::locale_ref(const std::locale& loc);
template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
template FMT_API locale_ref::locale_ref(const std::locale& loc);
template FMT_API auto locale_ref::get<std::locale>() const -> std::locale;
#endif
// Explicit instantiations for char.
template FMT_API std::string internal::grouping_impl<char>(locale_ref);
template FMT_API char internal::thousands_sep_impl(locale_ref);
template FMT_API char internal::decimal_point_impl(locale_ref);
template FMT_API auto thousands_sep_impl(locale_ref)
-> thousands_sep_result<char>;
template FMT_API auto decimal_point_impl(locale_ref) -> char;
template FMT_API void internal::buffer<char>::append(const char*, const char*);
template FMT_API void buffer<char>::append(const char*, const char*);
template FMT_API void internal::arg_map<format_context>::init(
const basic_format_args<format_context>& args);
template FMT_API std::string internal::vformat<char>(
string_view, basic_format_args<format_context>);
template FMT_API format_context::iterator internal::vformat_to(
internal::buffer<char>&, string_view, basic_format_args<format_context>);
template FMT_API int internal::snprintf_float(double, int,
internal::float_specs,
internal::buffer<char>&);
template FMT_API int internal::snprintf_float(long double, int,
internal::float_specs,
internal::buffer<char>&);
template FMT_API int internal::format_float(double, int, internal::float_specs,
internal::buffer<char>&);
template FMT_API int internal::format_float(long double, int,
internal::float_specs,
internal::buffer<char>&);
template FMT_API void vformat_to(buffer<char>&, string_view,
typename vformat_args<>::type, locale_ref);
// Explicit instantiations for wchar_t.
template FMT_API std::string internal::grouping_impl<wchar_t>(locale_ref);
template FMT_API wchar_t internal::thousands_sep_impl(locale_ref);
template FMT_API wchar_t internal::decimal_point_impl(locale_ref);
template FMT_API auto thousands_sep_impl(locale_ref)
-> thousands_sep_result<wchar_t>;
template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
template FMT_API void internal::buffer<wchar_t>::append(const wchar_t*,
const wchar_t*);
template FMT_API void buffer<wchar_t>::append(const wchar_t*, const wchar_t*);
template FMT_API std::wstring internal::vformat<wchar_t>(
wstring_view, basic_format_args<wformat_context>);
} // namespace detail
FMT_END_NAMESPACE

398
src/os.cc Normal file
View File

@ -0,0 +1,398 @@
// Formatting library for C++ - optional OS-specific functionality
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
// Disable bogus MSVC warnings.
#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "fmt/os.h"
#include <climits>
#if FMT_USE_FCNTL
# include <sys/stat.h>
# include <sys/types.h>
# ifdef _WRS_KERNEL // VxWorks7 kernel
# include <ioLib.h> // getpagesize
# endif
# ifndef _WIN32
# include <unistd.h>
# else
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <io.h>
# ifndef S_IRUSR
# define S_IRUSR _S_IREAD
# endif
# ifndef S_IWUSR
# define S_IWUSR _S_IWRITE
# endif
# ifndef S_IRGRP
# define S_IRGRP 0
# endif
# ifndef S_IWGRP
# define S_IWGRP 0
# endif
# ifndef S_IROTH
# define S_IROTH 0
# endif
# ifndef S_IWOTH
# define S_IWOTH 0
# endif
# endif // _WIN32
#endif // FMT_USE_FCNTL
#ifdef _WIN32
# include <windows.h>
#endif
namespace {
#ifdef _WIN32
// Return type of read and write functions.
using rwresult = int;
// On Windows the count argument to read and write is unsigned, so convert
// it from size_t preventing integer overflow.
inline unsigned convert_rwcount(std::size_t count) {
return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
}
#elif FMT_USE_FCNTL
// Return type of read and write functions.
using rwresult = ssize_t;
inline std::size_t convert_rwcount(std::size_t count) { return count; }
#endif
} // namespace
FMT_BEGIN_NAMESPACE
#ifdef _WIN32
namespace detail {
class system_message {
system_message(const system_message&) = delete;
void operator=(const system_message&) = delete;
unsigned long result_;
wchar_t* message_;
static bool is_whitespace(wchar_t c) noexcept {
return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0';
}
public:
explicit system_message(unsigned long error_code)
: result_(0), message_(nullptr) {
result_ = FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<wchar_t*>(&message_), 0, nullptr);
if (result_ != 0) {
while (result_ != 0 && is_whitespace(message_[result_ - 1])) {
--result_;
}
}
}
~system_message() { LocalFree(message_); }
explicit operator bool() const noexcept { return result_ != 0; }
operator basic_string_view<wchar_t>() const noexcept {
return basic_string_view<wchar_t>(message_, result_);
}
};
class utf8_system_category final : public std::error_category {
public:
const char* name() const noexcept override { return "system"; }
std::string message(int error_code) const override {
auto&& msg = system_message(error_code);
if (msg) {
auto utf8_message = to_utf8<wchar_t>();
if (utf8_message.convert(msg)) {
return utf8_message.str();
}
}
return "unknown error";
}
};
} // namespace detail
FMT_API const std::error_category& system_category() noexcept {
static const detail::utf8_system_category category;
return category;
}
std::system_error vwindows_error(int err_code, string_view format_str,
format_args args) {
auto ec = std::error_code(err_code, system_category());
return std::system_error(ec, vformat(format_str, args));
}
void detail::format_windows_error(detail::buffer<char>& out, int error_code,
const char* message) noexcept {
FMT_TRY {
auto&& msg = system_message(error_code);
if (msg) {
auto utf8_message = to_utf8<wchar_t>();
if (utf8_message.convert(msg)) {
fmt::format_to(appender(out), FMT_STRING("{}: {}"), message,
string_view(utf8_message));
return;
}
}
}
FMT_CATCH(...) {}
format_error_code(out, error_code, message);
}
void report_windows_error(int error_code, const char* message) noexcept {
report_error(detail::format_windows_error, error_code, message);
}
#endif // _WIN32
buffered_file::~buffered_file() noexcept {
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
report_system_error(errno, "cannot close file");
}
buffered_file::buffered_file(cstring_view filename, cstring_view mode) {
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())),
nullptr);
if (!file_)
FMT_THROW(system_error(errno, FMT_STRING("cannot open file {}"),
filename.c_str()));
}
void buffered_file::close() {
if (!file_) return;
int result = FMT_SYSTEM(fclose(file_));
file_ = nullptr;
if (result != 0)
FMT_THROW(system_error(errno, FMT_STRING("cannot close file")));
}
int buffered_file::descriptor() const {
#ifdef fileno // fileno is a macro on OpenBSD so we cannot use FMT_POSIX_CALL.
int fd = fileno(file_);
#else
int fd = FMT_POSIX_CALL(fileno(file_));
#endif
if (fd == -1)
FMT_THROW(system_error(errno, FMT_STRING("cannot get file descriptor")));
return fd;
}
#if FMT_USE_FCNTL
# ifdef _WIN32
using mode_t = int;
# endif
constexpr mode_t default_open_mode =
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
file::file(cstring_view path, int oflag) {
# if defined(_WIN32) && !defined(__MINGW32__)
fd_ = -1;
auto converted = detail::utf8_to_utf16(string_view(path.c_str()));
*this = file::open_windows_file(converted.c_str(), oflag);
# else
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, default_open_mode)));
if (fd_ == -1)
FMT_THROW(
system_error(errno, FMT_STRING("cannot open file {}"), path.c_str()));
# endif
}
file::~file() 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)
report_system_error(errno, "cannot close file");
}
void file::close() {
if (fd_ == -1) return;
// Don't retry close in case of EINTR!
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
int result = FMT_POSIX_CALL(close(fd_));
fd_ = -1;
if (result != 0)
FMT_THROW(system_error(errno, FMT_STRING("cannot close file")));
}
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.
// Both functions support large file sizes.
DWORD size_upper = 0;
HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_));
DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper));
if (size_lower == INVALID_FILE_SIZE) {
DWORD error = GetLastError();
if (error != NO_ERROR)
FMT_THROW(windows_error(GetLastError(), "cannot get file size"));
}
unsigned long long long_size = size_upper;
return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
# else
using Stat = struct stat;
Stat file_stat = Stat();
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
FMT_THROW(system_error(errno, FMT_STRING("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 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(system_error(errno, FMT_STRING("cannot read from file")));
return detail::to_unsigned(result);
}
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(system_error(errno, FMT_STRING("cannot write to file")));
return detail::to_unsigned(result);
}
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(system_error(
errno, FMT_STRING("cannot duplicate file descriptor {}"), fd));
return file(new_fd);
}
void file::dup2(int fd) {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) {
FMT_THROW(system_error(
errno, FMT_STRING("cannot duplicate file descriptor {} to {}"), fd_,
fd));
}
}
void file::dup2(int fd, std::error_code& ec) noexcept {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) ec = std::error_code(errno, std::generic_category());
}
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();
write_end.close();
int fds[2] = {};
# ifdef _WIN32
// Make the default pipe capacity same as on Linux 2.6.11+.
enum { DEFAULT_CAPACITY = 65536 };
int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
# else
// Don't retry as the pipe function doesn't return EINTR.
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
int result = FMT_POSIX_CALL(pipe(fds));
# endif
if (result != 0)
FMT_THROW(system_error(errno, FMT_STRING("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]);
}
buffered_file file::fdopen(const char* mode) {
// Don't retry as fdopen doesn't return EINTR.
# if defined(__MINGW32__) && defined(_POSIX_)
FILE* f = ::fdopen(fd_, mode);
# else
FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
# endif
if (!f) {
FMT_THROW(system_error(
errno, FMT_STRING("cannot associate stream with file descriptor")));
}
buffered_file bf(f);
fd_ = -1;
return bf;
}
# if defined(_WIN32) && !defined(__MINGW32__)
file file::open_windows_file(wcstring_view path, int oflag) {
int fd = -1;
auto err = _wsopen_s(&fd, path.c_str(), oflag, _SH_DENYNO, default_open_mode);
if (fd == -1) {
FMT_THROW(system_error(err, FMT_STRING("cannot open file {}"),
detail::to_utf8<wchar_t>(path.c_str()).c_str()));
}
return file(fd);
}
# endif
# if !defined(__MSDOS__)
long getpagesize() {
# ifdef _WIN32
SYSTEM_INFO si;
GetSystemInfo(&si);
return si.dwPageSize;
# else
# ifdef _WRS_KERNEL
long size = FMT_POSIX_CALL(getpagesize());
# else
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
# endif
if (size < 0)
FMT_THROW(system_error(errno, FMT_STRING("cannot get memory page size")));
return size;
# endif
}
# endif
namespace detail {
void file_buffer::grow(size_t) {
if (this->size() == this->capacity()) flush();
}
file_buffer::file_buffer(cstring_view path,
const detail::ostream_params& params)
: file_(path, params.oflag) {
set(new char[params.buffer_size], params.buffer_size);
}
file_buffer::file_buffer(file_buffer&& other)
: detail::buffer<char>(other.data(), other.size(), other.capacity()),
file_(std::move(other.file_)) {
other.clear();
other.set(nullptr, 0);
}
file_buffer::~file_buffer() {
flush();
delete[] data();
}
} // namespace detail
ostream::~ostream() = default;
#endif // FMT_USE_FCNTL
FMT_END_NAMESPACE

View File

@ -1,237 +0,0 @@
// 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.
#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "fmt/posix.h"
#include <climits>
#if FMT_USE_FCNTL
#include <sys/stat.h>
#include <sys/types.h>
#ifndef _WIN32
# include <unistd.h>
#else
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <io.h>
# include <windows.h>
# define O_CREAT _O_CREAT
# define O_TRUNC _O_TRUNC
# ifndef S_IRUSR
# define S_IRUSR _S_IREAD
# endif
# ifndef S_IWUSR
# define S_IWUSR _S_IWRITE
# endif
# ifdef __MINGW32__
# define _SH_DENYNO 0x40
# endif
#endif // _WIN32
#endif // FMT_USE_FCNTL
#ifdef fileno
# undef fileno
#endif
namespace {
#ifdef _WIN32
// Return type of read and write functions.
using RWResult = int;
// On Windows the count argument to read and write is unsigned, so convert
// it from size_t preventing integer overflow.
inline unsigned convert_rwcount(std::size_t count) {
return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
}
#else
// Return type of read and write functions.
using RWResult = ssize_t;
inline std::size_t convert_rwcount(std::size_t count) { return count; }
#endif
} // namespace
FMT_BEGIN_NAMESPACE
buffered_file::~buffered_file() FMT_NOEXCEPT {
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
report_system_error(errno, "cannot close file");
}
buffered_file::buffered_file(cstring_view filename, cstring_view mode) {
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())),
nullptr);
if (!file_)
FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str()));
}
void buffered_file::close() {
if (!file_) return;
int result = FMT_SYSTEM(fclose(file_));
file_ = nullptr;
if (result != 0) 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 buffered_file::fileno() const {
int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor"));
return fd;
}
#if FMT_USE_FCNTL
file::file(cstring_view path, int oflag) {
int mode = S_IRUSR | S_IWUSR;
#if defined(_WIN32) && !defined(__MINGW32__)
fd_ = -1;
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
#else
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
#endif
if (fd_ == -1)
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
}
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)
report_system_error(errno, "cannot close file");
}
void file::close() {
if (fd_ == -1) return;
// Don't retry close in case of EINTR!
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
int result = FMT_POSIX_CALL(close(fd_));
fd_ = -1;
if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
}
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.
// Both functions support large file sizes.
DWORD size_upper = 0;
HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_));
DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper));
if (size_lower == INVALID_FILE_SIZE) {
DWORD error = GetLastError();
if (error != NO_ERROR)
FMT_THROW(windows_error(GetLastError(), "cannot get file size"));
}
unsigned long long long_size = size_upper;
return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
#else
using Stat = struct stat;
Stat file_stat = Stat();
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
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 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(system_error(errno, "cannot read from file"));
return internal::to_unsigned(result);
}
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(system_error(errno, "cannot write to file"));
return internal::to_unsigned(result);
}
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(system_error(errno, "cannot duplicate file descriptor {}", fd));
return file(new_fd);
}
void file::dup2(int fd) {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) {
FMT_THROW(system_error(errno, "cannot duplicate file descriptor {} to {}",
fd_, fd));
}
}
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 = error_code(errno);
}
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();
write_end.close();
int fds[2] = {};
#ifdef _WIN32
// Make the default pipe capacity same as on Linux 2.6.11+.
enum { DEFAULT_CAPACITY = 65536 };
int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
#else
// Don't retry as the pipe function doesn't return EINTR.
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
int result = FMT_POSIX_CALL(pipe(fds));
#endif
if (result != 0) 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]);
}
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(
system_error(errno, "cannot associate stream with file descriptor"));
buffered_file bf(f);
fd_ = -1;
return bf;
}
long getpagesize() {
#ifdef _WIN32
SYSTEM_INFO si;
GetSystemInfo(&si);
return si.dwPageSize;
#else
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
if (size < 0) FMT_THROW(system_error(errno, "cannot get memory page size"));
return size;
#endif
}
#endif // FMT_USE_FCNTL
FMT_END_NAMESPACE

View File

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

7
support/Vagrantfile vendored
View File

@ -4,6 +4,7 @@
# A vagrant config for testing against gcc-4.8.
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/xenial64"
config.disksize.size = '15GB'
config.vm.provider "virtualbox" do |vb|
vb.memory = "4096"
@ -12,8 +13,8 @@ Vagrant.configure("2") do |config|
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y g++ make wget git
wget -q https://github.com/Kitware/CMake/releases/download/v3.14.4/cmake-3.14.4-Linux-x86_64.tar.gz
tar xzf cmake-3.14.4-Linux-x86_64.tar.gz
ln -s `pwd`/cmake-3.14.4-Linux-x86_64/bin/cmake /usr/local/bin
wget -q https://github.com/Kitware/CMake/releases/download/v3.26.0/cmake-3.26.0-Linux-x86_64.tar.gz
tar xzf cmake-3.26.0-Linux-x86_64.tar.gz
ln -s `pwd`/cmake-3.26.0-Linux-x86_64/bin/cmake /usr/local/bin
SHELL
end

View File

@ -1,43 +0,0 @@
#!/usr/bin/env python
# Build the project on AppVeyor.
import os
from subprocess import check_call
build = os.environ['BUILD']
config = os.environ['CONFIGURATION']
platform = os.environ['PLATFORM']
path = os.environ['PATH']
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']
test_command = ['mingw32-make', 'test']
# Remove the path to Git bin directory from $PATH because it breaks
# MinGW config.
path = path.replace(r'C:\Program Files (x86)\Git\bin', '')
os.environ['PATH'] = r'C:\MinGW\bin;' + path
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\15.0\Bin;' + path
if image == 'Visual Studio 2019':
generator = 'Visual Studio 16 2019'
if platform == 'x64':
cmake_command.extend(['-A', 'x64'])
else:
if 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)
build_command = ['cmake', '--build', '.', '--config', config, '--', '/m:4']
test_command = ['ctest', '-C', config]
check_call(cmake_command)
check_call(build_command)
check_call(test_command)

View File

@ -1,41 +0,0 @@
configuration:
- Debug
- Release
clone_depth: 1
image:
- Visual Studio 2015
- Visual Studio 2019
- Visual Studio 2017
platform:
- Win32
- x64
environment:
CTEST_OUTPUT_ON_FAILURE: 1
MSVC_DEFAULT_OPTIONS: ON
BUILD: msvc
matrix:
exclude:
- image: Visual Studio 2015
platform: Win32
- image: Visual Studio 2019
platform: Win32
before_build:
- mkdir build
- cd build
build_script:
- python ../support/appveyor-build.py
on_failure:
- appveyor PushArtifact Testing/Temporary/LastTest.log
- appveyor AddTest test
# Uncomment this to debug AppVeyor failures.
#on_finish:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))

View File

@ -0,0 +1 @@
6.1.2

28
support/bazel/BUILD.bazel Normal file
View File

@ -0,0 +1,28 @@
cc_library(
name = "fmt",
srcs = [
#"src/fmt.cc", # No C++ module support
"src/format.cc",
"src/os.cc",
],
hdrs = [
"include/fmt/args.h",
"include/fmt/chrono.h",
"include/fmt/color.h",
"include/fmt/compile.h",
"include/fmt/core.h",
"include/fmt/format.h",
"include/fmt/format-inl.h",
"include/fmt/os.h",
"include/fmt/ostream.h",
"include/fmt/printf.h",
"include/fmt/ranges.h",
"include/fmt/std.h",
"include/fmt/xchar.h",
],
includes = [
"include",
],
strip_include_prefix = "include",
visibility = ["//visibility:public"],
)

74
support/bazel/README.md Normal file
View File

@ -0,0 +1,74 @@
# Bazel support
To get [Bazel](https://bazel.build/) working with {fmt} you can copy the files `BUILD.bazel`, `WORKSPACE.bazel`, and `.bazelversion` from this folder (`support/bazel`) to the root folder of this project. This way {fmt} gets bazelized and can be used with Bazel (e.g. doing a `bazel build //...` on {fmt}).
## Using {fmt} as a dependency
The following minimal example shows how to use {fmt} as a dependency within a Bazel project.
The following file structure is assumed:
```
example
├── BUILD.bazel
├── main.cpp
└── WORKSPACE.bazel
```
*main.cpp*:
```c++
#include "fmt/core.h"
int main() {
fmt::print("The answer is {}\n", 42);
}
```
The expected output of this example is `The answer is 42`.
*WORKSPACE.bazel*:
```python
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "fmt",
branch = "master",
remote = "https://github.com/fmtlib/fmt",
patch_cmds = [
"mv support/bazel/.bazelversion .bazelversion",
"mv support/bazel/BUILD.bazel BUILD.bazel",
"mv support/bazel/WORKSPACE.bazel WORKSPACE.bazel",
],
# Windows-related patch commands are only needed in the case MSYS2 is not installed.
# More details about the installation process of MSYS2 on Windows systems can be found here:
# https://docs.bazel.build/versions/main/install-windows.html#installing-compilers-and-language-runtimes
# Even if MSYS2 is installed the Windows related patch commands can still be used.
patch_cmds_win = [
"Move-Item -Path support/bazel/.bazelversion -Destination .bazelversion",
"Move-Item -Path support/bazel/BUILD.bazel -Destination BUILD.bazel",
"Move-Item -Path support/bazel/WORKSPACE.bazel -Destination WORKSPACE.bazel",
],
)
```
In the *WORKSPACE* file, the {fmt} GitHub repository is fetched. Using the attribute `patch_cmds` the files `BUILD.bazel`, `WORKSPACE.bazel`, and `.bazelversion` are moved to the root of the {fmt} repository. This way the {fmt} repository is recognized as a bazelized workspace.
*BUILD.bazel*:
```python
cc_binary(
name = "Demo",
srcs = ["main.cpp"],
deps = ["@fmt"],
)
```
The *BUILD* file defines a binary named `Demo` that has a dependency to {fmt}.
To execute the binary you can run `bazel run //:Demo`.
# Using Bzlmod
The [Bazel Central Registry](https://github.com/bazelbuild/bazel-central-registry/tree/main/modules/fmt) also provides support for {fmt}.

View File

@ -0,0 +1 @@
workspace(name = "fmt")

58
support/build-docs.py Executable file
View File

@ -0,0 +1,58 @@
#!/usr/bin/env python
# Build the documentation in CI.
from __future__ import print_function
import errno, os, shutil, subprocess, sys, urllib
from subprocess import call, check_call, Popen, PIPE, STDOUT
def rmtree_if_exists(dir):
try:
shutil.rmtree(dir)
except OSError as e:
if e.errno == errno.ENOENT:
pass
# Build the docs.
fmt_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
sys.path.insert(0, os.path.join(fmt_dir, 'doc'))
import build
build.create_build_env()
html_dir = build.build_docs()
repo = 'fmtlib.github.io'
branch = os.environ['GITHUB_REF']
is_ci = 'CI' in os.environ
if is_ci and branch != 'refs/heads/master':
print('Branch: ' + branch)
exit(0) # Ignore non-master branches
if is_ci and 'KEY' not in os.environ:
# Don't update the repo if building in CI from an account that doesn't have
# push access.
print('Skipping update of ' + repo)
exit(0)
# Clone the fmtlib.github.io repo.
rmtree_if_exists(repo)
git_url = 'https://github.com/' if is_ci else 'git@github.com:'
check_call(['git', 'clone', git_url + 'fmtlib/{}.git'.format(repo)])
# Copy docs to the repo.
target_dir = os.path.join(repo, 'dev')
rmtree_if_exists(target_dir)
shutil.copytree(html_dir, target_dir, ignore=shutil.ignore_patterns('.*'))
if is_ci:
check_call(['git', 'config', '--global', 'user.name', 'fmtbot'])
check_call(['git', 'config', '--global', 'user.email', 'viz@fmt.dev'])
# Push docs to GitHub pages.
check_call(['git', 'add', '--all'], cwd=repo)
if call(['git', 'diff-index', '--quiet', 'HEAD'], cwd=repo):
check_call(['git', 'commit', '-m', 'Update documentation'], cwd=repo)
cmd = 'git push'
if is_ci:
cmd += ' https://$KEY@github.com/fmtlib/fmtlib.github.io.git master'
p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd=repo)
# Print the output without the key.
print(p.communicate()[0].decode('utf-8').replace(os.environ['KEY'], '$KEY'))
if p.returncode != 0:
raise subprocess.CalledProcessError(p.returncode, cmd)

View File

@ -1,3 +1,4 @@
import java.nio.file.Paths
// General gradle arguments for root project
buildscript {
@ -7,24 +8,25 @@ buildscript {
}
dependencies {
//
// https://developer.android.com/studio/releases/gradle-plugin
// https://developer.android.com/studio/releases/gradle-plugin#updating-gradle
//
// Notice that 3.3.0 here is the version of [Android Gradle Plugin]
// Accroding to URL above you will need Gradle 5.0 or higher
// Notice that 4.0.0 here is the version of [Android Gradle Plugin]
// According to URL above you will need Gradle 6.1 or higher
//
// If you are using Android Studio, and it is using Gradle's lower
// version, Use the plugin version 3.1.3 ~ 3.2.0 for Gradle 4.4 ~ 4.10
classpath 'com.android.tools.build:gradle:3.3.0'
classpath "com.android.tools.build:gradle:4.1.1"
}
}
repositories {
google()
jcenter()
}
// Output: Shared library (.so) for Android
apply plugin: 'com.android.library'
// Project's root where CMakeLists.txt exists: rootDir/support/.cxx -> rootDir
def rootDir = Paths.get(project.buildDir.getParent()).getParent()
println("rootDir: ${rootDir}")
// Output: Shared library (.so) for Android
apply plugin: "com.android.library"
android {
compileSdkVersion 25 // Android 7.0
@ -41,13 +43,13 @@ android {
include "arm64-v8a", "armeabi-v7a", "x86_64"
}
}
ndkVersion "21.3.6528147" // ANDROID_NDK_HOME is deprecated. Be explicit
defaultConfig {
minSdkVersion 21 // Android 5.0+
targetSdkVersion 25 // Follow Compile SDK
versionCode 21 // Follow release count
versionName "5.3.0" // Follow Official version
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
versionCode 34 // Follow release count
versionName "7.1.2" // Follow Official version
externalNativeBuild {
cmake {
@ -56,9 +58,9 @@ android {
arguments "-DFMT_TEST=false" // Skip test
arguments "-DFMT_DOC=false" // Skip document
cppFlags "-std=c++17"
targets "fmt"
}
}
println("Gradle CMake Plugin: ")
println(externalNativeBuild.cmake.cppFlags)
println(externalNativeBuild.cmake.arguments)
}
@ -69,16 +71,27 @@ android {
// neighbor of the top level cmake
externalNativeBuild {
cmake {
path "../CMakeLists.txt"
version "3.10.0+"
path "${rootDir}/CMakeLists.txt"
// buildStagingDirectory "./build" // Custom path for cmake output
}
//println(cmake.path)
}
sourceSets{
// Android Manifest for Gradle
main {
manifest.srcFile 'AndroidManifest.xml'
manifest.srcFile "AndroidManifest.xml"
}
}
// https://developer.android.com/studio/build/native-dependencies#build_system_configuration
buildFeatures {
prefab true
prefabPublishing true
}
prefab {
fmt {
headers "${rootDir}/include"
}
}
}
@ -88,20 +101,32 @@ 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'
from "build/intermediates/cmake"
into "${rootDir}/libs"
}
// Copy debug binaries
copy {
from '../libs/debug/obj'
into '../libs/debug'
from "${rootDir}/libs/debug/obj"
into "${rootDir}/libs/debug"
}
// Copy Release binaries
copy {
from '../libs/release/obj'
into '../libs/release'
from "${rootDir}/libs/release/obj"
into "${rootDir}/libs/release"
}
// Remove empty directory
delete '../libs/debug/obj'
delete '../libs/release/obj'
delete "${rootDir}/libs/debug/obj"
delete "${rootDir}/libs/release/obj"
// Copy AAR files. Notice that the aar is named after the folder of this script.
copy {
from "build/outputs/aar/support-release.aar"
into "${rootDir}/libs"
rename "support-release.aar", "fmt-release.aar"
}
copy {
from "build/outputs/aar/support-debug.aar"
into "${rootDir}/libs"
rename "support-debug.aar", "fmt-debug.aar"
}
}

View File

@ -0,0 +1,26 @@
# This module provides function for joining paths
# known from from most languages
#
# Original license:
# SPDX-License-Identifier: (MIT OR CC0-1.0)
# Explicit permission given to distribute this module under
# the terms of the project as described in /LICENSE.rst.
# Copyright 2020 Jan Tojnar
# https://github.com/jtojnar/cmake-snips
#
# Modelled after Pythons os.path.join
# https://docs.python.org/3.7/library/os.path.html#os.path.join
# Windows not supported
function(join_paths joined_path first_path_segment)
set(temp_path "${first_path_segment}")
foreach(current_segment IN LISTS ARGN)
if(NOT ("${current_segment}" STREQUAL ""))
if(IS_ABSOLUTE "${current_segment}")
set(temp_path "${current_segment}")
else()
set(temp_path "${temp_path}/${current_segment}")
endif()
endif()
endforeach()
set(${joined_path} "${temp_path}" PARENT_SCOPE)
endfunction()

View File

@ -1,81 +0,0 @@
# 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
# Can be removed once gcc 4.4 support is dropped.
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 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 ()
# Check if <variant> is available
set(CMAKE_REQUIRED_FLAGS -std=c++1z)
check_cxx_source_compiles("
#include <variant>
int main() {}"
FMT_HAS_VARIANT)
if (NOT FMT_HAS_VARIANT)
set (FMT_HAS_VARIANT OFF)
endif ()
set(CMAKE_REQUIRED_FLAGS )

View File

@ -1,4 +1,7 @@
@PACKAGE_INIT@
include(${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake)
if (NOT TARGET fmt::fmt)
include(${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake)
endif ()
check_required_components(fmt)

View File

@ -1,11 +1,11 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@
libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
libdir=@libdir_for_pc_file@
includedir=@includedir_for_pc_file@
Name: fmt
Description: A modern formatting library
Version: @FMT_VERSION@
Libs: -L${libdir} -lfmt
Libs: -L${libdir} -l@FMT_LIB_NAME@
Cflags: -I${includedir}

View File

@ -1,27 +0,0 @@
# 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

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
"""Manage site and releases.
@ -137,20 +137,58 @@ def update_site(env):
if not os.path.exists(contents):
os.rename(os.path.join(target_doc_dir, 'index.rst'), contents)
# Fix issues in reference.rst/api.rst.
for filename in ['reference.rst', 'api.rst']:
for filename in ['reference.rst', 'api.rst', 'index.rst']:
pattern = re.compile('doxygenfunction.. (bin|oct|hexu|hex)$', re.M)
with rewrite(os.path.join(target_doc_dir, filename)) as b:
b.data = b.data.replace('std::ostream &', 'std::ostream&')
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"" _')
b.data = b.data.replace(', size_t', ', std::size_t')
#b.data = b.data.replace('operator""_', 'operator"" _')
b.data = b.data.replace(
'format_to_n(OutputIt, size_t, string_view, Args&&',
'format_to_n(OutputIt, size_t, const S&, const Args&')
b.data = b.data.replace(
'format_to_n(OutputIt, std::size_t, string_view, Args&&',
'format_to_n(OutputIt, std::size_t, const S&, const Args&')
if version == ('3.0.2'):
b.data = b.data.replace(
'fprintf(std::ostream&', 'fprintf(std::ostream &')
if version == ('5.3.0'):
b.data = b.data.replace(
'format_to(OutputIt, const S&, const Args&...)',
'format_to(OutputIt, const S &, const Args &...)')
if version.startswith('5.') or version.startswith('6.'):
b.data = b.data.replace(', size_t', ', std::size_t')
if version.startswith('7.'):
b.data = b.data.replace(', std::size_t', ', size_t')
b.data = b.data.replace('join(It, It', 'join(It, Sentinel')
if version.startswith('7.1.'):
b.data = b.data.replace(', std::size_t', ', size_t')
b.data = b.data.replace('join(It, It', 'join(It, Sentinel')
b.data = b.data.replace(
'fmt::format_to(OutputIt, const S&, Args&&...)',
'fmt::format_to(OutputIt, const S&, Args&&...) -> ' +
'typename std::enable_if<enable, OutputIt>::type')
b.data = b.data.replace('aa long', 'a long')
b.data = b.data.replace('serveral', 'several')
if version.startswith('6.2.'):
b.data = b.data.replace(
'vformat(const S&, basic_format_args<' +
'buffer_context<Char>>)',
'vformat(const S&, basic_format_args<' +
'buffer_context<type_identity_t<Char>>>)')
# Fix a broken link in index.rst.
index = os.path.join(target_doc_dir, 'index.rst')
with rewrite(index) as b:
b.data = b.data.replace(
'doc/latest/index.html#format-string-syntax', 'syntax.html')
# Fix issues in syntax.rst.
index = os.path.join(target_doc_dir, 'syntax.rst')
with rewrite(index) as b:
b.data = b.data.replace(
'..productionlist:: sf\n', '.. productionlist:: sf\n ')
b.data = b.data.replace('Examples:\n', 'Examples::\n')
# Build the docs.
html_dir = os.path.join(env.build_dir, 'html')
if os.path.exists(html_dir):
@ -208,7 +246,7 @@ def release(args):
# Update the version in the changelog.
title_len = 0
for line in fileinput.input(changelog_path, inplace=True):
if line.decode('utf-8').startswith(version + ' - TBD'):
if line.startswith(version + ' - TBD'):
line = version + ' - ' + datetime.date.today().isoformat()
title_len = len(line)
line += '\n'
@ -238,9 +276,9 @@ def release(args):
# Create a release on GitHub.
fmt_repo.push('origin', 'release')
params = {'access_token': os.getenv('FMT_TOKEN')}
auth_headers = {'Authorization': 'token ' + os.getenv('FMT_TOKEN')}
r = requests.post('https://api.github.com/repos/fmtlib/fmt/releases',
params=params,
headers=auth_headers,
data=json.dumps({'tag_name': version,
'target_commitish': 'release',
'body': changes, 'draft': True}))
@ -251,8 +289,8 @@ def release(args):
package = 'fmt-{}.zip'.format(version)
r = requests.post(
'{}/{}/assets?name={}'.format(uploads_url, id, package),
headers={'Content-Type': 'application/zip'},
params=params, data=open('build/fmt/' + package, 'rb'))
headers={'Content-Type': 'application/zip'} | auth_headers,
data=open('build/fmt/' + package, 'rb'))
if r.status_code != 201:
raise Exception('Failed to upload an asset ' + str(r))

201
support/printable.py Executable file
View File

@ -0,0 +1,201 @@
#!/usr/bin/env python3
# This script is based on
# https://github.com/rust-lang/rust/blob/master/library/core/src/unicode/printable.py
# distributed under https://github.com/rust-lang/rust/blob/master/LICENSE-MIT.
# This script uses the following Unicode tables:
# - UnicodeData.txt
from collections import namedtuple
import csv
import os
import subprocess
NUM_CODEPOINTS=0x110000
def to_ranges(iter):
current = None
for i in iter:
if current is None or i != current[1] or i in (0x10000, 0x20000):
if current is not None:
yield tuple(current)
current = [i, i + 1]
else:
current[1] += 1
if current is not None:
yield tuple(current)
def get_escaped(codepoints):
for c in codepoints:
if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord(' '):
yield c.value
def get_file(f):
try:
return open(os.path.basename(f))
except FileNotFoundError:
subprocess.run(["curl", "-O", f], check=True)
return open(os.path.basename(f))
Codepoint = namedtuple('Codepoint', 'value class_')
def get_codepoints(f):
r = csv.reader(f, delimiter=";")
prev_codepoint = 0
class_first = None
for row in r:
codepoint = int(row[0], 16)
name = row[1]
class_ = row[2]
if class_first is not None:
if not name.endswith("Last>"):
raise ValueError("Missing Last after First")
for c in range(prev_codepoint + 1, codepoint):
yield Codepoint(c, class_first)
class_first = None
if name.endswith("First>"):
class_first = class_
yield Codepoint(codepoint, class_)
prev_codepoint = codepoint
if class_first is not None:
raise ValueError("Missing Last after First")
for c in range(prev_codepoint + 1, NUM_CODEPOINTS):
yield Codepoint(c, None)
def compress_singletons(singletons):
uppers = [] # (upper, # items in lowers)
lowers = []
for i in singletons:
upper = i >> 8
lower = i & 0xff
if len(uppers) == 0 or uppers[-1][0] != upper:
uppers.append((upper, 1))
else:
upper, count = uppers[-1]
uppers[-1] = upper, count + 1
lowers.append(lower)
return uppers, lowers
def compress_normal(normal):
# lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f
# lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff
compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)]
prev_start = 0
for start, count in normal:
truelen = start - prev_start
falselen = count
prev_start = start + count
assert truelen < 0x8000 and falselen < 0x8000
entry = []
if truelen > 0x7f:
entry.append(0x80 | (truelen >> 8))
entry.append(truelen & 0xff)
else:
entry.append(truelen & 0x7f)
if falselen > 0x7f:
entry.append(0x80 | (falselen >> 8))
entry.append(falselen & 0xff)
else:
entry.append(falselen & 0x7f)
compressed.append(entry)
return compressed
def print_singletons(uppers, lowers, uppersname, lowersname):
print(" static constexpr singleton {}[] = {{".format(uppersname))
for u, c in uppers:
print(" {{{:#04x}, {}}},".format(u, c))
print(" };")
print(" static constexpr unsigned char {}[] = {{".format(lowersname))
for i in range(0, len(lowers), 8):
print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8])))
print(" };")
def print_normal(normal, normalname):
print(" static constexpr unsigned char {}[] = {{".format(normalname))
for v in normal:
print(" {}".format(" ".join("{:#04x},".format(i) for i in v)))
print(" };")
def main():
file = get_file("https://www.unicode.org/Public/UNIDATA/UnicodeData.txt")
codepoints = get_codepoints(file)
CUTOFF=0x10000
singletons0 = []
singletons1 = []
normal0 = []
normal1 = []
extra = []
for a, b in to_ranges(get_escaped(codepoints)):
if a > 2 * CUTOFF:
extra.append((a, b - a))
elif a == b - 1:
if a & CUTOFF:
singletons1.append(a & ~CUTOFF)
else:
singletons0.append(a)
elif a == b - 2:
if a & CUTOFF:
singletons1.append(a & ~CUTOFF)
singletons1.append((a + 1) & ~CUTOFF)
else:
singletons0.append(a)
singletons0.append(a + 1)
else:
if a >= 2 * CUTOFF:
extra.append((a, b - a))
elif a & CUTOFF:
normal1.append((a & ~CUTOFF, b - a))
else:
normal0.append((a, b - a))
singletons0u, singletons0l = compress_singletons(singletons0)
singletons1u, singletons1l = compress_singletons(singletons1)
normal0 = compress_normal(normal0)
normal1 = compress_normal(normal1)
print("""\
FMT_FUNC auto is_printable(uint32_t cp) -> bool {\
""")
print_singletons(singletons0u, singletons0l, 'singletons0', 'singletons0_lower')
print_singletons(singletons1u, singletons1l, 'singletons1', 'singletons1_lower')
print_normal(normal0, 'normal0')
print_normal(normal1, 'normal1')
print("""\
auto lower = static_cast<uint16_t>(cp);
if (cp < 0x10000) {
return is_printable(lower, singletons0,
sizeof(singletons0) / sizeof(*singletons0),
singletons0_lower, normal0, sizeof(normal0));
}
if (cp < 0x20000) {
return is_printable(lower, singletons1,
sizeof(singletons1) / sizeof(*singletons1),
singletons1_lower, normal1, sizeof(normal1));
}\
""")
for a, b in extra:
print(" if (0x{:x} <= cp && cp < 0x{:x}) return false;".format(a, a + b))
print("""\
return cp < 0x{:x};
}}\
""".format(NUM_CODEPOINTS))
if __name__ == '__main__':
main()

View File

@ -65,7 +65,7 @@ class Translator(nodes.NodeVisitor):
self.write('\n\n')
def visit_paragraph(self, node):
pass
self.write('\n\n')
def depart_paragraph(self, node):
pass
@ -138,6 +138,13 @@ class Translator(nodes.NodeVisitor):
def depart_table(self, node):
pass
def visit_system_message(self, node):
pass
def depart_system_message(self, node):
pass
class MDWriter(writers.Writer):
"""GitHub-flavored markdown writer"""

View File

@ -1,119 +0,0 @@
#!/usr/bin/env python
# Build the project on Travis CI.
from __future__ import print_function
import errno, os, shutil, subprocess, sys, urllib
from subprocess import call, check_call, Popen, PIPE, STDOUT
def rmtree_if_exists(dir):
try:
shutil.rmtree(dir)
except OSError as e:
if e.errno == errno.ENOENT:
pass
def makedirs_if_not_exist(dir):
try:
os.makedirs(dir)
except OSError as e:
if e.errno != errno.EEXIST:
raise
def install_dependencies():
branch = os.environ['TRAVIS_BRANCH']
if branch != 'master':
print('Branch: ' + branch)
exit(0) # Ignore non-master branches
check_call('curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key ' +
'| sudo apt-key add -', shell=True)
check_call('echo "deb https://deb.nodesource.com/node_0.10 precise main" ' +
'| sudo tee /etc/apt/sources.list.d/nodesource.list', shell=True)
check_call(['sudo', 'apt-get', 'update'])
check_call(['sudo', 'apt-get', 'install', 'python-virtualenv', 'nodejs'])
check_call(['sudo', 'npm', 'install', '-g', 'less@2.6.1', 'less-plugin-clean-css'])
deb_file = 'doxygen_1.8.6-2_amd64.deb'
urllib.urlretrieve('http://mirrors.kernel.org/ubuntu/pool/main/d/doxygen/' +
deb_file, deb_file)
check_call(['sudo', 'dpkg', '-i', deb_file])
fmt_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
build = os.environ['BUILD']
if build == 'Doc':
travis = 'TRAVIS' in os.environ
if travis:
install_dependencies()
sys.path.insert(0, os.path.join(fmt_dir, 'doc'))
import build
build.create_build_env()
html_dir = build.build_docs()
repo = 'fmtlib.github.io'
if travis and 'KEY' not in os.environ:
# Don't update the repo if building on Travis from an account that
# doesn't have push access.
print('Skipping update of ' + repo)
exit(0)
# Clone the fmtlib.github.io repo.
rmtree_if_exists(repo)
git_url = 'https://github.com/' if travis else 'git@github.com:'
check_call(['git', 'clone', git_url + 'fmtlib/{}.git'.format(repo)])
# Copy docs to the repo.
target_dir = os.path.join(repo, 'dev')
rmtree_if_exists(target_dir)
shutil.copytree(html_dir, target_dir, ignore=shutil.ignore_patterns('.*'))
if travis:
check_call(['git', 'config', '--global', 'user.name', 'amplbot'])
check_call(['git', 'config', '--global', 'user.email', 'viz@ampl.com'])
# Push docs to GitHub pages.
check_call(['git', 'add', '--all'], cwd=repo)
if call(['git', 'diff-index', '--quiet', 'HEAD'], cwd=repo):
check_call(['git', 'commit', '-m', 'Update documentation'], cwd=repo)
cmd = 'git push'
if travis:
cmd += ' https://$KEY@github.com/fmtlib/fmtlib.github.io.git master'
p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd=repo)
# Print the output without the key.
print(p.communicate()[0].replace(os.environ['KEY'], '$KEY'))
if p.returncode != 0:
raise subprocess.CalledProcessError(p.returncode, cmd)
exit(0)
standard = os.environ['STANDARD']
install_dir = os.path.join(fmt_dir, "_install")
build_dir = os.path.join(fmt_dir, "_build")
test_build_dir = os.path.join(fmt_dir, "_build_test")
# Configure the library.
makedirs_if_not_exist(build_dir)
cmake_flags = [
'-DCMAKE_INSTALL_PREFIX=' + install_dir, '-DCMAKE_BUILD_TYPE=' + build,
'-DCMAKE_CXX_STANDARD=' + standard
]
# Make sure the fuzzers still compile.
main_cmake_flags = list(cmake_flags)
if 'ENABLE_FUZZING' in os.environ:
main_cmake_flags += ['-DFMT_FUZZ=ON', '-DFMT_FUZZ_LINKMAIN=On']
check_call(['cmake', '-DFMT_DOC=OFF', '-DFMT_PEDANTIC=ON', '-DFMT_WERROR=ON', fmt_dir] +
main_cmake_flags, cwd=build_dir)
# Build the library.
check_call(['cmake', '--build','.'], cwd=build_dir)
# Test the library.
env = os.environ.copy()
env['CTEST_OUTPUT_ON_FAILURE'] = '1'
if call(['make', 'test'], env=env, cwd=build_dir):
with open(os.path.join(build_dir, 'Testing', 'Temporary', 'LastTest.log'), 'r') as f:
print(f.read())
sys.exit(-1)
# Install the library.
check_call(['make', 'install'], cwd=build_dir)
# Test installation.
makedirs_if_not_exist(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

@ -1,30 +0,0 @@
#!/usr/bin/env python
# Update the coverity branch from the master branch.
# It is not done automatically because Coverity Scan limits
# the number of submissions per day.
from __future__ import print_function
import shutil, tempfile
from subprocess import check_output, STDOUT
class Git:
def __init__(self, dir):
self.dir = dir
def __call__(self, *args):
output = check_output(['git'] + list(args), cwd=self.dir, stderr=STDOUT)
print(output)
return output
dir = tempfile.mkdtemp()
try:
git = Git(dir)
git('clone', '-b', 'coverity', 'git@github.com:fmtlib/fmt.git', dir)
output = git('merge', '-X', 'theirs', '--no-commit', 'origin/master')
if 'Fast-forward' not in output:
git('reset', 'HEAD', '.travis.yml')
git('checkout', '--', '.travis.yml')
git('commit', '-m', 'Update coverity branch')
git('push')
finally:
shutil.rmtree(dir)

View File

@ -1,82 +1,49 @@
#------------------------------------------------------------------------------
# Build the google test library
add_subdirectory(gtest)
# We compile Google Test ourselves instead of using pre-compiled libraries.
# See the Google Test FAQ "Why is it not recommended to install a
# pre-compiled copy of Google Test (for example, into /usr/local)?"
# 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_definitions(gmock PUBLIC GTEST_HAS_STD_WSTRING=1)
target_include_directories(gmock SYSTEM PUBLIC . gmock gtest)
find_package(Threads)
if (Threads_FOUND)
target_link_libraries(gmock ${CMAKE_THREAD_LIBS_INIT})
else ()
target_compile_definitions(gmock PUBLIC GTEST_HAS_PTHREAD=0)
endif ()
if (NOT SUPPORTS_VARIADIC_TEMPLATES)
target_compile_definitions(gmock PUBLIC GTEST_LANG_CXX11=0)
endif ()
if (MSVC)
# Workaround a bug in implementation of variadic templates in MSVC11.
target_compile_definitions(gmock PUBLIC _VARIADIC_MAX=10)
# Disable MSVC warnings of _CRT_INSECURE_DEPRECATE functions.
target_compile_definitions(gmock PRIVATE _CRT_SECURE_NO_WARNINGS)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# Disable MSVC warnings of POSIX functions.
target_compile_options(gmock PUBLIC -Wno-deprecated-declarations)
endif ()
endif ()
# GTest doesn't detect <tuple> with clang.
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=1)
#------------------------------------------------------------------------------
# Build the actual library tests
include(CheckSymbolExists)
set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc)
add_library(test-main STATIC ${TEST_MAIN_SRC})
target_include_directories(test-main SYSTEM PUBLIC gtest gmock)
target_link_libraries(test-main gmock fmt)
include(CheckCXXCompilerFlag)
# Workaround GTest bug https://github.com/google/googletest/issues/705.
check_cxx_compiler_flag(
-fno-delete-null-pointer-checks HAVE_FNO_DELETE_NULL_POINTER_CHECKS)
if (HAVE_FNO_DELETE_NULL_POINTER_CHECKS)
target_compile_options(test-main PUBLIC -fno-delete-null-pointer-checks)
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)
endif ()
target_include_directories(test-main PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
target_link_libraries(test-main gtest fmt)
function(add_fmt_executable name)
add_executable(${name} ${ARGN})
if (MINGW)
target_link_libraries(${name} -static-libgcc -static-libstdc++)
# (Wstringop-overflow) - [meta-bug] bogus/missing -Wstringop-overflow warnings
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88443
# Bogus -Wstringop-overflow warning
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100395
# [10 Regression] spurious -Wstringop-overflow writing to a trailing array plus offset
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95353
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND
NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
target_compile_options(${name} PRIVATE -Wno-stringop-overflow)
# The linker flag is needed for LTO.
target_link_libraries(${name} -Wno-stringop-overflow)
endif ()
endfunction()
# Adds a test.
# Usage: add_fmt_test(name srcs...)
function(add_fmt_test name)
add_fmt_executable(${name} ${name}.cc ${ARGN})
target_link_libraries(${name} test-main)
cmake_parse_arguments(ADD_FMT_TEST "HEADER_ONLY;MODULE" "" "" ${ARGN})
set(sources ${name}.cc ${ADD_FMT_TEST_UNPARSED_ARGUMENTS})
if (ADD_FMT_TEST_HEADER_ONLY)
set(sources ${sources} ${TEST_MAIN_SRC} ../src/os.cc)
set(libs gtest fmt-header-only)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wno-weak-vtables)
endif ()
elseif (ADD_FMT_TEST_MODULE)
set(libs test-main test-module)
set_source_files_properties(${name}.cc PROPERTIES OBJECT_DEPENDS test-module)
else ()
set(libs test-main fmt)
endif ()
add_fmt_executable(${name} ${sources})
target_link_libraries(${name} ${libs})
# Define if certain C++ features can be used.
if (FMT_PEDANTIC)
@ -85,83 +52,118 @@ function(add_fmt_test name)
if (FMT_WERROR)
target_compile_options(${name} PRIVATE ${WERROR_FLAG})
endif ()
target_include_directories(${name} SYSTEM PUBLIC gtest gmock)
add_test(NAME ${name} COMMAND ${name})
endfunction()
if (FMT_MODULE)
return ()
endif ()
add_fmt_test(args-test)
add_fmt_test(assert-test)
add_fmt_test(chrono-test)
add_fmt_test(color-test)
add_fmt_test(core-test)
add_fmt_test(grisu-test)
target_compile_definitions(grisu-test PRIVATE FMT_USE_GRISU=1)
add_fmt_test(gtest-extra-test)
add_fmt_test(format-test mock-allocator.h)
if (MSVC)
target_compile_options(format-test PRIVATE /bigobj)
endif ()
if (NOT (MSVC AND BUILD_SHARED_LIBS))
add_fmt_test(format-impl-test)
add_fmt_test(format-impl-test HEADER_ONLY header-only-test.cc)
endif ()
add_fmt_test(locale-test)
add_fmt_test(ostream-test)
add_fmt_test(compile-test)
add_fmt_test(compile-fp-test HEADER_ONLY)
if (MSVC)
# Without this option, MSVC returns 199711L for the __cplusplus macro.
target_compile_options(compile-fp-test PRIVATE /Zc:__cplusplus)
endif()
add_fmt_test(printf-test)
add_fmt_test(custom-formatter-test)
add_fmt_test(ranges-test)
add_fmt_test(scan-test)
add_fmt_test(ranges-test ranges-odr-test.cc)
if (NOT MSVC_BUILD_STATIC)
add_fmt_test(scan-test)
check_symbol_exists(strptime "time.h" HAVE_STRPTIME)
if (HAVE_STRPTIME)
target_compile_definitions(scan-test PRIVATE FMT_HAVE_STRPTIME)
endif ()
add_fmt_test(std-test)
try_compile(compile_result_unused
${CMAKE_CURRENT_BINARY_DIR}
SOURCES ${CMAKE_CURRENT_LIST_DIR}/detect-stdfs.cc
OUTPUT_VARIABLE RAWOUTPUT)
string(REGEX REPLACE ".*libfound \"([^\"]*)\".*" "\\1" STDLIBFS "${RAWOUTPUT}")
if (STDLIBFS)
target_link_libraries(std-test ${STDLIBFS})
endif ()
add_fmt_test(unicode-test HEADER_ONLY)
if (MSVC)
target_compile_options(unicode-test PRIVATE /utf-8)
endif ()
add_fmt_test(xchar-test)
add_fmt_test(enforce-checks-test)
target_compile_definitions(enforce-checks-test PRIVATE
-DFMT_ENFORCE_COMPILE_STRING)
if (FMT_MODULE)
# The tests need {fmt} to be compiled as traditional library
# because of visibility of implementation details.
# If module support is present the module tests require a
# test-only module to be built from {fmt}
add_library(test-module OBJECT ${CMAKE_SOURCE_DIR}/src/fmt.cc)
target_compile_features(test-module PUBLIC cxx_std_11)
target_include_directories(test-module PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
enable_module(test-module)
add_fmt_test(module-test MODULE test-main.cc)
if (MSVC)
target_compile_options(test-module PRIVATE /utf-8 /Zc:__cplusplus
/Zc:externConstexpr /Zc:inline)
target_compile_options(module-test PRIVATE /utf-8 /Zc:__cplusplus
/Zc:externConstexpr /Zc:inline)
endif ()
endif ()
if (NOT DEFINED MSVC_STATIC_RUNTIME AND MSVC)
foreach (flag_var
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if (${flag_var} MATCHES "^(/|-)(MT|MTd)")
set(MSVC_STATIC_RUNTIME ON)
break()
endif()
endforeach()
endif()
if (NOT MSVC_STATIC_RUNTIME)
add_fmt_executable(posix-mock-test
posix-mock-test.cc ../src/format.cc ${TEST_MAIN_SRC})
target_include_directories(
posix-mock-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_link_libraries(posix-mock-test gmock)
target_include_directories(posix-mock-test SYSTEM PUBLIC gtest gmock)
target_link_libraries(posix-mock-test gtest)
if (FMT_PEDANTIC)
target_compile_options(posix-mock-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
if (HAVE_STRTOD_L)
target_compile_definitions(posix-mock-test PRIVATE FMT_LOCALE)
endif ()
add_test(NAME posix-mock-test COMMAND posix-mock-test)
add_fmt_test(posix-test)
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}/include)
target_compile_definitions(header-only-test PRIVATE FMT_HEADER_ONLY=1)
add_fmt_test(os-test)
endif ()
message(STATUS "FMT_PEDANTIC: ${FMT_PEDANTIC}")
if (FMT_PEDANTIC)
# MSVC fails to compile GMock when C++17 is enabled.
if (FMT_HAS_VARIANT AND NOT MSVC)
add_fmt_test(std-format-test)
set_property(TARGET std-format-test PROPERTY CXX_STANDARD 17)
endif ()
# Test that the library can be compiled with exceptions disabled.
# -fno-exception is broken in icc: https://github.com/fmtlib/fmt/issues/822.
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG)
endif ()
if (HAVE_FNO_EXCEPTIONS_FLAG)
add_library(noexception-test ../src/format.cc)
add_library(noexception-test ../src/format.cc noexception-test.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_compile_options(noexception-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
# Test that the library compiles without locale.
@ -170,19 +172,11 @@ if (FMT_PEDANTIC)
nolocale-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_definitions(
nolocale-test PRIVATE FMT_STATIC_THOUSANDS_SEPARATOR=1)
endif ()
# Test that the library compiles without windows.h.
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
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 ()
# These tests are disabled on Windows because they take too long.
if (FMT_PEDANTIC AND NOT WIN32)
# Test if incorrect API usages produce compilation error.
add_test(compile-error-test ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMAKE_CURRENT_SOURCE_DIR}/compile-error-test"
@ -191,14 +185,11 @@ if (FMT_PEDANTIC)
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
"-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}")
endif ()
"-DFMT_DIR=${CMAKE_SOURCE_DIR}")
# These tests are disabled on Windows because they take too long.
if (FMT_PEDANTIC AND NOT WIN32)
# Test if the targets are found from the build directory.
add_test(find-package-test ${CMAKE_CTEST_COMMAND}
-C ${CMAKE_BUILD_TYPE}
@ -209,6 +200,7 @@ if (FMT_PEDANTIC AND NOT WIN32)
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DFMT_DIR=${PROJECT_BINARY_DIR}"
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
@ -229,20 +221,37 @@ if (FMT_PEDANTIC AND NOT WIN32)
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
endif ()
# Activate optional CUDA tests if CUDA is found. For version selection, see
# https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#cpp14-language-features
if (${CMAKE_VERSION} VERSION_LESS 3.15)
find_package(CUDA 9.0)
else ()
include(CheckLanguage)
check_language(CUDA)
if (CMAKE_CUDA_COMPILER)
enable_language(CUDA OPTIONAL)
set(CUDA_FOUND TRUE)
endif ()
# This test are disabled on Windows because it is only *NIX issue.
if (FMT_PEDANTIC AND NOT WIN32)
add_test(static-export-test ${CMAKE_CTEST_COMMAND}
-C ${CMAKE_BUILD_TYPE}
--build-and-test
"${CMAKE_CURRENT_SOURCE_DIR}/static-export-test"
"${CMAKE_CURRENT_BINARY_DIR}/static-export-test"
--build-generator ${CMAKE_GENERATOR}
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
endif ()
if (CUDA_FOUND)
add_subdirectory(cuda-test)
add_test(NAME cuda-test COMMAND fmt-in-cuda-test)
# Activate optional CUDA tests if CUDA is found. For version selection see
# https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#cpp14-language-features
if (FMT_CUDA_TEST)
if (${CMAKE_VERSION} VERSION_LESS 3.15)
find_package(CUDA 9.0)
else ()
include(CheckLanguage)
check_language(CUDA)
if (CMAKE_CUDA_COMPILER)
enable_language(CUDA OPTIONAL)
set(CUDA_FOUND TRUE)
endif ()
endif ()
if (CUDA_FOUND)
add_subdirectory(cuda-test)
add_test(NAME cuda-test COMMAND fmt-in-cuda-test)
endif ()
endif ()

View File

@ -1,17 +1,17 @@
cmake_minimum_required(VERSION 3.1.0)
cmake_minimum_required(VERSION 3.8...3.25)
project(fmt-test)
project(fmt-test CXX)
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})
add_executable(library-test main.cc)
target_include_directories(library-test PUBLIC SYSTEM .)
target_compile_options(library-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
target_link_libraries(library-test fmt::fmt)
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})
add_executable(header-only-test main.cc)
target_include_directories(header-only-test PUBLIC SYSTEM .)
target_compile_options(header-only-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
target_link_libraries(header-only-test fmt::fmt-header-only)
endif ()

View File

@ -1,6 +1,5 @@
#include "fmt/format.h"
#include "fmt/core.h"
int main(int argc, char** argv) {
for(int i = 0; i < argc; ++i)
fmt::print("{}: {}\n", i, argv[i]);
for (int i = 0; i < argc; ++i) fmt::print("{}: {}\n", i, argv[i]);
}

186
test/args-test.cc Normal file
View File

@ -0,0 +1,186 @@
// Formatting library for C++ - dynamic argument store tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/args.h"
#include <memory>
#include "gtest/gtest.h"
TEST(args_test, basic) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(42);
store.push_back("abc1");
store.push_back(1.5f);
EXPECT_EQ("42 and abc1 and 1.5", fmt::vformat("{} and {} and {}", store));
}
TEST(args_test, strings_and_refs) {
// Unfortunately the tests are compiled with old ABI so strings use COW.
fmt::dynamic_format_arg_store<fmt::format_context> store;
char str[] = "1234567890";
store.push_back(str);
store.push_back(std::cref(str));
store.push_back(fmt::string_view{str});
str[0] = 'X';
auto result = fmt::vformat("{} and {} and {}", store);
EXPECT_EQ("1234567890 and X234567890 and X234567890", result);
}
struct custom_type {
int i = 0;
};
FMT_BEGIN_NAMESPACE
template <> struct formatter<custom_type> {
auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const custom_type& p, FormatContext& ctx) -> decltype(ctx.out()) {
return fmt::format_to(ctx.out(), "cust={}", p.i);
}
};
FMT_END_NAMESPACE
TEST(args_test, custom_format) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
auto c = custom_type();
store.push_back(c);
++c.i;
store.push_back(c);
++c.i;
store.push_back(std::cref(c));
++c.i;
auto result = fmt::vformat("{} and {} and {}", store);
EXPECT_EQ("cust=0 and cust=1 and cust=3", result);
}
struct to_stringable {
friend fmt::string_view to_string_view(to_stringable) { return {}; }
};
FMT_BEGIN_NAMESPACE
template <> struct formatter<to_stringable> {
auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) {
return ctx.begin();
}
auto format(to_stringable, format_context& ctx) -> decltype(ctx.out()) {
return ctx.out();
}
};
FMT_END_NAMESPACE
TEST(args_test, to_string_and_formatter) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
auto s = to_stringable();
store.push_back(s);
store.push_back(std::cref(s));
fmt::vformat("", store);
}
TEST(args_test, named_int) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(fmt::arg("a1", 42));
EXPECT_EQ("42", fmt::vformat("{a1}", store));
}
TEST(args_test, named_strings) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
char str[] = "1234567890";
store.push_back(fmt::arg("a1", str));
store.push_back(fmt::arg("a2", std::cref(str)));
str[0] = 'X';
EXPECT_EQ("1234567890 and X234567890", fmt::vformat("{a1} and {a2}", store));
}
TEST(args_test, named_arg_by_ref) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
char band[] = "Rolling Stones";
store.push_back(fmt::arg("band", std::cref(band)));
band[9] = 'c'; // Changing band affects the output.
EXPECT_EQ(fmt::vformat("{band}", store), "Rolling Scones");
}
TEST(args_test, named_custom_format) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
auto c = custom_type();
store.push_back(fmt::arg("c1", c));
++c.i;
store.push_back(fmt::arg("c2", c));
++c.i;
store.push_back(fmt::arg("c_ref", std::cref(c)));
++c.i;
auto result = fmt::vformat("{c1} and {c2} and {c_ref}", store);
EXPECT_EQ("cust=0 and cust=1 and cust=3", result);
}
TEST(args_test, clear) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(42);
auto result = fmt::vformat("{}", store);
EXPECT_EQ("42", result);
store.push_back(43);
result = fmt::vformat("{} and {}", store);
EXPECT_EQ("42 and 43", result);
store.clear();
store.push_back(44);
result = fmt::vformat("{}", store);
EXPECT_EQ("44", result);
}
TEST(args_test, reserve) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.reserve(2, 1);
store.push_back(1.5f);
store.push_back(fmt::arg("a1", 42));
auto result = fmt::vformat("{a1} and {}", store);
EXPECT_EQ("42 and 1.5", result);
}
struct copy_throwable {
copy_throwable() {}
copy_throwable(const copy_throwable&) { throw "deal with it"; }
};
FMT_BEGIN_NAMESPACE
template <> struct formatter<copy_throwable> {
auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) {
return ctx.begin();
}
auto format(copy_throwable, format_context& ctx) -> decltype(ctx.out()) {
return ctx.out();
}
};
FMT_END_NAMESPACE
TEST(args_test, throw_on_copy) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(std::string("foo"));
try {
store.push_back(copy_throwable());
} catch (...) {
}
EXPECT_EQ(fmt::vformat("{}", store), "foo");
}
TEST(args_test, move_constructor) {
using store_type = fmt::dynamic_format_arg_store<fmt::format_context>;
auto store = std::unique_ptr<store_type>(new store_type());
store->push_back(42);
store->push_back(std::string("foo"));
store->push_back(fmt::arg("a1", "foo"));
auto moved_store = std::move(*store);
store.reset();
EXPECT_EQ(fmt::vformat("{} {} {a1}", moved_store), "42 foo foo");
}

View File

@ -1,4 +1,8 @@
// Formatting library for C++ - assertion tests
// Formatting library for C++ - FMT_ASSERT test
//
// It is a separate test to minimize the number of EXPECT_DEBUG_DEATH checks
// which are slow on some platforms. In other tests FMT_ASSERT is made to throw
// an exception which is much faster and easier to check.
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
@ -6,24 +10,18 @@
// For the license information refer to format.h.
#include "fmt/core.h"
#include "gtest.h"
#include "gtest/gtest.h"
TEST(assert_test, fail) {
#if GTEST_HAS_DEATH_TEST
# define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \
EXPECT_DEBUG_DEATH(statement, regex)
EXPECT_DEBUG_DEATH(FMT_ASSERT(false, "don't panic!"), "don't panic!");
#else
# define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \
GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
fmt::print("warning: death tests are not supported\n");
#endif
TEST(AssertTest, Fail) {
EXPECT_DEBUG_DEATH_IF_SUPPORTED(FMT_ASSERT(false, "don't panic!"),
"don't panic!");
}
bool test_condition = false;
TEST(AssertTest, DanglingElse) {
TEST(assert_test, dangling_else) {
bool test_condition = false;
bool executed_else = false;
if (test_condition)
FMT_ASSERT(true, "");

File diff suppressed because it is too large Load Diff

View File

@ -6,48 +6,12 @@
// For the license information refer to format.h.
#include "fmt/color.h"
#include "gtest-extra.h"
TEST(ColorsTest, ColorsPrint) {
EXPECT_WRITE(stdout, fmt::print(fg(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(fg(fmt::color::blue), "blue"),
"\x1b[38;2;000;000;255mblue\x1b[0m");
EXPECT_WRITE(
stdout,
fmt::print(fg(fmt::color::blue) | bg(fmt::color::red), "two color"),
"\x1b[38;2;000;000;255m\x1b[48;2;255;000;000mtwo color\x1b[0m");
EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::bold, "bold"),
"\x1b[1mbold\x1b[0m");
EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::italic, "italic"),
"\x1b[3mitalic\x1b[0m");
EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::underline, "underline"),
"\x1b[4munderline\x1b[0m");
EXPECT_WRITE(stdout,
fmt::print(fmt::emphasis::strikethrough, "strikethrough"),
"\x1b[9mstrikethrough\x1b[0m");
EXPECT_WRITE(
stdout,
fmt::print(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"),
"\x1b[1m\x1b[38;2;000;000;255mblue/bold\x1b[0m");
EXPECT_WRITE(stderr, fmt::print(stderr, fmt::emphasis::bold, "bold error"),
"\x1b[1mbold error\x1b[0m");
EXPECT_WRITE(stderr, fmt::print(stderr, fg(fmt::color::blue), "blue log"),
"\x1b[38;2;000;000;255mblue log\x1b[0m");
EXPECT_WRITE(stdout, fmt::print(fmt::text_style(), "hi"), "hi");
EXPECT_WRITE(stdout, fmt::print(fg(fmt::terminal_color::red), "tred"),
"\x1b[31mtred\x1b[0m");
EXPECT_WRITE(stdout, fmt::print(bg(fmt::terminal_color::cyan), "tcyan"),
"\x1b[46mtcyan\x1b[0m");
EXPECT_WRITE(stdout,
fmt::print(fg(fmt::terminal_color::bright_green), "tbgreen"),
"\x1b[92mtbgreen\x1b[0m");
EXPECT_WRITE(stdout,
fmt::print(bg(fmt::terminal_color::bright_magenta), "tbmagenta"),
"\x1b[105mtbmagenta\x1b[0m");
}
#include <iterator> // std::back_inserter
TEST(ColorsTest, Format) {
#include "gtest-extra.h" // EXPECT_WRITE
TEST(color_test, format) {
EXPECT_EQ(fmt::format(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"),
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
EXPECT_EQ(fmt::format(fg(fmt::color::blue), "blue"),
@ -56,10 +20,16 @@ TEST(ColorsTest, Format) {
fmt::format(fg(fmt::color::blue) | bg(fmt::color::red), "two color"),
"\x1b[38;2;000;000;255m\x1b[48;2;255;000;000mtwo color\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold"), "\x1b[1mbold\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::faint, "faint"), "\x1b[2mfaint\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::italic, "italic"),
"\x1b[3mitalic\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::underline, "underline"),
"\x1b[4munderline\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::blink, "blink"), "\x1b[5mblink\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::reverse, "reverse"),
"\x1b[7mreverse\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::conceal, "conceal"),
"\x1b[8mconceal\x1b[0m");
EXPECT_EQ(fmt::format(fmt::emphasis::strikethrough, "strikethrough"),
"\x1b[9mstrikethrough\x1b[0m");
EXPECT_EQ(
@ -80,4 +50,23 @@ TEST(ColorsTest, Format) {
"\x1b[105mtbmagenta\x1b[0m");
EXPECT_EQ(fmt::format(fg(fmt::terminal_color::red), "{}", "foo"),
"\x1b[31mfoo\x1b[0m");
EXPECT_EQ(fmt::format("{}{}", fmt::styled("red", fg(fmt::color::red)),
fmt::styled("bold", fmt::emphasis::bold)),
"\x1b[38;2;255;000;000mred\x1b[0m\x1b[1mbold\x1b[0m");
EXPECT_EQ(fmt::format("{}", fmt::styled("bar", fg(fmt::color::blue) |
fmt::emphasis::underline)),
"\x1b[4m\x1b[38;2;000;000;255mbar\x1b[0m");
}
TEST(color_test, format_to) {
auto out = std::string();
fmt::format_to(std::back_inserter(out), fg(fmt::rgb(255, 20, 30)),
"rgb(255,20,30){}{}{}", 1, 2, 3);
EXPECT_EQ(fmt::to_string(out),
"\x1b[38;2;255;020;030mrgb(255,20,30)123\x1b[0m");
}
TEST(color_test, print) {
EXPECT_WRITE(stdout, fmt::print(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"),
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
}

View File

@ -1,71 +1,182 @@
# Test if compile errors are produced where necessary.
cmake_minimum_required(VERSION 3.1.0)
cmake_minimum_required(VERSION 3.8...3.25)
project(compile-error-test CXX)
include(CheckCXXSourceCompiles)
include(CheckCXXCompilerFlag)
set(fmt_headers "
#include <fmt/format.h>
#include <fmt/xchar.h>
#include <fmt/ostream.h>
#include <iostream>
")
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG} ${PEDANTIC_COMPILE_FLAGS})
set(error_test_names "")
set(non_error_test_content "")
function (generate_source result fragment)
set(${result} "
#define FMT_HEADER_ONLY 1
#include \"fmt/format.h\"
int main() {
${fragment}
}
" PARENT_SCOPE)
# For error tests (we expect them to produce compilation error):
# * adds a name of test into `error_test_names` list
# * generates a single source file (with the same name) for each test
# For non-error tests (we expect them to compile successfully):
# * adds a code segment as separate function to `non_error_test_content`
function (expect_compile name code_fragment)
cmake_parse_arguments(EXPECT_COMPILE "ERROR" "" "" ${ARGN})
string(MAKE_C_IDENTIFIER "${name}" test_name)
if (EXPECT_COMPILE_ERROR)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/${test_name}.cc" "
${fmt_headers}
void ${test_name}() {
${code_fragment}
}
")
set(error_test_names_copy "${error_test_names}")
list(APPEND error_test_names_copy "${test_name}")
set(error_test_names "${error_test_names_copy}" PARENT_SCOPE)
else()
set(non_error_test_content "
${non_error_test_content}
void ${test_name}() {
${code_fragment}
}" PARENT_SCOPE)
endif()
endfunction ()
function (expect_compile code)
generate_source(source "${code}")
check_cxx_source_compiles("${source}" compiles)
if (NOT compiles)
set(error_msg "Compile error for: ${code}")
endif ()
# Unset the CMake cache variable compiles. Otherwise the compile test will
# just use cached information next time it runs.
unset(compiles CACHE)
if (error_msg)
message(FATAL_ERROR ${error_msg})
# Generates a source file for non-error test with `non_error_test_content` and
# CMake project file with all error and single non-error test targets.
function (run_tests)
set(cmake_targets "")
foreach(test_name IN LISTS error_test_names)
set(cmake_targets "
${cmake_targets}
add_library(test-${test_name} ${test_name}.cc)
target_link_libraries(test-${test_name} PRIVATE fmt::fmt)
")
endforeach()
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/non_error_test.cc" "
${fmt_headers}
${non_error_test_content}
")
set(cmake_targets "
${cmake_targets}
add_library(non-error-test non_error_test.cc)
target_link_libraries(non-error-test PRIVATE fmt::fmt)
")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/CMakeLists.txt" "
cmake_minimum_required(VERSION 3.8...3.25)
project(tests CXX)
add_subdirectory(${FMT_DIR} fmt)
${cmake_targets}
")
set(build_directory "${CMAKE_CURRENT_BINARY_DIR}/test/build")
file(MAKE_DIRECTORY "${build_directory}")
execute_process(
COMMAND
"${CMAKE_COMMAND}"
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DCMAKE_GENERATOR=${CMAKE_GENERATOR}"
"-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}"
"-DFMT_DIR=${FMT_DIR}"
"${CMAKE_CURRENT_BINARY_DIR}/test"
WORKING_DIRECTORY "${build_directory}"
RESULT_VARIABLE result_var
OUTPUT_VARIABLE output_var
ERROR_VARIABLE output_var)
if (NOT result_var EQUAL 0)
message(FATAL_ERROR "Unable to configure:\n${output_var}")
endif()
foreach(test_name IN LISTS error_test_names)
execute_process(
COMMAND
"${CMAKE_COMMAND}" --build "${build_directory}" --target "test-${test_name}"
WORKING_DIRECTORY "${build_directory}"
RESULT_VARIABLE result_var
OUTPUT_VARIABLE output_var
ERROR_QUIET)
if (result_var EQUAL 0)
message(SEND_ERROR "No compile error for \"${test_name}\":\n${output_var}")
endif ()
endforeach()
execute_process(
COMMAND
"${CMAKE_COMMAND}" --build "${build_directory}" --target "non-error-test"
WORKING_DIRECTORY "${build_directory}"
RESULT_VARIABLE result_var
OUTPUT_VARIABLE output_var
ERROR_VARIABLE output_var)
if (NOT result_var EQUAL 0)
message(SEND_ERROR "Compile error for combined non-error test:\n${output_var}")
endif ()
endfunction ()
function (expect_compile_error code)
generate_source(source "${code}")
check_cxx_source_compiles("${source}" compiles)
if (compiles)
set(error_msg "No compile error for: ${code}")
endif ()
# Unset the CMake cache variable compiles. Otherwise the compile test will
# just use cached information next time it runs.
unset(compiles CACHE)
if (error_msg)
message(FATAL_ERROR ${error_msg})
endif ()
endfunction ()
# check if the source file skeleton compiles
expect_compile("")
expect_compile(check "")
expect_compile(check-error "compilation_error" ERROR)
# Formatting a wide character with a narrow format string is forbidden.
expect_compile_error("fmt::format(\"{}\", L'a');")
expect_compile(wide-character-narrow-format-string "fmt::format(L\"{}\", L'a');")
expect_compile(wide-character-narrow-format-string-error "fmt::format(\"{}\", L'a');" ERROR)
# Formatting a wide string with a narrow format string is forbidden.
expect_compile_error("fmt::format(\"{}\", L\"foo\");")
expect_compile(wide-string-narrow-format-string "fmt::format(L\"{}\", L\"foo\");")
expect_compile(wide-string-narrow-format-string-error "fmt::format(\"{}\", L\"foo\");" ERROR)
# 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\");")
expect_compile(narrow-string-wide-format-string "fmt::format(L\"{}\", L\"foo\");")
expect_compile(narrow-string-wide-format-string-error "fmt::format(L\"{}\", \"foo\");" ERROR)
# Formatting a wide string with a narrow format string is forbidden.
expect_compile_error("
expect_compile(cast-to-string "
struct S {
operator std::string() const { return std::string(); }
};
fmt::format(\"{}\", std::string(S()));
")
expect_compile(cast-to-string-error "
struct S {
operator std::string() const { return std::string(); }
};
fmt::format(\"{}\", S());
" ERROR)
# Formatting a function
expect_compile(format-function "
void (*f)();
fmt::format(\"{}\", fmt::ptr(f));
")
expect_compile(format-function-error "
void (*f)();
fmt::format(\"{}\", f);
" ERROR)
# Formatting an unformattable argument should always be a compile time error
expect_compile(format-lots-of-arguments-with-unformattable "
struct E {};
fmt::format(\"\", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, E());
" ERROR)
expect_compile(format-lots-of-arguments-with-function "
void (*f)();
fmt::format(\"\", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, f);
" ERROR)
# Check if user-defined literals are available
include(CheckCXXSourceCompiles)
set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG})
check_cxx_source_compiles("
void operator\"\" _udl(long double);
int main() {}"
SUPPORTS_USER_DEFINED_LITERALS)
set(CMAKE_REQUIRED_FLAGS )
if (NOT SUPPORTS_USER_DEFINED_LITERALS)
set (SUPPORTS_USER_DEFINED_LITERALS OFF)
endif ()
# Make sure that compiler features detected in the header
# match the features detected in CMake.
@ -74,6 +185,57 @@ if (SUPPORTS_USER_DEFINED_LITERALS)
else ()
set(supports_udl 0)
endif ()
expect_compile("#if FMT_USE_USER_DEFINED_LITERALS != ${supports_udl}
# error
#endif")
expect_compile(udl-check "
#if FMT_USE_USER_DEFINED_LITERALS != ${supports_udl}
# error
#endif
")
if (CMAKE_CXX_STANDARD GREATER_EQUAL 20)
# Compile-time argument type check
expect_compile(format-string-number-spec "
#ifdef FMT_HAS_CONSTEVAL
fmt::format(\"{:d}\", 42);
#endif
")
expect_compile(format-string-number-spec-error "
#ifdef FMT_HAS_CONSTEVAL
fmt::format(\"{:d}\", \"I am not a number\");
#else
#error
#endif
" ERROR)
expect_compile(print-string-number-spec-error "
#ifdef FMT_HAS_CONSTEVAL
fmt::print(\"{:d}\", \"I am not a number\");
#else
#error
#endif
" ERROR)
expect_compile(print-stream-string-number-spec-error "
#ifdef FMT_HAS_CONSTEVAL
fmt::print(std::cout, \"{:d}\", \"I am not a number\");
#else
#error
#endif
" ERROR)
# Compile-time argument name check
expect_compile(format-string-name "
#if defined(FMT_HAS_CONSTEVAL) && FMT_USE_NONTYPE_TEMPLATE_ARGS
using namespace fmt::literals;
fmt::print(\"{foo}\", \"foo\"_a=42);
#endif
")
expect_compile(format-string-name-error "
#if defined(FMT_HAS_CONSTEVAL) && FMT_USE_NONTYPE_TEMPLATE_ARGS
using namespace fmt::literals;
fmt::print(\"{foo}\", \"bar\"_a=42);
#else
#error
#endif
" ERROR)
endif ()
# Run all tests
run_tests()

63
test/compile-fp-test.cc Normal file
View File

@ -0,0 +1,63 @@
// Formatting library for C++ - formatting library tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/compile.h"
#include "gmock/gmock.h"
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806 && \
defined(__cpp_constexpr) && __cpp_constexpr >= 201907 && \
defined(__cpp_constexpr_dynamic_alloc) && \
__cpp_constexpr_dynamic_alloc >= 201907 && FMT_CPLUSPLUS >= 202002L
template <size_t max_string_length, typename Char = char> struct test_string {
template <typename T> constexpr bool operator==(const T& rhs) const noexcept {
return fmt::basic_string_view<Char>(rhs).compare(buffer) == 0;
}
Char buffer[max_string_length]{};
};
template <size_t max_string_length, typename Char = char, typename... Args>
consteval auto test_format(auto format, const Args&... args) {
test_string<max_string_length, Char> string{};
fmt::format_to(string.buffer, format, args...);
return string;
}
TEST(compile_time_formatting_test, floating_point) {
EXPECT_EQ("0", test_format<2>(FMT_COMPILE("{}"), 0.0f));
EXPECT_EQ("392.500000", test_format<11>(FMT_COMPILE("{0:f}"), 392.5f));
EXPECT_EQ("0", test_format<2>(FMT_COMPILE("{:}"), 0.0));
EXPECT_EQ("0.000000", test_format<9>(FMT_COMPILE("{:f}"), 0.0));
EXPECT_EQ("0", test_format<2>(FMT_COMPILE("{:g}"), 0.0));
EXPECT_EQ("392.65", test_format<7>(FMT_COMPILE("{:}"), 392.65));
EXPECT_EQ("392.65", test_format<7>(FMT_COMPILE("{:g}"), 392.65));
EXPECT_EQ("392.65", test_format<7>(FMT_COMPILE("{:G}"), 392.65));
EXPECT_EQ("4.9014e+06", test_format<11>(FMT_COMPILE("{:g}"), 4.9014e6));
EXPECT_EQ("-392.650000", test_format<12>(FMT_COMPILE("{:f}"), -392.65));
EXPECT_EQ("-392.650000", test_format<12>(FMT_COMPILE("{:F}"), -392.65));
EXPECT_EQ("3.926500e+02", test_format<13>(FMT_COMPILE("{0:e}"), 392.65));
EXPECT_EQ("3.926500E+02", test_format<13>(FMT_COMPILE("{0:E}"), 392.65));
EXPECT_EQ("+0000392.6", test_format<11>(FMT_COMPILE("{0:+010.4g}"), 392.65));
EXPECT_EQ("9223372036854775808.000000",
test_format<27>(FMT_COMPILE("{:f}"), 9223372036854775807.0));
constexpr double nan = std::numeric_limits<double>::quiet_NaN();
EXPECT_EQ("nan", test_format<4>(FMT_COMPILE("{}"), nan));
EXPECT_EQ("+nan", test_format<5>(FMT_COMPILE("{:+}"), nan));
if (std::signbit(-nan))
EXPECT_EQ("-nan", test_format<5>(FMT_COMPILE("{}"), -nan));
else
fmt::print("Warning: compiler doesn't handle negative NaN correctly");
constexpr double inf = std::numeric_limits<double>::infinity();
EXPECT_EQ("inf", test_format<4>(FMT_COMPILE("{}"), inf));
EXPECT_EQ("+inf", test_format<5>(FMT_COMPILE("{:+}"), inf));
EXPECT_EQ("-inf", test_format<5>(FMT_COMPILE("{}"), -inf));
}
#endif

View File

@ -5,139 +5,355 @@
//
// For the license information refer to format.h.
#include <stdint.h>
#include <cctype>
#include <cfloat>
#include <climits>
#include <cmath>
#include <cstring>
#include <deque>
#include <list>
#include <memory>
#include <string>
// Check if fmt/compile.h compiles with windows.h included before it.
#ifdef _WIN32
# include <windows.h>
#endif
#include "fmt/compile.h"
#include "gmock.h"
#include <type_traits>
#include "fmt/chrono.h"
#include "gmock/gmock.h"
#include "gtest-extra.h"
#include "mock-allocator.h"
#include "util.h"
#undef ERROR
#undef min
#undef max
using testing::Return;
using testing::StrictMock;
// compiletime_prepared_parts_type_provider is useful only with relaxed
// constexpr.
#if FMT_USE_CONSTEXPR
template <unsigned EXPECTED_PARTS_COUNT, typename Format>
void check_prepared_parts_type(Format format) {
typedef fmt::internal::compiled_format_base<decltype(format)> provider;
typedef fmt::internal::format_part<char>
expected_parts_type[EXPECTED_PARTS_COUNT];
static_assert(std::is_same<typename provider::parts_container,
expected_parts_type>::value,
"CompileTimePreparedPartsTypeProvider test failed");
TEST(iterator_test, counting_iterator) {
auto it = fmt::detail::counting_iterator();
auto prev = it++;
EXPECT_EQ(prev.count(), 0);
EXPECT_EQ(it.count(), 1);
EXPECT_EQ((it + 41).count(), 42);
}
TEST(CompileTest, CompileTimePreparedPartsTypeProvider) {
check_prepared_parts_type<1u>(FMT_STRING("text"));
check_prepared_parts_type<1u>(FMT_STRING("{}"));
check_prepared_parts_type<2u>(FMT_STRING("text{}"));
check_prepared_parts_type<2u>(FMT_STRING("{}text"));
check_prepared_parts_type<3u>(FMT_STRING("text{}text"));
check_prepared_parts_type<3u>(FMT_STRING("{:{}.{}} {:{}}"));
check_prepared_parts_type<3u>(FMT_STRING("{{{}}}")); // '{', 'argument', '}'
check_prepared_parts_type<2u>(FMT_STRING("text{{")); // 'text', '{'
check_prepared_parts_type<3u>(FMT_STRING("text{{ ")); // 'text', '{', ' '
check_prepared_parts_type<2u>(FMT_STRING("}}text")); // '}', text
check_prepared_parts_type<2u>(FMT_STRING("text}}text")); // 'text}', 'text'
check_prepared_parts_type<4u>(
FMT_STRING("text{{}}text")); // 'text', '{', '}', 'text'
}
#endif
TEST(CompileTest, PassStringLiteralFormat) {
const auto prepared = fmt::compile<int>("test {}");
EXPECT_EQ("test 42", fmt::format(prepared, 42));
const auto wprepared = fmt::compile<int>(L"test {}");
EXPECT_EQ(L"test 42", fmt::format(wprepared, 42));
TEST(compile_test, compile_fallback) {
// FMT_COMPILE should fallback on runtime formatting when `if constexpr` is
// not available.
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42));
}
#if FMT_USE_CONSTEXPR
TEST(CompileTest, PassCompileString) {
const auto prepared = fmt::compile<int>(FMT_STRING("test {}"));
EXPECT_EQ("test 42", fmt::format(prepared, 42));
const auto wprepared = fmt::compile<int>(FMT_STRING(L"test {}"));
EXPECT_EQ(L"test 42", fmt::format(wprepared, 42));
}
#endif
TEST(CompileTest, FormatToArrayOfChars) {
char buffer[32] = {0};
const auto prepared = fmt::compile<int>("4{}");
fmt::format_to(fmt::internal::make_checked(buffer, 32), prepared, 2);
EXPECT_EQ(std::string("42"), buffer);
wchar_t wbuffer[32] = {0};
const auto wprepared = fmt::compile<int>(L"4{}");
fmt::format_to(fmt::internal::make_checked(wbuffer, 32), wprepared, 2);
EXPECT_EQ(std::wstring(L"42"), wbuffer);
}
TEST(CompileTest, FormatToIterator) {
std::string s(2, ' ');
const auto prepared = fmt::compile<int>("4{}");
fmt::format_to(s.begin(), prepared, 2);
EXPECT_EQ("42", s);
std::wstring ws(2, L' ');
const auto wprepared = fmt::compile<int>(L"4{}");
fmt::format_to(ws.begin(), wprepared, 2);
EXPECT_EQ(L"42", ws);
}
TEST(CompileTest, FormatToN) {
char buf[5];
auto f = fmt::compile<int>("{:10}");
auto result = fmt::format_to_n(buf, 5, f, 42);
EXPECT_EQ(result.size, 10);
EXPECT_EQ(result.out, buf + 5);
EXPECT_EQ(fmt::string_view(buf, 5), " ");
}
TEST(CompileTest, FormattedSize) {
auto f = fmt::compile<int>("{:10}");
EXPECT_EQ(fmt::formatted_size(f, 42), 10);
}
TEST(CompileTest, MultipleTypes) {
auto f = fmt::compile<int, int>("{} {}");
EXPECT_EQ(fmt::format(f, 42, 42), "42 42");
}
struct formattable {};
struct type_with_get {
template <int> friend void get(type_with_get);
};
FMT_BEGIN_NAMESPACE
template <> struct formatter<formattable> : formatter<const char*> {
auto format(formattable, format_context& ctx) -> decltype(ctx.out()) {
return formatter<const char*>::format("foo", ctx);
template <> struct formatter<type_with_get> : formatter<int> {
template <typename FormatContext>
auto format(type_with_get, FormatContext& ctx) -> decltype(ctx.out()) {
return formatter<int>::format(42, ctx);
}
};
FMT_END_NAMESPACE
TEST(CompileTest, FormatUserDefinedType) {
auto f = fmt::compile<formattable>("{}");
EXPECT_EQ(fmt::format(f, formattable()), "foo");
TEST(compile_test, compile_type_with_get) {
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), type_with_get()));
}
TEST(CompileTest, EmptyFormatString) {
auto f = fmt::compile<>("");
EXPECT_EQ(fmt::format(f), "");
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
struct test_formattable {};
FMT_BEGIN_NAMESPACE
template <> struct formatter<test_formattable> : formatter<const char*> {
char word_spec = 'f';
constexpr auto parse(format_parse_context& ctx) {
auto it = ctx.begin(), end = ctx.end();
if (it == end || *it == '}') return it;
if (it != end && (*it == 'f' || *it == 'b')) word_spec = *it++;
if (it != end && *it != '}') throw format_error("invalid format");
return it;
}
template <typename FormatContext>
constexpr auto format(test_formattable, FormatContext& ctx) const
-> decltype(ctx.out()) {
return formatter<const char*>::format(word_spec == 'f' ? "foo" : "bar",
ctx);
}
};
FMT_END_NAMESPACE
TEST(compile_test, format_default) {
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42));
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42u));
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42ll));
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42ull));
EXPECT_EQ("true", fmt::format(FMT_COMPILE("{}"), true));
EXPECT_EQ("x", fmt::format(FMT_COMPILE("{}"), 'x'));
EXPECT_EQ("4.2", fmt::format(FMT_COMPILE("{}"), 4.2));
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), "foo"));
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), std::string("foo")));
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), test_formattable()));
auto t = std::chrono::system_clock::now();
EXPECT_EQ(fmt::format("{}", t), fmt::format(FMT_COMPILE("{}"), t));
# ifdef __cpp_lib_byte
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), std::byte{42}));
# endif
}
TEST(compile_test, format_wide_string) {
EXPECT_EQ(L"42", fmt::format(FMT_COMPILE(L"{}"), 42));
}
TEST(compile_test, format_specs) {
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42));
EXPECT_EQ("1.2 ms ",
fmt::format(FMT_COMPILE("{:7.1%Q %q}"),
std::chrono::duration<double, std::milli>(1.234)));
}
TEST(compile_test, dynamic_format_specs) {
EXPECT_EQ("foo ", fmt::format(FMT_COMPILE("{:{}}"), "foo", 5));
EXPECT_EQ(" 3.14", fmt::format(FMT_COMPILE("{:{}.{}f}"), 3.141592, 6, 2));
EXPECT_EQ(
"=1.234ms=",
fmt::format(FMT_COMPILE("{:=^{}.{}}"),
std::chrono::duration<double, std::milli>(1.234), 9, 3));
}
TEST(compile_test, manual_ordering) {
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{0}"), 42));
EXPECT_EQ(" -42", fmt::format(FMT_COMPILE("{0:4}"), -42));
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{0} {1}"), 41, 43));
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{1} {0}"), 43, 41));
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{0} {2}"), 41, 42, 43));
EXPECT_EQ(" 41 43", fmt::format(FMT_COMPILE("{1:{2}} {0:4}"), 43, 41, 4));
EXPECT_EQ("42 1.2 ms ",
fmt::format(FMT_COMPILE("{0} {1:7.1%Q %q}"), 42,
std::chrono::duration<double, std::milli>(1.234)));
EXPECT_EQ(
"true 42 42 foo 0x1234 foo",
fmt::format(FMT_COMPILE("{0} {1} {2} {3} {4} {5}"), true, 42, 42.0f,
"foo", reinterpret_cast<void*>(0x1234), test_formattable()));
EXPECT_EQ(L"42", fmt::format(FMT_COMPILE(L"{0}"), 42));
}
TEST(compile_test, named) {
auto runtime_named_field_compiled =
fmt::detail::compile<decltype(fmt::arg("arg", 42))>(FMT_COMPILE("{arg}"));
static_assert(std::is_same_v<decltype(runtime_named_field_compiled),
fmt::detail::runtime_named_field<char>>);
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), fmt::arg("arg", 42)));
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{} {}"), fmt::arg("arg", 41),
fmt::arg("arg", 43)));
EXPECT_EQ("foobar",
fmt::format(FMT_COMPILE("{a0}{a1}"), fmt::arg("a0", "foo"),
fmt::arg("a1", "bar")));
EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{}{a1}"), fmt::arg("a0", "foo"),
fmt::arg("a1", "bar")));
EXPECT_EQ("foofoo", fmt::format(FMT_COMPILE("{a0}{}"), fmt::arg("a0", "foo"),
fmt::arg("a1", "bar")));
EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{0}{a1}"), fmt::arg("a0", "foo"),
fmt::arg("a1", "bar")));
EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{a0}{1}"), fmt::arg("a0", "foo"),
fmt::arg("a1", "bar")));
EXPECT_EQ("foobar",
fmt::format(FMT_COMPILE("{}{a1}"), "foo", fmt::arg("a1", "bar")));
EXPECT_EQ("foobar",
fmt::format(FMT_COMPILE("{a0}{a1}"), fmt::arg("a1", "bar"),
fmt::arg("a2", "baz"), fmt::arg("a0", "foo")));
EXPECT_EQ(" bar foo ",
fmt::format(FMT_COMPILE(" {foo} {bar} "), fmt::arg("foo", "bar"),
fmt::arg("bar", "foo")));
EXPECT_THROW(fmt::format(FMT_COMPILE("{invalid}"), fmt::arg("valid", 42)),
fmt::format_error);
# if FMT_USE_NONTYPE_TEMPLATE_ARGS
using namespace fmt::literals;
auto statically_named_field_compiled =
fmt::detail::compile<decltype("arg"_a = 42)>(FMT_COMPILE("{arg}"));
static_assert(std::is_same_v<decltype(statically_named_field_compiled),
fmt::detail::field<char, int, 0>>);
EXPECT_EQ("41 43",
fmt::format(FMT_COMPILE("{a0} {a1}"), "a0"_a = 41, "a1"_a = 43));
EXPECT_EQ("41 43",
fmt::format(FMT_COMPILE("{a1} {a0}"), "a0"_a = 43, "a1"_a = 41));
# endif
}
TEST(compile_test, join) {
unsigned char data[] = {0x1, 0x2, 0xaf};
EXPECT_EQ("0102af", fmt::format(FMT_COMPILE("{:02x}"), fmt::join(data, "")));
}
TEST(compile_test, format_to) {
char buf[8];
auto end = fmt::format_to(buf, FMT_COMPILE("{}"), 42);
*end = '\0';
EXPECT_STREQ("42", buf);
end = fmt::format_to(buf, FMT_COMPILE("{:x}"), 42);
*end = '\0';
EXPECT_STREQ("2a", buf);
}
TEST(compile_test, format_to_n) {
constexpr auto buffer_size = 8;
char buffer[buffer_size];
auto res = fmt::format_to_n(buffer, buffer_size, FMT_COMPILE("{}"), 42);
*res.out = '\0';
EXPECT_STREQ("42", buffer);
res = fmt::format_to_n(buffer, buffer_size, FMT_COMPILE("{:x}"), 42);
*res.out = '\0';
EXPECT_STREQ("2a", buffer);
}
# ifdef __cpp_lib_bit_cast
TEST(compile_test, constexpr_formatted_size) {
FMT_CONSTEXPR20 size_t size = fmt::formatted_size(FMT_COMPILE("{}"), 42);
EXPECT_EQ(size, 2);
}
# endif
TEST(compile_test, text_and_arg) {
EXPECT_EQ(">>>42<<<", fmt::format(FMT_COMPILE(">>>{}<<<"), 42));
EXPECT_EQ("42!", fmt::format(FMT_COMPILE("{}!"), 42));
}
TEST(compile_test, unknown_format_fallback) {
EXPECT_EQ(" 42 ",
fmt::format(FMT_COMPILE("{name:^4}"), fmt::arg("name", 42)));
std::vector<char> v;
fmt::format_to(std::back_inserter(v), FMT_COMPILE("{name:^4}"),
fmt::arg("name", 42));
EXPECT_EQ(" 42 ", fmt::string_view(v.data(), v.size()));
char buffer[4];
auto result = fmt::format_to_n(buffer, 4, FMT_COMPILE("{name:^5}"),
fmt::arg("name", 42));
EXPECT_EQ(5u, result.size);
EXPECT_EQ(buffer + 4, result.out);
EXPECT_EQ(" 42 ", fmt::string_view(buffer, 4));
}
TEST(compile_test, empty) { EXPECT_EQ("", fmt::format(FMT_COMPILE(""))); }
struct to_stringable {
friend fmt::string_view to_string_view(to_stringable) { return {}; }
};
FMT_BEGIN_NAMESPACE
template <> struct formatter<to_stringable> {
auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const to_stringable&, FormatContext& ctx) -> decltype(ctx.out()) {
return ctx.out();
}
};
FMT_END_NAMESPACE
TEST(compile_test, to_string_and_formatter) {
fmt::format(FMT_COMPILE("{}"), to_stringable());
}
TEST(compile_test, print) {
EXPECT_WRITE(stdout, fmt::print(FMT_COMPILE("Don't {}!"), "panic"),
"Don't panic!");
EXPECT_WRITE(stderr, fmt::print(stderr, FMT_COMPILE("Don't {}!"), "panic"),
"Don't panic!");
}
#endif
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
TEST(compile_test, compile_format_string_literal) {
using namespace fmt::literals;
EXPECT_EQ("", fmt::format(""_cf));
EXPECT_EQ("42", fmt::format("{}"_cf, 42));
EXPECT_EQ(L"42", fmt::format(L"{}"_cf, 42));
}
#endif
// MSVS 2019 19.29.30145.0 - Support C++20 and OK.
// MSVS 2022 19.32.31332.0 - compile-test.cc(362,3): fatal error C1001: Internal
// compiler error.
// (compiler file
// 'D:\a\_work\1\s\src\vctools\Compiler\CxxFE\sl\p1\c\constexpr\constexpr.cpp',
// line 8635)
#if ((FMT_CPLUSPLUS >= 202002L) && \
(!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE > 9) && \
(!FMT_MSC_VERSION || FMT_MSC_VERSION < 1930)) || \
(FMT_CPLUSPLUS >= 201709L && FMT_GCC_VERSION >= 1002)
template <size_t max_string_length, typename Char = char> struct test_string {
template <typename T> constexpr bool operator==(const T& rhs) const noexcept {
return fmt::basic_string_view<Char>(rhs).compare(buffer) == 0;
}
Char buffer[max_string_length]{};
};
template <size_t max_string_length, typename Char = char, typename... Args>
consteval auto test_format(auto format, const Args&... args) {
test_string<max_string_length, Char> string{};
fmt::format_to(string.buffer, format, args...);
return string;
}
TEST(compile_time_formatting_test, bool) {
EXPECT_EQ("true", test_format<5>(FMT_COMPILE("{}"), true));
EXPECT_EQ("false", test_format<6>(FMT_COMPILE("{}"), false));
EXPECT_EQ("true ", test_format<6>(FMT_COMPILE("{:5}"), true));
EXPECT_EQ("1", test_format<2>(FMT_COMPILE("{:d}"), true));
}
TEST(compile_time_formatting_test, integer) {
EXPECT_EQ("42", test_format<3>(FMT_COMPILE("{}"), 42));
EXPECT_EQ("420", test_format<4>(FMT_COMPILE("{}"), 420));
EXPECT_EQ("42 42", test_format<6>(FMT_COMPILE("{} {}"), 42, 42));
EXPECT_EQ("42 42",
test_format<6>(FMT_COMPILE("{} {}"), uint32_t{42}, uint64_t{42}));
EXPECT_EQ("+42", test_format<4>(FMT_COMPILE("{:+}"), 42));
EXPECT_EQ("42", test_format<3>(FMT_COMPILE("{:-}"), 42));
EXPECT_EQ(" 42", test_format<4>(FMT_COMPILE("{: }"), 42));
EXPECT_EQ("-0042", test_format<6>(FMT_COMPILE("{:05}"), -42));
EXPECT_EQ("101010", test_format<7>(FMT_COMPILE("{:b}"), 42));
EXPECT_EQ("0b101010", test_format<9>(FMT_COMPILE("{:#b}"), 42));
EXPECT_EQ("0B101010", test_format<9>(FMT_COMPILE("{:#B}"), 42));
EXPECT_EQ("042", test_format<4>(FMT_COMPILE("{:#o}"), 042));
EXPECT_EQ("0x4a", test_format<5>(FMT_COMPILE("{:#x}"), 0x4a));
EXPECT_EQ("0X4A", test_format<5>(FMT_COMPILE("{:#X}"), 0x4a));
EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42));
EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42ll));
EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42ull));
EXPECT_EQ("42 ", test_format<5>(FMT_COMPILE("{:<4}"), 42));
EXPECT_EQ(" 42", test_format<5>(FMT_COMPILE("{:>4}"), 42));
EXPECT_EQ(" 42 ", test_format<5>(FMT_COMPILE("{:^4}"), 42));
EXPECT_EQ("**-42", test_format<6>(FMT_COMPILE("{:*>5}"), -42));
}
TEST(compile_time_formatting_test, char) {
EXPECT_EQ("c", test_format<2>(FMT_COMPILE("{}"), 'c'));
EXPECT_EQ("c ", test_format<4>(FMT_COMPILE("{:3}"), 'c'));
EXPECT_EQ("99", test_format<3>(FMT_COMPILE("{:d}"), 'c'));
}
TEST(compile_time_formatting_test, string) {
EXPECT_EQ("42", test_format<3>(FMT_COMPILE("{}"), "42"));
EXPECT_EQ("The answer is 42",
test_format<17>(FMT_COMPILE("{} is {}"), "The answer", "42"));
EXPECT_EQ("abc**", test_format<6>(FMT_COMPILE("{:*<5}"), "abc"));
EXPECT_EQ("**🤡**", test_format<9>(FMT_COMPILE("{:*^6}"), "🤡"));
}
TEST(compile_time_formatting_test, combination) {
EXPECT_EQ("420, true, answer",
test_format<18>(FMT_COMPILE("{}, {}, {}"), 420, true, "answer"));
EXPECT_EQ(" -42", test_format<5>(FMT_COMPILE("{:{}}"), -42, 4));
}
TEST(compile_time_formatting_test, custom_type) {
EXPECT_EQ("foo", test_format<4>(FMT_COMPILE("{}"), test_formattable()));
EXPECT_EQ("bar", test_format<4>(FMT_COMPILE("{:b}"), test_formattable()));
}
TEST(compile_time_formatting_test, multibyte_fill) {
EXPECT_EQ("жж42", test_format<8>(FMT_COMPILE("{:ж>4}"), 42));
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,56 +0,0 @@
// 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.
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "fmt/format.h"
#include "gtest-extra.h"
// 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 custom_arg_formatter
: public fmt::arg_formatter<fmt::buffer_range<char>> {
public:
using range = fmt::buffer_range<char>;
typedef fmt::arg_formatter<range> base;
custom_arg_formatter(fmt::format_context& ctx,
fmt::format_parse_context* parse_ctx,
fmt::format_specs* s = nullptr)
: base(ctx, parse_ctx, s) {}
using base::operator();
iterator operator()(double value) {
// Comparing a float to 0.0 is safe.
if (round(value * pow(10, specs()->precision)) == 0.0) value = 0;
return base::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 vwrite.
fmt::vformat_to<custom_arg_formatter>(buffer, format_str, args);
return std::string(buffer.data(), buffer.size());
}
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);
}
TEST(CustomFormatterTest, Format) {
EXPECT_EQ("0.00", custom_format("{:.2f}", -.00001));
}
#endif

18
test/detect-stdfs.cc Normal file
View File

@ -0,0 +1,18 @@
// Formatting library for C++ - tests of formatters for standard library types
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include <exception> // _GLIBCXX_RELEASE & _LIBCPP_VERSION
#if defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8
# error libfound "stdc++fs"
#elif !defined(__apple_build_version__) && defined(_LIBCPP_VERSION) && \
_LIBCPP_VERSION >= 7000 && _LIBCPP_VERSION < 9000
# error libfound "c++fs"
#else
// none if std::filesystem does not require additional libraries
# error libfound ""
#endif

View File

@ -0,0 +1,65 @@
// Formatting library for C++ - formatting library tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include <iterator>
#include <vector>
#define I 42 // simulate https://en.cppreference.com/w/c/numeric/complex/I
#include "fmt/chrono.h"
#include "fmt/color.h"
#include "fmt/format.h"
#include "fmt/ostream.h"
#include "fmt/ranges.h"
#include "fmt/xchar.h"
#undef I
// Exercise the API to verify that everything we expect to can compile.
void test_format_api() {
(void)fmt::format(FMT_STRING("{}"), 42);
(void)fmt::format(FMT_STRING(L"{}"), 42);
(void)fmt::format(FMT_STRING("noop"));
(void)fmt::to_string(42);
(void)fmt::to_wstring(42);
std::vector<char> out;
fmt::format_to(std::back_inserter(out), FMT_STRING("{}"), 42);
char buffer[4];
fmt::format_to_n(buffer, 3, FMT_STRING("{}"), 12345);
wchar_t wbuffer[4];
fmt::format_to_n(wbuffer, 3, FMT_STRING(L"{}"), 12345);
}
void test_chrono() {
(void)fmt::format(FMT_STRING("{}"), std::chrono::seconds(42));
(void)fmt::format(FMT_STRING(L"{}"), std::chrono::seconds(42));
}
void test_text_style() {
fmt::print(fg(fmt::rgb(255, 20, 30)), FMT_STRING("{}"), "rgb(255,20,30)");
(void)fmt::format(fg(fmt::rgb(255, 20, 30)), FMT_STRING("{}"),
"rgb(255,20,30)");
fmt::text_style ts = fg(fmt::rgb(255, 20, 30));
std::string out;
fmt::format_to(std::back_inserter(out), ts,
FMT_STRING("rgb(255,20,30){}{}{}"), 1, 2, 3);
}
void test_range() {
std::vector<char> hello = {'h', 'e', 'l', 'l', 'o'};
(void)fmt::format(FMT_STRING("{}"), hello);
}
int main() {
test_format_api();
test_chrono();
test_text_style();
test_range();
}

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.1.0)
cmake_minimum_required(VERSION 3.8...3.25)
project(fmt-test)

View File

@ -1,6 +1,5 @@
#include "fmt/format.h"
int main(int argc, char** argv) {
for(int i = 0; i < argc; ++i)
fmt::print("{}: {}\n", i, argv[i]);
for (int i = 0; i < argc; ++i) fmt::print("{}: {}\n", i, argv[i]);
}

View File

@ -1,861 +0,0 @@
// Formatting library for C++ - the standard API implementation
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_FORMAT_
#define FMT_FORMAT_
#include <cassert>
#include <variant>
#include "fmt/format.h"
// This implementation verifies the correctness of the standard API proposed in
// P0645 Text Formatting and is optimized for copy-pasting from the paper, not
// for efficiency or readability. An efficient implementation should not use
// std::variant and should store packed argument type tags separately from
// values in basic_format_args for small number of arguments.
namespace std {
template<class T>
constexpr bool Integral = is_integral_v<T>;
template <class O>
using iter_difference_t = ptrdiff_t;
}
// https://fmt.dev/Text%20Formatting.html#format.syn
namespace std {
// [format.error], class format_error
class format_error;
// [format.formatter], formatter
template<class charT> class basic_format_parse_context;
using format_parse_context = basic_format_parse_context<char>;
using wformat_parse_context = basic_format_parse_context<wchar_t>;
template<class Out, class charT> class basic_format_context;
using format_context = basic_format_context<
/* unspecified */ std::back_insert_iterator<fmt::internal::buffer<char>>, char>;
using wformat_context = basic_format_context<
/* unspecified */ std::back_insert_iterator<fmt::internal::buffer<wchar_t>>, wchar_t>;
template<class T, class charT = char> struct formatter {
formatter() = delete;
};
// [format.arguments], arguments
template<class Context> class basic_format_arg;
template<class Visitor, class Context>
/* see below */ auto visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg);
template<class Context, class... Args> struct format_arg_store; // exposition only
template<class Context> class basic_format_args;
using format_args = basic_format_args<format_context>;
using wformat_args = basic_format_args<wformat_context>;
template<class Out, class charT>
using format_args_t = basic_format_args<basic_format_context<Out, charT>>;
template<class Context = format_context, class... Args>
format_arg_store<Context, Args...>
make_format_args(const Args&... args);
template<class... Args>
format_arg_store<wformat_context, Args...>
make_wformat_args(const Args&... args);
// [format.functions], formatting functions
template<class... Args>
string format(string_view fmt, const Args&... args);
template<class... Args>
wstring format(wstring_view fmt, const Args&... args);
string vformat(string_view fmt, format_args args);
wstring vformat(wstring_view fmt, wformat_args args);
template<class Out, class... Args>
Out format_to(Out out, string_view fmt, const Args&... args);
template<class Out, class... Args>
Out format_to(Out out, wstring_view fmt, const Args&... args);
template<class Out>
Out vformat_to(Out out, string_view fmt, format_args_t<Out, char> args);
template<class Out>
Out vformat_to(Out out, wstring_view fmt, format_args_t<Out, wchar_t> args);
template<class Out>
struct format_to_n_result {
Out out;
iter_difference_t<Out> size;
};
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
string_view fmt, const Args&... args);
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
wstring_view fmt, const Args&... args);
template<class... Args>
size_t formatted_size(string_view fmt, const Args&... args);
template<class... Args>
size_t formatted_size(wstring_view fmt, const Args&... args);
}
// https://fmt.dev/Text%20Formatting.html#format.error
namespace std {
class format_error : public runtime_error {
public:
explicit format_error(const string& what_arg) : runtime_error(what_arg) {}
explicit format_error(const char* what_arg) : runtime_error(what_arg) {}
};
}
namespace std {
namespace detail {
struct error_handler {
// This function is intentionally not constexpr to give a compile-time error.
void on_error(const char* message) {
throw std::format_error(message);
}
};
}
}
// https://fmt.dev/Text%20Formatting.html#format.parse_context
namespace std {
template<class charT>
class basic_format_parse_context {
public:
using char_type = charT;
using const_iterator = typename basic_string_view<charT>::const_iterator;
using iterator = const_iterator;
private:
iterator begin_; // exposition only
iterator end_; // exposition only
enum indexing { unknown, manual, automatic }; // exposition only
indexing indexing_; // exposition only
size_t next_arg_id_; // exposition only
size_t num_args_; // exposition only
public:
explicit constexpr basic_format_parse_context(basic_string_view<charT> fmt,
size_t num_args = 0) noexcept;
basic_format_parse_context(const basic_format_parse_context&) = delete;
basic_format_parse_context& operator=(const basic_format_parse_context&) = delete;
constexpr const_iterator begin() const noexcept;
constexpr const_iterator end() const noexcept;
constexpr void advance_to(const_iterator it);
constexpr size_t next_arg_id();
constexpr void check_arg_id(size_t id);
// Implementation detail:
constexpr void check_arg_id(fmt::string_view) {}
detail::error_handler error_handler() const { return {}; }
void on_error(const char* msg) { error_handler().on_error(msg); }
};
}
namespace std {
template<class charT>
/* explicit */ constexpr basic_format_parse_context<charT>::
basic_format_parse_context(basic_string_view<charT> fmt,
size_t num_args) noexcept
: begin_(fmt.begin()), end_(fmt.end()), indexing_(unknown), next_arg_id_(0), num_args_(num_args) {}
template<class charT>
constexpr typename basic_format_parse_context<charT>::const_iterator basic_format_parse_context<charT>::begin() const noexcept { return begin_; }
template<class charT>
constexpr typename basic_format_parse_context<charT>::const_iterator basic_format_parse_context<charT>::end() const noexcept { return end_; }
template<class charT>
constexpr void basic_format_parse_context<charT>::advance_to(typename basic_format_parse_context<charT>::iterator it) { begin_ = it; }
template<class charT>
constexpr size_t basic_format_parse_context<charT>::next_arg_id() {
if (indexing_ == manual)
throw format_error("manual to automatic indexing");
if (indexing_ == unknown)
indexing_ = automatic;
return next_arg_id_++;
}
template<class charT>
constexpr void basic_format_parse_context<charT>::check_arg_id(size_t id) {
// clang doesn't support __builtin_is_constant_evaluated yet
//if (!(!__builtin_is_constant_evaluated() || id < num_args_))
// throw format_error(invalid index is out of range");
if (indexing_ == automatic)
throw format_error("automatic to manual indexing");
if (indexing_ == unknown)
indexing_ = manual;
}
}
// https://fmt.dev/Text%20Formatting.html#format.context
namespace std {
template<class Out, class charT>
class basic_format_context {
basic_format_args<basic_format_context> args_; // exposition only
Out out_; // exposition only
public:
using iterator = Out;
using char_type = charT;
template<class T> using formatter_type = formatter<T, charT>;
basic_format_arg<basic_format_context> arg(size_t id) const;
iterator out();
void advance_to(iterator it);
// Implementation details:
using format_arg = basic_format_arg<basic_format_context>;
basic_format_context(Out out, basic_format_args<basic_format_context> args, fmt::internal::locale_ref)
: args_(args), out_(out) {}
detail::error_handler error_handler() const { return {}; }
basic_format_arg<basic_format_context> arg(fmt::basic_string_view<charT>) const {
return {}; // unused: named arguments are not supported yet
}
void on_error(const char* msg) { error_handler().on_error(msg); }
};
}
namespace std {
template<class O, class charT>
basic_format_arg<basic_format_context<O, charT>> basic_format_context<O, charT>::arg(size_t id) const { return args_.get(id); }
template<class O, class charT>
typename basic_format_context<O, charT>::iterator basic_format_context<O, charT>::out() { return out_; }
template<class O, class charT>
void basic_format_context<O, charT>::advance_to(typename basic_format_context<O, charT>::iterator it) { out_ = it; }
}
namespace std {
namespace detail {
template <typename T>
constexpr bool is_standard_integer_v =
std::is_same_v<T, signed char> ||
std::is_same_v<T, short int> ||
std::is_same_v<T, int> ||
std::is_same_v<T, long int> ||
std::is_same_v<T, long long int>;
template <typename T>
constexpr bool is_standard_unsigned_integer_v =
std::is_same_v<T, unsigned char> ||
std::is_same_v<T, unsigned short int> ||
std::is_same_v<T, unsigned int> ||
std::is_same_v<T, unsigned long int> ||
std::is_same_v<T, unsigned long long int>;
template <typename T, typename Char> struct formatter;
}
}
// https://fmt.dev/Text%20Formatting.html#format.arg
namespace std {
template<class Context>
class basic_format_arg {
public:
class handle;
private:
using char_type = typename Context::char_type; // exposition only
variant<monostate, bool, char_type,
int, unsigned int, long long int, unsigned long long int,
double, long double,
const char_type*, basic_string_view<char_type>,
const void*, handle> value; // exposition only
template<typename T,
typename = enable_if_t<
std::is_same_v<T, bool> ||
std::is_same_v<T, char_type> ||
(std::is_same_v<T, char> && std::is_same_v<char_type, wchar_t>) ||
detail::is_standard_integer_v<T> ||
detail::is_standard_unsigned_integer_v<T> ||
sizeof(typename Context::template formatter_type<T>().format(declval<const T&>(), declval<Context&>())) != 0
>> explicit basic_format_arg(const T& v) noexcept; // exposition only
explicit basic_format_arg(float n) noexcept; // exposition only
explicit basic_format_arg(double n) noexcept; // exposition only
explicit basic_format_arg(long double n) noexcept; // exposition only
explicit basic_format_arg(const char_type* s); // exposition only
template<class traits>
explicit basic_format_arg(
basic_string_view<char_type, traits> s) noexcept; // exposition only
template<class traits, class Allocator>
explicit basic_format_arg(
const basic_string<char_type, traits, Allocator>& s) noexcept; // exposition only
explicit basic_format_arg(nullptr_t) noexcept; // exposition only
template<class T, typename = enable_if_t<is_void_v<T>>>
explicit basic_format_arg(const T* p) noexcept; // exposition only
// Fails due to a bug in clang
//template<class Visitor, class Ctx>
// friend auto visit_format_arg(Visitor&& vis,
// basic_format_arg<Ctx> arg); // exposition only
friend auto get_value(basic_format_arg arg) {
return arg.value;
}
template <typename T, typename Char> friend struct detail::formatter;
template<class Ctx, class... Args>
friend format_arg_store<Ctx, Args...>
make_format_args(const Args&... args); // exposition only
public:
basic_format_arg() noexcept;
explicit operator bool() const noexcept;
};
}
namespace std {
template<class Context>
basic_format_arg<Context>::basic_format_arg() noexcept {}
template<class Context>
template<class T, typename> /* explicit */ basic_format_arg<Context>::basic_format_arg(const T& v) noexcept {
if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, char_type>)
value = v;
else if constexpr (std::is_same_v<T, char> && std::is_same_v<char_type, wchar_t>)
value = static_cast<wchar_t>(v);
else if constexpr (detail::is_standard_integer_v<T> && sizeof(T) <= sizeof(int))
value = static_cast<int>(v);
else if constexpr (detail::is_standard_unsigned_integer_v<T> && sizeof(T) <= sizeof(unsigned))
value = static_cast<unsigned>(v);
else if constexpr (detail::is_standard_integer_v<T>)
value = static_cast<long long int>(v);
else if constexpr (detail::is_standard_unsigned_integer_v<T>)
value = static_cast<unsigned long long int>(v);
else if constexpr (sizeof(typename Context::template formatter_type<T>().format(declval<const T&>(), declval<Context&>())) != 0)
value = handle(v);
}
template<class Context>
/* explicit */ basic_format_arg<Context>::basic_format_arg(float n) noexcept
: value(static_cast<double>(n)) {}
template<class Context>
/* explicit */ basic_format_arg<Context>::basic_format_arg(double n) noexcept
: value(n) {}
template<class Context>
/* explicit */ basic_format_arg<Context>::basic_format_arg(long double n) noexcept
: value(n) {}
template<class Context>
/* explicit */ basic_format_arg<Context>::basic_format_arg(const typename basic_format_arg<Context>::char_type* s)
: value(s) {
assert(s != nullptr);
}
template<class Context>
template<class traits>
/* explicit */ basic_format_arg<Context>::basic_format_arg(basic_string_view<char_type, traits> s) noexcept
: value(s) {}
template<class Context>
template<class traits, class Allocator>
/* explicit */ basic_format_arg<Context>::basic_format_arg(
const basic_string<char_type, traits, Allocator>& s) noexcept
: value(basic_string_view<char_type>(s.data(), s.size())) {}
template<class Context>
/* explicit */ basic_format_arg<Context>::basic_format_arg(nullptr_t) noexcept
: value(static_cast<const void*>(nullptr)) {}
template<class Context>
template<class T, typename> /* explicit */ basic_format_arg<Context>::basic_format_arg(const T* p) noexcept
: value(p) {}
template<class Context>
/* explicit */ basic_format_arg<Context>::operator bool() const noexcept {
return !holds_alternative<monostate>(value);
}
}
namespace std {
template<class Context>
class basic_format_arg<Context>::handle {
const void* ptr_; // exposition only
void (*format_)(basic_format_parse_context<char_type>&,
Context&, const void*); // exposition only
template<class T> explicit handle(const T& val) noexcept; // exposition only
friend class basic_format_arg<Context>; // exposition only
public:
void format(basic_format_parse_context<char_type>&, Context& ctx) const;
};
}
namespace std {
template<class Context>
template<class T> /* explicit */ basic_format_arg<Context>::handle::handle(const T& val) noexcept
: ptr_(&val), format_([](basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx, const void* ptr) {
typename Context::template formatter_type<T> f;
parse_ctx.advance_to(f.parse(parse_ctx));
format_ctx.advance_to(f.format(*static_cast<const T*>(ptr), format_ctx));
}) {}
template<class Context>
void basic_format_arg<Context>::handle::format(basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx) const {
format_(parse_ctx, format_ctx, ptr_);
}
// https://fmt.dev/Text%20Formatting.html#format.visit
template<class Visitor, class Context>
auto visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg) {
return visit(vis, get_value(arg));
}
}
// https://fmt.dev/Text%20Formatting.html#format.store
namespace std {
template<class Context, class... Args>
struct format_arg_store { // exposition only
array<basic_format_arg<Context>, sizeof...(Args)> args;
};
}
// https://fmt.dev/Text%20Formatting.html#format.basic_args
namespace std {
template<class Context>
class basic_format_args {
size_t size_; // exposition only
const basic_format_arg<Context>* data_; // exposition only
public:
basic_format_args() noexcept;
template<class... Args>
basic_format_args(const format_arg_store<Context, Args...>& store) noexcept;
basic_format_arg<Context> get(size_t i) const noexcept;
};
}
namespace std {
template<class Context>
basic_format_args<Context>::basic_format_args() noexcept : size_(0) {}
template<class Context>
template<class... Args>
basic_format_args<Context>::basic_format_args(const format_arg_store<Context, Args...>& store) noexcept
: size_(sizeof...(Args)), data_(store.args.data()) {}
template<class Context>
basic_format_arg<Context> basic_format_args<Context>::get(size_t i) const noexcept {
return i < size_ ? data_[i] : basic_format_arg<Context>();
}
}
namespace std {
// https://fmt.dev/Text%20Formatting.html#format.make_args
template<class Context /*= format_context*/, class... Args>
format_arg_store<Context, Args...> make_format_args(const Args&... args) {
return {basic_format_arg<Context>(args)...};
}
// https://fmt.dev/Text%20Formatting.html#format.make_wargs
template<class... Args>
format_arg_store<wformat_context, Args...> make_wformat_args(const Args&... args) {
return make_format_args<wformat_context>(args...);
}
}
namespace std {
namespace detail {
template <typename Range>
class arg_formatter
: public fmt::internal::arg_formatter_base<Range, error_handler> {
private:
using char_type = typename Range::value_type;
using base = fmt::internal::arg_formatter_base<Range, error_handler>;
using format_context = std::basic_format_context<typename base::iterator, char_type>;
using parse_context = basic_format_parse_context<char_type>;
parse_context* parse_ctx_;
format_context& ctx_;
public:
typedef Range range;
typedef typename base::iterator iterator;
typedef typename base::format_specs format_specs;
/**
\rst
Constructs an argument formatter object.
*ctx* is a reference to the formatting context,
*spec* contains format specifier information for standard argument types.
\endrst
*/
arg_formatter(format_context& ctx, parse_context* parse_ctx = nullptr, fmt::format_specs* spec = nullptr)
: base(Range(ctx.out()), spec, {}), parse_ctx_(parse_ctx), ctx_(ctx) {}
using base::operator();
/** Formats an argument of a user-defined type. */
iterator operator()(typename std::basic_format_arg<format_context>::handle handle) {
handle.format(*parse_ctx_, ctx_);
return this->out();
}
iterator operator()(monostate) {
throw format_error("");
}
};
template <typename Context>
inline fmt::internal::type get_type(basic_format_arg<Context> arg) {
return visit_format_arg([&] (auto val) {
using char_type = typename Context::char_type;
using T = decltype(val);
if (std::is_same_v<T, monostate>)
return fmt::internal::none_type;
if (std::is_same_v<T, bool>)
return fmt::internal::bool_type;
if (std::is_same_v<T, char_type>)
return fmt::internal::char_type;
if (std::is_same_v<T, int>)
return fmt::internal::int_type;
if (std::is_same_v<T, unsigned int>)
return fmt::internal::uint_type;
if (std::is_same_v<T, long long int>)
return fmt::internal::long_long_type;
if (std::is_same_v<T, unsigned long long int>)
return fmt::internal::ulong_long_type;
if (std::is_same_v<T, double>)
return fmt::internal::double_type;
if (std::is_same_v<T, long double>)
return fmt::internal::long_double_type;
if (std::is_same_v<T, const char_type*>)
return fmt::internal::cstring_type;
if (std::is_same_v<T, basic_string_view<char_type>>)
return fmt::internal::string_type;
if (std::is_same_v<T, const void*>)
return fmt::internal::pointer_type;
assert(get_value(arg).index() == 12);
return fmt::internal::custom_type;
}, arg);
}
template <typename Context>
class custom_formatter {
private:
using parse_context = basic_format_parse_context<typename Context::char_type>;
parse_context& parse_ctx_;
Context& format_ctx_;
public:
custom_formatter(parse_context& parse_ctx, Context& ctx) : parse_ctx_(parse_ctx), format_ctx_(ctx) {}
bool operator()(typename basic_format_arg<Context>::handle h) const {
h.format(parse_ctx_, format_ctx_);
return true;
}
template <typename T> bool operator()(T) const { return false; }
};
template <typename ArgFormatter, typename Char, typename Context>
struct format_handler : detail::error_handler {
typedef typename ArgFormatter::range range;
format_handler(range r, basic_string_view<Char> str,
basic_format_args<Context> format_args,
fmt::internal::locale_ref loc)
: parse_ctx(str), context(r.begin(), format_args, loc) {}
void on_text(const Char* begin, const Char* end) {
auto size = fmt::internal::to_unsigned(end - begin);
auto out = context.out();
auto&& it = fmt::internal::reserve(out, size);
it = std::copy_n(begin, size, it);
context.advance_to(out);
}
void on_arg_id() {
arg = context.arg(parse_ctx.next_arg_id());
}
void on_arg_id(unsigned id) {
parse_ctx.check_arg_id(id);
arg = context.arg(id);
}
void on_arg_id(fmt::basic_string_view<Char>) {}
void on_replacement_field(const Char* p) {
parse_ctx.advance_to(parse_ctx.begin() + (p - &*parse_ctx.begin()));
custom_formatter<Context> f(parse_ctx, context);
if (!visit_format_arg(f, arg))
context.advance_to(visit_format_arg(ArgFormatter(context, &parse_ctx), arg));
}
const Char* on_format_specs(const Char* begin, const Char* end) {
parse_ctx.advance_to(parse_ctx.begin() + (begin - &*parse_ctx.begin()));
custom_formatter<Context> f(parse_ctx, context);
if (visit_format_arg(f, arg)) return &*parse_ctx.begin();
fmt::basic_format_specs<Char> specs;
using fmt::internal::specs_handler;
using parse_context = basic_format_parse_context<Char>;
fmt::internal::specs_checker<specs_handler<parse_context, Context>> handler(
specs_handler<parse_context, Context>(specs, parse_ctx, context), get_type(arg));
begin = parse_format_specs(begin, end, handler);
if (begin == end || *begin != '}') on_error("missing '}' in format string");
parse_ctx.advance_to(parse_ctx.begin() + (begin - &*parse_ctx.begin()));
context.advance_to(visit_format_arg(ArgFormatter(context, &parse_ctx, &specs), arg));
return begin;
}
basic_format_parse_context<Char> parse_ctx;
Context context;
basic_format_arg<Context> arg;
};
template <typename T, typename Char>
struct formatter {
// Parses format specifiers stopping either at the end of the range or at the
// terminating '}'.
template <typename ParseContext>
FMT_CONSTEXPR typename ParseContext::iterator parse(ParseContext& ctx) {
namespace internal = fmt::internal;
typedef internal::dynamic_specs_handler<ParseContext> handler_type;
auto type = internal::mapped_type_constant<T, fmt::buffer_context<Char>>::value;
internal::specs_checker<handler_type> handler(handler_type(specs_, ctx),
type);
auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
auto type_spec = specs_.type;
auto eh = ctx.error_handler();
switch (type) {
case internal::none_type:
case internal::named_arg_type:
FMT_ASSERT(false, "invalid argument type");
break;
case internal::int_type:
case internal::uint_type:
case internal::long_long_type:
case internal::ulong_long_type:
case internal::bool_type:
handle_int_type_spec(type_spec,
internal::int_type_checker<decltype(eh)>(eh));
break;
case internal::char_type:
handle_char_specs(
&specs_, internal::char_specs_checker<decltype(eh)>(type_spec, eh));
break;
case internal::double_type:
case internal::long_double_type:
internal::parse_float_type_spec(specs_, eh);
break;
case internal::cstring_type:
internal::handle_cstring_type_spec(
type_spec, internal::cstring_type_checker<decltype(eh)>(eh));
break;
case internal::string_type:
internal::check_string_type_spec(type_spec, eh);
break;
case internal::pointer_type:
internal::check_pointer_type_spec(type_spec, eh);
break;
case internal::custom_type:
// Custom format specifiers should be checked in parse functions of
// formatter specializations.
break;
}
return it;
}
template <typename FormatContext>
auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) {
fmt::internal::handle_dynamic_spec<fmt::internal::width_checker>(
specs_.width, specs_.width_ref, ctx);
fmt::internal::handle_dynamic_spec<fmt::internal::precision_checker>(
specs_.precision, specs_.precision_ref, ctx);
using range_type = fmt::internal::output_range<typename FormatContext::iterator,
typename FormatContext::char_type>;
return visit_format_arg(arg_formatter<range_type>(ctx, nullptr, &specs_),
basic_format_arg<FormatContext>(val));
}
private:
fmt::internal::dynamic_format_specs<Char> specs_;
};
} // namespace detail
// https://fmt.dev/Text%20Formatting.html#format.functions
template<class... Args>
string format(string_view fmt, const Args&... args) {
return vformat(fmt, make_format_args(args...));
}
template<class... Args>
wstring format(wstring_view fmt, const Args&... args) {
return vformat(fmt, make_wformat_args(args...));
}
string vformat(string_view fmt, format_args args) {
fmt::memory_buffer mbuf;
fmt::internal::buffer<char>& buf = mbuf;
using range = fmt::buffer_range<char>;
detail::format_handler<detail::arg_formatter<range>, char, format_context>
h(range(std::back_inserter(buf)), fmt, args, {});
fmt::internal::parse_format_string<false>(fmt::to_string_view(fmt), h);
return to_string(mbuf);
}
wstring vformat(wstring_view fmt, wformat_args args);
template<class Out, class... Args>
Out format_to(Out out, string_view fmt, const Args&... args) {
using context = basic_format_context<Out, decltype(fmt)::value_type>;
return vformat_to(out, fmt, {make_format_args<context>(args...)});
}
template<class Out, class... Args>
Out format_to(Out out, wstring_view fmt, const Args&... args) {
using context = basic_format_context<Out, decltype(fmt)::value_type>;
return vformat_to(out, fmt, {make_format_args<context>(args...)});
}
template<class Out>
Out vformat_to(Out out, string_view fmt, format_args_t<Out, char> args) {
using range = fmt::internal::output_range<Out, char>;
detail::format_handler<detail::arg_formatter<range>, char, basic_format_context<Out, char>>
h(range(out), fmt, args, {});
fmt::internal::parse_format_string<false>(fmt::to_string_view(fmt), h);
return h.context.out();
}
template<class Out>
Out vformat_to(Out out, wstring_view fmt, format_args_t<Out, wchar_t> args);
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
string_view fmt, const Args&... args);
template<class Out, class... Args>
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
wstring_view fmt, const Args&... args);
template<class... Args>
size_t formatted_size(string_view fmt, const Args&... args);
template<class... Args>
size_t formatted_size(wstring_view fmt, const Args&... args);
#define charT char
template<> struct formatter<charT, charT> : detail::formatter<charT, charT> {};
template<> struct formatter<char, wchar_t>;
template<> struct formatter<charT*, charT> : detail::formatter<const charT*, charT> {};
template<> struct formatter<const charT*, charT> : detail::formatter<const charT*, charT> {};
template<size_t N> struct formatter<const charT[N], charT>
: detail::formatter<std::basic_string_view<charT>, charT> {};
template<class traits, class Allocator>
struct formatter<basic_string<charT, traits, Allocator>, charT>
: detail::formatter<std::basic_string_view<charT>, charT> {};
template<class traits>
struct formatter<basic_string_view<charT, traits>, charT>
: detail::formatter<std::basic_string_view<charT>, charT> {};
template <> struct formatter<nullptr_t, charT> : detail::formatter<const void*, charT> {};
template <> struct formatter<void*, charT> : detail::formatter<const void*, charT> {};
template <> struct formatter<const void*, charT> : detail::formatter<const void*, charT> {};
template <> struct formatter<bool, charT> : detail::formatter<bool, charT> {};
template <> struct formatter<signed char, charT> : detail::formatter<int, charT> {};
template <> struct formatter<short, charT> : detail::formatter<int, charT> {};
template <> struct formatter<int, charT> : detail::formatter<int, charT> {};
template <> struct formatter<long, charT>
: detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), int, long long>, charT> {};
template <> struct formatter<long long, charT> : detail::formatter<long long, charT> {};
template <> struct formatter<unsigned char, charT> : detail::formatter<unsigned int, charT> {};
template <> struct formatter<unsigned short, charT> : detail::formatter<unsigned int, charT> {};
template <> struct formatter<unsigned int, charT> : detail::formatter<unsigned int, charT> {};
template <> struct formatter<unsigned long, charT>
: detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), unsigned, unsigned long long>, charT> {};
template <> struct formatter<unsigned long long, charT> : detail::formatter<unsigned long long, charT> {};
template <> struct formatter<float, charT> : detail::formatter<double, charT> {};
template <> struct formatter<double, charT> : detail::formatter<double, charT> {};
template <> struct formatter<long double, charT> : detail::formatter<long double, charT> {};
#undef charT
#define charT wchar_t
template<> struct formatter<charT, charT> : detail::formatter<charT, charT> {};
template<> struct formatter<char, wchar_t> : detail::formatter<charT, charT> {};
template<> struct formatter<charT*, charT> : detail::formatter<const charT*, charT> {};
template<> struct formatter<const charT*, charT> : detail::formatter<const charT*, charT> {};
template<size_t N> struct formatter<const charT[N], charT>
: detail::formatter<std::basic_string_view<charT>, charT> {};
template<class traits, class Allocator>
struct formatter<std::basic_string<charT, traits, Allocator>, charT>
: detail::formatter<std::basic_string_view<charT>, charT> {};
template<class traits>
struct formatter<std::basic_string_view<charT, traits>, charT>
: detail::formatter<std::basic_string_view<charT>, charT> {};
template <> struct formatter<nullptr_t, charT> : detail::formatter<const void*, charT> {};
template <> struct formatter<void*, charT> : detail::formatter<const void*, charT> {};
template <> struct formatter<const void*, charT> : detail::formatter<const void*, charT> {};
template <> struct formatter<bool, charT> : detail::formatter<bool, charT> {};
template <> struct formatter<signed char, charT> : detail::formatter<int, charT> {};
template <> struct formatter<short, charT> : detail::formatter<int, charT> {};
template <> struct formatter<int, charT> : detail::formatter<int, charT> {};
template <> struct formatter<long, charT>
: detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), int, long long>, charT> {};
template <> struct formatter<long long, charT> : detail::formatter<long long, charT> {};
template <> struct formatter<unsigned char, charT> : detail::formatter<unsigned int, charT> {};
template <> struct formatter<unsigned short, charT> : detail::formatter<unsigned int, charT> {};
template <> struct formatter<unsigned int, charT> : detail::formatter<unsigned int, charT> {};
template <> struct formatter<unsigned long, charT>
: detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), unsigned, unsigned long long>, charT> {};
template <> struct formatter<unsigned long long, charT> : detail::formatter<unsigned long long, charT> {};
template <> struct formatter<float, charT> : detail::formatter<double, charT> {};
template <> struct formatter<double, charT> : detail::formatter<double, charT> {};
template <> struct formatter<long double, charT> : detail::formatter<long double, charT> {};
#undef charT
template<> struct formatter<const wchar_t, char> {
formatter() = delete;
};
}
#endif // FMT_FORMAT_

View File

@ -5,37 +5,31 @@
//
// For the license information refer to format.h.
#define FMT_NOEXCEPT
#undef FMT_SHARED
#include "test-assert.h"
// Include format.cc instead of format.h to test implementation.
#include "../src/format.cc"
#include "fmt/printf.h"
#include <algorithm>
#include <cstring>
#include "gmock.h"
#include "gtest-extra.h"
// clang-format off
#include "test-assert.h"
// clang-format on
#include "fmt/format.h"
#include "gmock/gmock.h"
#include "util.h"
#undef max
using fmt::internal::bigint;
using fmt::internal::fp;
using fmt::internal::max_value;
using fmt::detail::bigint;
using fmt::detail::fp;
using fmt::detail::max_value;
static_assert(!std::is_copy_constructible<bigint>::value, "");
static_assert(!std::is_copy_assignable<bigint>::value, "");
TEST(BigIntTest, Construct) {
EXPECT_EQ("", fmt::format("{}", bigint()));
EXPECT_EQ("42", fmt::format("{}", bigint(0x42)));
EXPECT_EQ("123456789abcedf0", fmt::format("{}", bigint(0x123456789abcedf0)));
TEST(bigint_test, construct) {
EXPECT_EQ(fmt::to_string(bigint()), "");
EXPECT_EQ(fmt::to_string(bigint(0x42)), "42");
EXPECT_EQ(fmt::to_string(bigint(0x123456789abcedf0)), "123456789abcedf0");
}
TEST(BigIntTest, Compare) {
TEST(bigint_test, compare) {
bigint n1(42);
bigint n2(42);
EXPECT_EQ(compare(n1, n2), 0);
@ -49,7 +43,7 @@ TEST(BigIntTest, Compare) {
EXPECT_GT(compare(n4, n2), 0);
}
TEST(BigIntTest, AddCompare) {
TEST(bigint_test, add_compare) {
EXPECT_LT(
add_compare(bigint(0xffffffff), bigint(0xffffffff), bigint(1) <<= 64), 0);
EXPECT_LT(add_compare(bigint(1) <<= 32, bigint(1), bigint(1) <<= 96), 0);
@ -75,80 +69,73 @@ TEST(BigIntTest, AddCompare) {
0);
}
TEST(BigIntTest, ShiftLeft) {
TEST(bigint_test, shift_left) {
bigint n(0x42);
n <<= 0;
EXPECT_EQ("42", fmt::format("{}", n));
EXPECT_EQ(fmt::to_string(n), "42");
n <<= 1;
EXPECT_EQ("84", fmt::format("{}", n));
EXPECT_EQ(fmt::to_string(n), "84");
n <<= 25;
EXPECT_EQ("108000000", fmt::format("{}", n));
EXPECT_EQ(fmt::to_string(n), "108000000");
}
TEST(BigIntTest, Multiply) {
TEST(bigint_test, multiply) {
bigint n(0x42);
EXPECT_THROW(n *= 0, assertion_failure);
n *= 1;
EXPECT_EQ("42", fmt::format("{}", n));
EXPECT_EQ(fmt::to_string(n), "42");
n *= 2;
EXPECT_EQ("84", fmt::format("{}", n));
EXPECT_EQ(fmt::to_string(n), "84");
n *= 0x12345678;
EXPECT_EQ("962fc95e0", fmt::format("{}", n));
EXPECT_EQ(fmt::to_string(n), "962fc95e0");
bigint bigmax(max_value<uint32_t>());
bigmax *= max_value<uint32_t>();
EXPECT_EQ("fffffffe00000001", fmt::format("{}", bigmax));
bigmax.assign(max_value<uint64_t>());
bigmax *= max_value<uint64_t>();
EXPECT_EQ("fffffffffffffffe0000000000000001", fmt::format("{}", bigmax));
EXPECT_EQ(fmt::to_string(bigmax), "fffffffe00000001");
const auto max64 = max_value<uint64_t>();
bigmax = max64;
bigmax *= max64;
EXPECT_EQ(fmt::to_string(bigmax), "fffffffffffffffe0000000000000001");
const auto max128 = (fmt::detail::uint128_t(max64) << 64) | max64;
bigmax = max128;
bigmax *= max128;
EXPECT_EQ(fmt::to_string(bigmax),
"fffffffffffffffffffffffffffffffe00000000000000000000000000000001");
}
TEST(BigIntTest, Accumulator) {
fmt::internal::accumulator acc;
EXPECT_EQ(acc.lower, 0);
EXPECT_EQ(acc.upper, 0);
acc.upper = 12;
acc.lower = 34;
EXPECT_EQ(static_cast<uint32_t>(acc), 34);
acc += 56;
EXPECT_EQ(acc.lower, 90);
acc += fmt::internal::max_value<uint64_t>();
EXPECT_EQ(acc.upper, 13);
EXPECT_EQ(acc.lower, 89);
acc >>= 32;
EXPECT_EQ(acc.upper, 0);
EXPECT_EQ(acc.lower, 13 * 0x100000000);
}
TEST(BigIntTest, Square) {
TEST(bigint_test, square) {
bigint n0(0);
n0.square();
EXPECT_EQ("0", fmt::format("{}", n0));
EXPECT_EQ(fmt::to_string(n0), "0");
bigint n1(0x100);
n1.square();
EXPECT_EQ("10000", fmt::format("{}", n1));
EXPECT_EQ(fmt::to_string(n1), "10000");
bigint n2(0xfffffffff);
n2.square();
EXPECT_EQ("ffffffffe000000001", fmt::format("{}", n2));
EXPECT_EQ(fmt::to_string(n2), "ffffffffe000000001");
bigint n3(max_value<uint64_t>());
n3.square();
EXPECT_EQ("fffffffffffffffe0000000000000001", fmt::format("{}", n3));
EXPECT_EQ(fmt::to_string(n3), "fffffffffffffffe0000000000000001");
bigint n4;
n4.assign_pow10(10);
EXPECT_EQ("2540be400", fmt::format("{}", n4));
EXPECT_EQ(fmt::to_string(n4), "2540be400");
}
TEST(BigIntTest, DivModAssignZeroDivisor) {
TEST(bigint_test, divmod_assign_zero_divisor) {
bigint zero(0);
EXPECT_THROW(bigint(0).divmod_assign(zero), assertion_failure);
EXPECT_THROW(bigint(42).divmod_assign(zero), assertion_failure);
}
TEST(BigIntTest, DivModAssignSelf) {
TEST(bigint_test, divmod_assign_self) {
bigint n(100);
EXPECT_THROW(n.divmod_assign(n), assertion_failure);
}
TEST(BigIntTest, DivModAssignUnaligned) {
TEST(bigint_test, divmod_assign_unaligned) {
// (42 << 340) / pow(10, 100):
bigint n1(42);
n1 <<= 340;
@ -156,28 +143,28 @@ TEST(BigIntTest, DivModAssignUnaligned) {
n2.assign_pow10(100);
int result = n1.divmod_assign(n2);
EXPECT_EQ(result, 9406);
EXPECT_EQ("10f8353019583bfc29ffc8f564e1b9f9d819dbb4cf783e4507eca1539220p96",
fmt::format("{}", n1));
EXPECT_EQ(fmt::to_string(n1),
"10f8353019583bfc29ffc8f564e1b9f9d819dbb4cf783e4507eca1539220p96");
}
TEST(BigIntTest, DivModAssign) {
TEST(bigint_test, divmod_assign) {
// 100 / 10:
bigint n1(100);
int result = n1.divmod_assign(bigint(10));
EXPECT_EQ(result, 10);
EXPECT_EQ("0", fmt::format("{}", n1));
EXPECT_EQ(fmt::to_string(n1), "0");
// pow(10, 100) / (42 << 320):
n1.assign_pow10(100);
result = n1.divmod_assign(bigint(42) <<= 320);
EXPECT_EQ(result, 111);
EXPECT_EQ("13ad2594c37ceb0b2784c4ce0bf38ace408e211a7caab24308a82e8f10p96",
fmt::format("{}", n1));
EXPECT_EQ(fmt::to_string(n1),
"13ad2594c37ceb0b2784c4ce0bf38ace408e211a7caab24308a82e8f10p96");
// 42 / 100:
bigint n2(42);
n1.assign_pow10(2);
result = n2.divmod_assign(n1);
EXPECT_EQ(result, 0);
EXPECT_EQ("2a", fmt::format("{}", n2));
EXPECT_EQ(fmt::to_string(n2), "2a");
}
template <bool is_iec559> void run_double_tests() {
@ -187,70 +174,20 @@ template <bool is_iec559> void run_double_tests() {
template <> void run_double_tests<true>() {
// Construct from double.
EXPECT_EQ(fp(1.23), fp(0x13ae147ae147aeu, -52));
// Compute boundaries:
fp value;
// Normalized & not power of 2 - equidistant boundaries:
auto b = value.assign_with_boundaries(1.23);
EXPECT_EQ(value, fp(0x0013ae147ae147ae, -52));
EXPECT_EQ(b.lower, 0x9d70a3d70a3d6c00);
EXPECT_EQ(b.upper, 0x9d70a3d70a3d7400);
// Normalized power of 2 - lower boundary is closer:
b = value.assign_with_boundaries(1.9807040628566084e+28); // 2**94
EXPECT_EQ(value, fp(0x0010000000000000, 42));
EXPECT_EQ(b.lower, 0x7ffffffffffffe00);
EXPECT_EQ(b.upper, 0x8000000000000400);
// Smallest normalized double - equidistant boundaries:
b = value.assign_with_boundaries(2.2250738585072014e-308);
EXPECT_EQ(value, fp(0x0010000000000000, -1074));
EXPECT_EQ(b.lower, 0x7ffffffffffffc00);
EXPECT_EQ(b.upper, 0x8000000000000400);
// Subnormal - equidistant boundaries:
b = value.assign_with_boundaries(4.9406564584124654e-324);
EXPECT_EQ(value, fp(0x0000000000000001, -1074));
EXPECT_EQ(b.lower, 0x4000000000000000);
EXPECT_EQ(b.upper, 0xc000000000000000);
}
TEST(FPTest, DoubleTests) {
TEST(fp_test, double_tests) {
run_double_tests<std::numeric_limits<double>::is_iec559>();
}
TEST(FPTest, Normalize) {
TEST(fp_test, normalize) {
const auto v = fp(0xbeef, 42);
auto normalized = normalize(v);
EXPECT_EQ(0xbeef000000000000, normalized.f);
EXPECT_EQ(-6, normalized.e);
EXPECT_EQ(normalized.f, 0xbeef000000000000);
EXPECT_EQ(normalized.e, -6);
}
TEST(FPTest, ComputeFloatBoundaries) {
struct {
double x, lower, upper;
} tests[] = {
// regular
{1.5f, 1.4999999403953552, 1.5000000596046448},
// boundary
{1.0f, 0.9999999701976776, 1.0000000596046448},
// min normal
{1.1754944e-38f, 1.1754942807573643e-38, 1.1754944208872107e-38},
// max subnormal
{1.1754942e-38f, 1.1754941406275179e-38, 1.1754942807573643e-38},
// min subnormal
{1e-45f, 7.006492321624085e-46, 2.1019476964872256e-45},
};
for (auto test : tests) {
fp vlower = normalize(fp(test.lower));
fp vupper = normalize(fp(test.upper));
vlower.f >>= vupper.e - vlower.e;
vlower.e = vupper.e;
fp value;
auto b = value.assign_float_with_boundaries(test.x);
EXPECT_EQ(vlower.f, b.lower);
EXPECT_EQ(vupper.f, b.upper);
}
}
TEST(FPTest, Multiply) {
TEST(fp_test, multiply) {
auto v = fp(123ULL << 32, 4) * fp(56ULL << 32, 7);
EXPECT_EQ(v.f, 123u * 56u);
EXPECT_EQ(v.e, 4 + 7 + 64);
@ -259,196 +196,288 @@ TEST(FPTest, Multiply) {
EXPECT_EQ(v.e, 4 + 8 + 64);
}
TEST(FPTest, GetCachedPower) {
typedef std::numeric_limits<double> limits;
for (auto exp = limits::min_exponent; exp <= limits::max_exponent; ++exp) {
int dec_exp = 0;
auto fp = fmt::internal::get_cached_power(exp, dec_exp);
EXPECT_LE(exp, fp.e);
int dec_exp_step = 8;
EXPECT_LE(fp.e, exp + dec_exp_step * log2(10));
EXPECT_DOUBLE_EQ(pow(10, dec_exp), ldexp(static_cast<double>(fp.f), fp.e));
}
TEST(fp_test, dragonbox_max_k) {
using fmt::detail::dragonbox::floor_log10_pow2;
using float_info = fmt::detail::dragonbox::float_info<float>;
EXPECT_EQ(
fmt::detail::const_check(float_info::max_k),
float_info::kappa -
floor_log10_pow2(std::numeric_limits<float>::min_exponent -
fmt::detail::num_significand_bits<float>() - 1));
using double_info = fmt::detail::dragonbox::float_info<double>;
EXPECT_EQ(fmt::detail::const_check(double_info::max_k),
double_info::kappa -
floor_log10_pow2(
std::numeric_limits<double>::min_exponent -
2 * fmt::detail::num_significand_bits<double>() - 1));
}
TEST(FPTest, GetRoundDirection) {
using fmt::internal::get_round_direction;
EXPECT_EQ(fmt::internal::down, get_round_direction(100, 50, 0));
EXPECT_EQ(fmt::internal::up, get_round_direction(100, 51, 0));
EXPECT_EQ(fmt::internal::down, get_round_direction(100, 40, 10));
EXPECT_EQ(fmt::internal::up, get_round_direction(100, 60, 10));
for (int i = 41; i < 60; ++i)
EXPECT_EQ(fmt::internal::unknown, get_round_direction(100, i, 10));
uint64_t max = max_value<uint64_t>();
EXPECT_THROW(get_round_direction(100, 100, 0), assertion_failure);
EXPECT_THROW(get_round_direction(100, 0, 100), assertion_failure);
EXPECT_THROW(get_round_direction(100, 0, 50), assertion_failure);
// Check that remainder + error doesn't overflow.
EXPECT_EQ(fmt::internal::up, get_round_direction(max, max - 1, 2));
// Check that 2 * (remainder + error) doesn't overflow.
EXPECT_EQ(fmt::internal::unknown,
get_round_direction(max, max / 2 + 1, max / 2));
// Check that remainder - error doesn't overflow.
EXPECT_EQ(fmt::internal::unknown, get_round_direction(100, 40, 41));
// Check that 2 * (remainder - error) doesn't overflow.
EXPECT_EQ(fmt::internal::up, get_round_direction(max, max - 1, 1));
}
TEST(FPTest, FixedHandler) {
struct handler : fmt::internal::fixed_handler {
char buffer[10];
handler(int prec = 0) : fmt::internal::fixed_handler() {
buf = buffer;
precision = prec;
}
};
int exp = 0;
handler().on_digit('0', 100, 99, 0, exp, false);
EXPECT_THROW(handler().on_digit('0', 100, 100, 0, exp, false),
assertion_failure);
namespace digits = fmt::internal::digits;
EXPECT_EQ(handler(1).on_digit('0', 100, 10, 10, exp, false), digits::done);
// Check that divisor - error doesn't overflow.
EXPECT_EQ(handler(1).on_digit('0', 100, 10, 101, exp, false), digits::error);
// Check that 2 * error doesn't overflow.
uint64_t max = max_value<uint64_t>();
EXPECT_EQ(handler(1).on_digit('0', max, 10, max - 1, exp, false),
digits::error);
}
TEST(FPTest, GrisuFormatCompilesWithNonIEEEDouble) {
fmt::memory_buffer buf;
format_float(0.42, -1, fmt::internal::float_specs(), buf);
}
template <typename T> struct value_extractor {
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()));
}
#ifdef __apple_build_version__
// Apple Clang does not define typeid for __int128_t and __uint128_t.
FMT_NORETURN T operator()(__int128_t) {
throw std::runtime_error(fmt::format("invalid type {}", "__int128_t"));
}
FMT_NORETURN T operator()(__uint128_t) {
throw std::runtime_error(fmt::format("invalid type {}", "__uint128_t"));
}
#endif
};
TEST(FormatTest, ArgConverter) {
long long value = max_value<long long>();
auto arg = fmt::internal::make_arg<fmt::format_context>(value);
fmt::visit_format_arg(
fmt::internal::arg_converter<long long, fmt::format_context>(arg, 'd'),
arg);
EXPECT_EQ(value, fmt::visit_format_arg(value_extractor<long long>(), arg));
}
TEST(FormatTest, FormatNegativeNaN) {
double nan = std::numeric_limits<double>::quiet_NaN();
if (std::signbit(-nan))
EXPECT_EQ("-nan", fmt::format("{}", -nan));
else
fmt::print("Warning: compiler doesn't handle negative NaN correctly");
}
TEST(FormatTest, StrError) {
char* message = nullptr;
char buffer[BUFFER_SIZE];
EXPECT_ASSERT(fmt::internal::safe_strerror(EDOM, message = nullptr, 0),
"invalid buffer");
EXPECT_ASSERT(fmt::internal::safe_strerror(EDOM, message = buffer, 0),
"invalid buffer");
buffer[0] = 'x';
#if defined(_GNU_SOURCE) && !defined(__COVERITY__)
// Use invalid error code to make sure that safe_strerror returns an error
// message in the buffer rather than a pointer to a static string.
int error_code = -1;
#else
int error_code = EDOM;
#endif
int result =
fmt::internal::safe_strerror(error_code, message = buffer, BUFFER_SIZE);
EXPECT_EQ(result, 0);
std::size_t message_size = std::strlen(message);
EXPECT_GE(BUFFER_SIZE - 1u, message_size);
EXPECT_EQ(get_system_error(error_code), message);
// safe_strerror never uses buffer on MinGW.
#if !defined(__MINGW32__) && !defined(__sun)
result =
fmt::internal::safe_strerror(error_code, message = buffer, message_size);
EXPECT_EQ(ERANGE, result);
result = fmt::internal::safe_strerror(error_code, message = buffer, 1);
EXPECT_EQ(buffer, message); // Message should point to buffer.
EXPECT_EQ(ERANGE, result);
EXPECT_STREQ("", message);
#endif
}
TEST(FormatTest, FormatErrorCode) {
TEST(format_impl_test, format_error_code) {
std::string msg = "error 42", sep = ": ";
{
fmt::memory_buffer buffer;
format_to(buffer, "garbage");
fmt::internal::format_error_code(buffer, 42, "test");
EXPECT_EQ("test: " + msg, to_string(buffer));
auto buffer = fmt::memory_buffer();
fmt::format_to(fmt::appender(buffer), "garbage");
fmt::detail::format_error_code(buffer, 42, "test");
EXPECT_EQ(to_string(buffer), "test: " + msg);
}
{
fmt::memory_buffer buffer;
std::string prefix(fmt::inline_buffer_size - msg.size() - sep.size() + 1,
'x');
fmt::internal::format_error_code(buffer, 42, prefix);
auto buffer = fmt::memory_buffer();
auto prefix =
std::string(fmt::inline_buffer_size - msg.size() - sep.size() + 1, 'x');
fmt::detail::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) {
for (size_t i = 0, n = sizeof(codes) / sizeof(*codes); i < n; ++i) {
// Test maximum buffer size.
msg = fmt::format("error {}", codes[i]);
fmt::memory_buffer buffer;
std::string prefix(fmt::inline_buffer_size - msg.size() - sep.size(), 'x');
fmt::internal::format_error_code(buffer, codes[i], prefix);
auto prefix =
std::string(fmt::inline_buffer_size - msg.size() - sep.size(), 'x');
fmt::detail::format_error_code(buffer, codes[i], prefix);
EXPECT_EQ(prefix + sep + msg, to_string(buffer));
std::size_t size = fmt::inline_buffer_size;
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::internal::format_error_code(buffer, codes[i], prefix);
EXPECT_EQ(msg, to_string(buffer));
fmt::detail::format_error_code(buffer, codes[i], prefix);
EXPECT_EQ(to_string(buffer), msg);
}
}
TEST(FormatTest, CountCodePoints) {
EXPECT_EQ(4, fmt::internal::count_code_points(fmt::u8string_view("ёжик")));
TEST(format_impl_test, compute_width) {
EXPECT_EQ(4,
fmt::detail::compute_width(
fmt::basic_string_view<fmt::detail::char8_type>(
reinterpret_cast<const fmt::detail::char8_type*>("ёжик"))));
}
// Tests fmt::internal::count_digits for integer type Int.
// Tests fmt::detail::count_digits for integer type Int.
template <typename Int> void test_count_digits() {
for (Int i = 0; i < 10; ++i) EXPECT_EQ(1u, fmt::internal::count_digits(i));
for (Int i = 0; i < 10; ++i) EXPECT_EQ(1u, fmt::detail::count_digits(i));
for (Int i = 1, n = 1, end = max_value<Int>() / 10; n <= end; ++i) {
n *= 10;
EXPECT_EQ(i, fmt::internal::count_digits(n - 1));
EXPECT_EQ(i + 1, fmt::internal::count_digits(n));
EXPECT_EQ(fmt::detail::count_digits(n - 1), i);
EXPECT_EQ(fmt::detail::count_digits(n), i + 1);
}
}
TEST(UtilTest, CountDigits) {
TEST(format_impl_test, count_digits) {
test_count_digits<uint32_t>();
test_count_digits<uint64_t>();
}
TEST(UtilTest, WriteUIntPtr) {
fmt::memory_buffer buf;
fmt::internal::writer writer(buf);
writer.write_pointer(fmt::internal::fallback_uintptr(
reinterpret_cast<void*>(0xface)),
nullptr);
EXPECT_EQ("0xface", to_string(buf));
TEST(format_impl_test, countl_zero) {
constexpr auto num_bits = fmt::detail::num_bits<uint32_t>();
uint32_t n = 1u;
for (int i = 1; i < num_bits - 1; i++) {
n <<= 1;
EXPECT_EQ(fmt::detail::countl_zero(n - 1), num_bits - i);
EXPECT_EQ(fmt::detail::countl_zero(n), num_bits - i - 1);
}
}
#if FMT_USE_FLOAT128
TEST(format_impl_test, write_float128) {
auto s = std::string();
fmt::detail::write<char>(std::back_inserter(s), __float128(42));
EXPECT_EQ(s, "42");
}
#endif
struct double_double {
double a;
double b;
explicit constexpr double_double(double a_val = 0, double b_val = 0)
: a(a_val), b(b_val) {}
operator double() const { return a + b; }
auto operator-() const -> double_double { return double_double(-a, -b); }
};
auto format_as(double_double d) -> double { return d; }
bool operator>=(const double_double& lhs, const double_double& rhs) {
return lhs.a + lhs.b >= rhs.a + rhs.b;
}
struct slow_float {
float value;
explicit constexpr slow_float(float val = 0) : value(val) {}
operator float() const { return value; }
auto operator-() const -> slow_float { return slow_float(-value); }
};
auto format_as(slow_float f) -> float { return f; }
namespace std {
template <> struct is_floating_point<double_double> : std::true_type {};
template <> struct numeric_limits<double_double> {
// is_iec559 is true for double-double in libstdc++.
static constexpr bool is_iec559 = true;
static constexpr int digits = 106;
};
template <> struct is_floating_point<slow_float> : std::true_type {};
template <> struct numeric_limits<slow_float> : numeric_limits<float> {};
} // namespace std
FMT_BEGIN_NAMESPACE
namespace detail {
template <> struct is_fast_float<slow_float> : std::false_type {};
namespace dragonbox {
template <> struct float_info<slow_float> {
using carrier_uint = uint32_t;
static const int exponent_bits = 8;
};
} // namespace dragonbox
} // namespace detail
FMT_END_NAMESPACE
TEST(format_impl_test, write_double_double) {
auto s = std::string();
fmt::detail::write<char>(std::back_inserter(s), double_double(42), {});
// Specializing is_floating_point is broken in MSVC.
if (!FMT_MSC_VERSION) EXPECT_EQ(s, "42");
}
TEST(format_impl_test, write_dragon_even) {
auto s = std::string();
fmt::detail::write<char>(std::back_inserter(s), slow_float(33554450.0f), {});
// Specializing is_floating_point is broken in MSVC.
if (!FMT_MSC_VERSION) EXPECT_EQ(s, "33554450");
}
#ifdef _WIN32
# include <windows.h>
TEST(format_impl_test, write_console_signature) {
decltype(::WriteConsoleW)* p = fmt::detail::WriteConsoleW;
(void)p;
}
#endif
// A public domain branchless UTF-8 decoder by Christopher Wellons:
// https://github.com/skeeto/branchless-utf8
constexpr bool unicode_is_surrogate(uint32_t c) {
return c >= 0xD800U && c <= 0xDFFFU;
}
FMT_CONSTEXPR char* utf8_encode(char* s, uint32_t c) {
if (c >= (1UL << 16)) {
s[0] = static_cast<char>(0xf0 | (c >> 18));
s[1] = static_cast<char>(0x80 | ((c >> 12) & 0x3f));
s[2] = static_cast<char>(0x80 | ((c >> 6) & 0x3f));
s[3] = static_cast<char>(0x80 | ((c >> 0) & 0x3f));
return s + 4;
} else if (c >= (1UL << 11)) {
s[0] = static_cast<char>(0xe0 | (c >> 12));
s[1] = static_cast<char>(0x80 | ((c >> 6) & 0x3f));
s[2] = static_cast<char>(0x80 | ((c >> 0) & 0x3f));
return s + 3;
} else if (c >= (1UL << 7)) {
s[0] = static_cast<char>(0xc0 | (c >> 6));
s[1] = static_cast<char>(0x80 | ((c >> 0) & 0x3f));
return s + 2;
} else {
s[0] = static_cast<char>(c);
return s + 1;
}
}
// Make sure it can decode every character
TEST(format_impl_test, utf8_decode_decode_all) {
for (uint32_t i = 0; i < 0x10ffff; i++) {
if (!unicode_is_surrogate(i)) {
int e;
uint32_t c;
char buf[8] = {0};
char* end = utf8_encode(buf, i);
const char* res = fmt::detail::utf8_decode(buf, &c, &e);
EXPECT_EQ(end, res);
EXPECT_EQ(c, i);
EXPECT_EQ(e, 0);
}
}
}
// Reject everything outside of U+0000..U+10FFFF
TEST(format_impl_test, utf8_decode_out_of_range) {
for (uint32_t i = 0x110000; i < 0x1fffff; i++) {
int e;
uint32_t c;
char buf[8] = {0};
utf8_encode(buf, i);
const char* end = fmt::detail::utf8_decode(buf, &c, &e);
EXPECT_NE(e, 0);
EXPECT_EQ(end - buf, 4);
}
}
// Does it reject all surrogate halves?
TEST(format_impl_test, utf8_decode_surrogate_halves) {
for (uint32_t i = 0xd800; i <= 0xdfff; i++) {
int e;
uint32_t c;
char buf[8] = {0};
utf8_encode(buf, i);
fmt::detail::utf8_decode(buf, &c, &e);
EXPECT_NE(e, 0);
}
}
// How about non-canonical encodings?
TEST(format_impl_test, utf8_decode_non_canonical_encodings) {
int e;
uint32_t c;
const char* end;
char buf2[8] = {char(0xc0), char(0xA4)};
end = fmt::detail::utf8_decode(buf2, &c, &e);
EXPECT_NE(e, 0); // non-canonical len 2
EXPECT_EQ(end, buf2 + 2); // non-canonical recover 2
char buf3[8] = {char(0xe0), char(0x80), char(0xA4)};
end = fmt::detail::utf8_decode(buf3, &c, &e);
EXPECT_NE(e, 0); // non-canonical len 3
EXPECT_EQ(end, buf3 + 3); // non-canonical recover 3
char buf4[8] = {char(0xf0), char(0x80), char(0x80), char(0xA4)};
end = fmt::detail::utf8_decode(buf4, &c, &e);
EXPECT_NE(e, 0); // non-canonical encoding len 4
EXPECT_EQ(end, buf4 + 4); // non-canonical recover 4
}
// Let's try some bogus byte sequences
TEST(format_impl_test, utf8_decode_bogus_byte_sequences) {
int e;
uint32_t c;
// Invalid first byte
char buf0[4] = {char(0xff)};
auto len = fmt::detail::utf8_decode(buf0, &c, &e) - buf0;
EXPECT_NE(e, 0); // "bogus [ff] 0x%02x U+%04lx", e, (unsigned long)c);
EXPECT_EQ(len, 1); // "bogus [ff] recovery %d", len);
// Invalid first byte
char buf1[4] = {char(0x80)};
len = fmt::detail::utf8_decode(buf1, &c, &e) - buf1;
EXPECT_NE(e, 0); // "bogus [80] 0x%02x U+%04lx", e, (unsigned long)c);
EXPECT_EQ(len, 1); // "bogus [80] recovery %d", len);
// Looks like a two-byte sequence but second byte is wrong
char buf2[4] = {char(0xc0), char(0x0a)};
len = fmt::detail::utf8_decode(buf2, &c, &e) - buf2;
EXPECT_NE(e, 0); // "bogus [c0 0a] 0x%02x U+%04lx", e, (unsigned long)c
EXPECT_EQ(len, 2); // "bogus [c0 0a] recovery %d", len);
}
TEST(format_impl_test, to_utf8) {
auto s = std::string("ёжик");
auto u = fmt::detail::to_utf8<wchar_t>(L"\x0451\x0436\x0438\x043A");
EXPECT_EQ(s, u.str());
EXPECT_EQ(s.size(), u.size());
}

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +1,30 @@
# Copyright (c) 2019, Paul Dreik
# License: see LICENSE.rst in the fmt root directory
# settings this links in a main. useful for reproducing,
# kcov, gdb, afl, valgrind.
# (note that libFuzzer can also reproduce, just pass it the files)
option(FMT_FUZZ_LINKMAIN "enables the reproduce mode, instead of libFuzzer" On)
# Link in the main function. Useful for reproducing, kcov, gdb, afl, valgrind.
# (Note that libFuzzer can also reproduce, just pass it the files.)
option(FMT_FUZZ_LINKMAIN "Enables the reproduce mode, instead of libFuzzer" On)
# For oss-fuzz - insert $LIB_FUZZING_ENGINE into the link flags, but only for
# the fuzz targets, otherwise the cmake configuration step fails.
# the fuzz targets, otherwise the CMake configuration step fails.
set(FMT_FUZZ_LDFLAGS "" CACHE STRING "LDFLAGS for the fuzz targets")
# Find all fuzzers.
set(SOURCES
chrono_duration.cpp
named_arg.cpp
one_arg.cpp
sprintf.cpp
two_args.cpp
)
macro(implement_fuzzer sourcefile)
get_filename_component(basename ${sourcefile} NAME_WE)
set(name fuzzer_${basename})
add_executable(${name} ${sourcefile} fuzzer_common.h)
# Adds a binary for reproducing, i.e. no fuzzing, just enables replaying data
# through the fuzzers.
function(add_fuzzer source)
get_filename_component(basename ${source} NAME_WE)
set(name ${basename}-fuzzer)
add_executable(${name} ${source} fuzzer-common.h)
if (FMT_FUZZ_LINKMAIN)
target_sources(${name} PRIVATE main.cpp)
target_sources(${name} PRIVATE main.cc)
endif ()
target_link_libraries(${name} PRIVATE fmt)
if (FMT_FUZZ_LDFLAGS)
target_link_libraries(${name} PRIVATE ${FMT_FUZZ_LDFLAGS})
endif ()
target_compile_features(${name} PRIVATE cxx_generic_lambdas)
endmacro ()
if (FMT_FUZZ_LDFLAGS)
target_link_libraries(${name} PRIVATE ${FMT_FUZZ_LDFLAGS})
endif ()
target_compile_features(${name} PRIVATE cxx_std_14)
endfunction()
foreach (X IN ITEMS ${SOURCES})
implement_fuzzer(${X})
foreach (source chrono-duration.cc chrono-timepoint.cc float.cc named-arg.cc one-arg.cc two-args.cc)
add_fuzzer(${source})
endforeach ()

View File

@ -1,22 +1,4 @@
# FMT Fuzzer
Fuzzing has revealed [several bugs](https://github.com/fmtlib/fmt/issues?&q=is%3Aissue+fuzz)
in fmt. It is a part of the continous fuzzing at
[oss-fuzz](https://github.com/google/oss-fuzz).
The source code is modified to make the fuzzing possible without locking up on
resource exhaustion:
```cpp
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if(spec.precision>100000) {
throw std::runtime_error("fuzz mode - avoiding large precision");
}
#endif
```
This macro is the defacto standard for making fuzzing practically possible, see
[the libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode).
## Running the fuzzers locally
# Running the fuzzers locally
There is a [helper script](build.sh) to build the fuzzers, which has only been
tested on Debian and Ubuntu linux so far. There should be no problems fuzzing on
@ -29,7 +11,7 @@ mkdir build
cd build
export CXX=clang++
export CXXFLAGS="-fsanitize=fuzzer-no-link -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION= -g"
cmake .. -DFMT_SAFE_DURATION_CAST=On -DFMT_FUZZ=On -DFMT_FUZZ_LINKMAIN=Off -DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer"
cmake .. -DFMT_SAFE_DURATION_CAST=On -DFMT_FUZZ=On -DFMT_FUZZ_LINKMAIN=Off -DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer"
cmake --build .
```
should work to build the fuzzers for all platforms which clang supports.
@ -39,5 +21,5 @@ Execute a fuzzer with for instance
cd build
export UBSAN_OPTIONS=halt_on_error=1
mkdir out_chrono
bin/fuzzer_chrono_duration out_chrono
bin/fuzzer_chrono_duration out_chrono
```

View File

@ -1,7 +1,6 @@
#!/bin/sh
#
# Creates fuzzer builds of various kinds
# - reproduce mode (no fuzzing, just enables replaying data through the fuzzers)
# - oss-fuzz emulated mode (makes sure a simulated invocation by oss-fuzz works)
# - libFuzzer build (you will need clang)
# - afl build (you will need afl)
@ -9,7 +8,7 @@
#
# Copyright (c) 2019 Paul Dreik
#
# License: see LICENSE.rst in the fmt root directory
# For the license information refer to format.h.
set -e
me=$(basename $0)
@ -23,16 +22,9 @@ here=$(pwd)
CXXFLAGSALL="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION= -g"
CMAKEFLAGSALL="$root -GNinja -DCMAKE_BUILD_TYPE=Debug -DFMT_DOC=Off -DFMT_TEST=Off -DFMT_FUZZ=On -DCMAKE_CXX_STANDARD=17"
#builds the fuzzers as one would do if using afl or just making
#binaries for reproducing.
builddir=$here/build-fuzzers-reproduce
mkdir -p $builddir
cd $builddir
CXX="ccache g++" CXXFLAGS="$CXXFLAGSALL" cmake \
$CMAKEFLAGSALL
cmake --build $builddir
CLANG=clang++-11
#for performance analysis of the fuzzers
# For performance analysis of the fuzzers.
builddir=$here/build-fuzzers-perfanalysis
mkdir -p $builddir
cd $builddir
@ -43,11 +35,11 @@ $CMAKEFLAGSALL \
cmake --build $builddir
#builds the fuzzers as oss-fuzz does
# Builds the fuzzers as oss-fuzz does.
builddir=$here/build-fuzzers-ossfuzz
mkdir -p $builddir
cd $builddir
CXX="clang++" \
CXX=$CLANG \
CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link" cmake \
cmake $CMAKEFLAGSALL \
-DFMT_FUZZ_LINKMAIN=Off \
@ -56,11 +48,11 @@ cmake $CMAKEFLAGSALL \
cmake --build $builddir
#builds fuzzers for local fuzzing with libfuzzer with asan+usan
# Builds fuzzers for local fuzzing with libfuzzer with asan+usan.
builddir=$here/build-fuzzers-libfuzzer
mkdir -p $builddir
cd $builddir
CXX="clang++" \
CXX=$CLANG \
CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link,address,undefined" cmake \
cmake $CMAKEFLAGSALL \
-DFMT_FUZZ_LINKMAIN=Off \
@ -68,23 +60,11 @@ cmake $CMAKEFLAGSALL \
cmake --build $builddir
#builds fuzzers for local fuzzing with libfuzzer with asan only
builddir=$here/build-fuzzers-libfuzzer-addr
mkdir -p $builddir
cd $builddir
CXX="clang++" \
CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link,undefined" cmake \
cmake $CMAKEFLAGSALL \
-DFMT_FUZZ_LINKMAIN=Off \
-DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer"
cmake --build $builddir
#builds a fast fuzzer for making coverage fast
# Builds a fast fuzzer for making coverage fast.
builddir=$here/build-fuzzers-fast
mkdir -p $builddir
cd $builddir
CXX="clang++" \
CXX=$CLANG \
CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link -O3" cmake \
cmake $CMAKEFLAGSALL \
-DFMT_FUZZ_LINKMAIN=Off \
@ -94,7 +74,7 @@ cmake $CMAKEFLAGSALL \
cmake --build $builddir
#builds fuzzers for local fuzzing with afl
# Builds fuzzers for local fuzzing with afl.
builddir=$here/build-fuzzers-afl
mkdir -p $builddir
cd $builddir

View File

@ -0,0 +1,136 @@
// Copyright (c) 2019, Paul Dreik
// For the license information refer to format.h.
#include <fmt/chrono.h>
#include <cstdint>
#include "fuzzer-common.h"
template <typename Period, typename Rep>
void invoke_inner(fmt::string_view format_str, Rep rep) {
auto value = std::chrono::duration<Rep, Period>(rep);
try {
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(format_str, value);
#else
auto buf = fmt::memory_buffer();
fmt::format_to(std::back_inserter(buf), format_str, value);
#endif
} catch (std::exception&) {
}
}
// Rep is a duration's representation type.
template <typename Rep>
void invoke_outer(const uint8_t* data, size_t size, int period) {
// Always use a fixed location of the data.
static_assert(sizeof(Rep) <= fixed_size, "fixed size is too small");
if (size <= fixed_size + 1) return;
const Rep rep = assign_from_buf<Rep>(data);
data += fixed_size;
size -= fixed_size;
// data is already allocated separately in libFuzzer so reading past the end
// will most likely be detected anyway.
const auto format_str = fmt::string_view(as_chars(data), size);
// yocto, zepto, zetta and yotta are not handled.
switch (period) {
case 1:
invoke_inner<std::atto>(format_str, rep);
break;
case 2:
invoke_inner<std::femto>(format_str, rep);
break;
case 3:
invoke_inner<std::pico>(format_str, rep);
break;
case 4:
invoke_inner<std::nano>(format_str, rep);
break;
case 5:
invoke_inner<std::micro>(format_str, rep);
break;
case 6:
invoke_inner<std::milli>(format_str, rep);
break;
case 7:
invoke_inner<std::centi>(format_str, rep);
break;
case 8:
invoke_inner<std::deci>(format_str, rep);
break;
case 9:
invoke_inner<std::deca>(format_str, rep);
break;
case 10:
invoke_inner<std::kilo>(format_str, rep);
break;
case 11:
invoke_inner<std::mega>(format_str, rep);
break;
case 12:
invoke_inner<std::giga>(format_str, rep);
break;
case 13:
invoke_inner<std::tera>(format_str, rep);
break;
case 14:
invoke_inner<std::peta>(format_str, rep);
break;
case 15:
invoke_inner<std::exa>(format_str, rep);
break;
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (size <= 4) return 0;
const auto representation = data[0];
const auto period = data[1];
data += 2;
size -= 2;
switch (representation) {
case 1:
invoke_outer<char>(data, size, period);
break;
case 2:
invoke_outer<signed char>(data, size, period);
break;
case 3:
invoke_outer<unsigned char>(data, size, period);
break;
case 4:
invoke_outer<short>(data, size, period);
break;
case 5:
invoke_outer<unsigned short>(data, size, period);
break;
case 6:
invoke_outer<int>(data, size, period);
break;
case 7:
invoke_outer<unsigned int>(data, size, period);
break;
case 8:
invoke_outer<long>(data, size, period);
break;
case 9:
invoke_outer<unsigned long>(data, size, period);
break;
case 10:
invoke_outer<float>(data, size, period);
break;
case 11:
invoke_outer<double>(data, size, period);
break;
case 12:
invoke_outer<long double>(data, size, period);
break;
}
return 0;
}

View File

@ -0,0 +1,32 @@
// Copyright (c) 2021, Paul Dreik
// For license information refer to format.h.
#include <fmt/chrono.h>
#include "fuzzer-common.h"
/*
* a fuzzer for the chrono timepoints formatters
* C is a clock (std::chrono::system_clock etc)
*/
template <typename C> void doit(const uint8_t* data, size_t size) {
using Rep = typename C::time_point::rep;
constexpr auto N = sizeof(Rep);
if (size < N) return;
const auto x = assign_from_buf<Rep>(data);
typename C::duration dur{x};
typename C::time_point timepoint{dur};
data += N;
size -= N;
data_to_string format_str(data, size);
std::string message = fmt::format(format_str.get(), timepoint);
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
try {
doit<std::chrono::system_clock>(data, size);
} catch (...) {
}
return 0;
}

View File

@ -1,152 +0,0 @@
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <fmt/chrono.h>
#include <cstdint>
#include <limits>
#include <stdexcept>
#include <type_traits>
#include <vector>
#include "fuzzer_common.h"
template <typename Item, typename Ratio>
void invoke_inner(fmt::string_view formatstring, const Item item) {
const std::chrono::duration<Item, Ratio> value(item);
try {
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(formatstring, value);
#else
fmt::memory_buffer buf;
fmt::format_to(buf, formatstring, value);
#endif
} catch (std::exception& /*e*/) {
}
}
// Item is the underlying type for duration (int, long etc)
template <typename Item>
void invoke_outer(const uint8_t* Data, std::size_t Size, const int scaling) {
// always use a fixed location of the data
using fmt_fuzzer::Nfixed;
constexpr auto N = sizeof(Item);
static_assert(N <= Nfixed, "fixed size is too small");
if (Size <= Nfixed + 1) {
return;
}
const Item item = fmt_fuzzer::assignFromBuf<Item>(Data);
// fast forward
Data += Nfixed;
Size -= Nfixed;
// Data is already allocated separately in libFuzzer so reading past
// the end will most likely be detected anyway
const auto formatstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
// doit_impl<Item,std::yocto>(buf.data(),item);
// doit_impl<Item,std::zepto>(buf.data(),item);
switch (scaling) {
case 1:
invoke_inner<Item, std::atto>(formatstring, item);
break;
case 2:
invoke_inner<Item, std::femto>(formatstring, item);
break;
case 3:
invoke_inner<Item, std::pico>(formatstring, item);
break;
case 4:
invoke_inner<Item, std::nano>(formatstring, item);
break;
case 5:
invoke_inner<Item, std::micro>(formatstring, item);
break;
case 6:
invoke_inner<Item, std::milli>(formatstring, item);
break;
case 7:
invoke_inner<Item, std::centi>(formatstring, item);
break;
case 8:
invoke_inner<Item, std::deci>(formatstring, item);
break;
case 9:
invoke_inner<Item, std::deca>(formatstring, item);
break;
case 10:
invoke_inner<Item, std::kilo>(formatstring, item);
break;
case 11:
invoke_inner<Item, std::mega>(formatstring, item);
break;
case 12:
invoke_inner<Item, std::giga>(formatstring, item);
break;
case 13:
invoke_inner<Item, std::tera>(formatstring, item);
break;
case 14:
invoke_inner<Item, std::peta>(formatstring, item);
break;
case 15:
invoke_inner<Item, std::exa>(formatstring, item);
}
// doit_impl<Item,std::zeta>(buf.data(),item);
// doit_impl<Item,std::yotta>(buf.data(),item);
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, std::size_t Size) {
if (Size <= 4) {
return 0;
}
const auto representation = Data[0];
const auto scaling = Data[1];
Data += 2;
Size -= 2;
switch (representation) {
case 1:
invoke_outer<char>(Data, Size, scaling);
break;
case 2:
invoke_outer<unsigned char>(Data, Size, scaling);
break;
case 3:
invoke_outer<signed char>(Data, Size, scaling);
break;
case 4:
invoke_outer<short>(Data, Size, scaling);
break;
case 5:
invoke_outer<unsigned short>(Data, Size, scaling);
break;
case 6:
invoke_outer<int>(Data, Size, scaling);
break;
case 7:
invoke_outer<unsigned int>(Data, Size, scaling);
break;
case 8:
invoke_outer<long>(Data, Size, scaling);
break;
case 9:
invoke_outer<unsigned long>(Data, Size, scaling);
break;
case 10:
invoke_outer<float>(Data, Size, scaling);
break;
case 11:
invoke_outer<double>(Data, Size, scaling);
break;
case 12:
invoke_outer<long double>(Data, Size, scaling);
break;
default:
break;
}
return 0;
}

39
test/fuzzing/float.cc Normal file
View File

@ -0,0 +1,39 @@
// A fuzzer for floating-point formatter.
// For the license information refer to format.h.
#include <fmt/format.h>
#include <cstdint>
#include <cstdlib>
#include <limits>
#include <stdexcept>
#include "fuzzer-common.h"
void check_round_trip(fmt::string_view format_str, double value) {
auto buffer = fmt::memory_buffer();
fmt::format_to(std::back_inserter(buffer), format_str, value);
if (std::isnan(value)) {
auto nan = std::signbit(value) ? "-nan" : "nan";
if (fmt::string_view(buffer.data(), buffer.size()) != nan)
throw std::runtime_error("round trip failure");
return;
}
buffer.push_back('\0');
char* ptr = nullptr;
if (std::strtod(buffer.data(), &ptr) != value)
throw std::runtime_error("round trip failure");
if (ptr + 1 != buffer.end()) throw std::runtime_error("unparsed output");
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (size <= sizeof(double) || !std::numeric_limits<double>::is_iec559)
return 0;
check_round_trip("{}", assign_from_buf<double>(data));
// A larger than necessary precision is used to trigger the fallback
// formatter.
check_round_trip("{:.50g}", assign_from_buf<double>(data));
return 0;
}

View File

@ -0,0 +1,77 @@
// Copyright (c) 2019, Paul Dreik
// For the license information refer to format.h.
#ifndef FUZZER_COMMON_H
#define FUZZER_COMMON_H
#include <fmt/core.h>
#include <cstdint> // std::uint8_t
#include <cstring> // memcpy
#include <vector>
// One can format to either a string, or a buffer. The latter is faster, but
// one may be interested in formatting to a string instead to verify it works
// as intended. To avoid a combinatoric explosion, select this at compile time
// instead of dynamically from the fuzz data.
#define FMT_FUZZ_FORMAT_TO_STRING 0
// If {fmt} is given a buffer that is separately allocated, chances that address
// sanitizer detects out of bound reads is much higher. However, it slows down
// the fuzzing.
#define FMT_FUZZ_SEPARATE_ALLOCATION 1
// The size of the largest possible type in use.
// To let the the fuzzer mutation be efficient at cross pollinating between
// different types, use a fixed size format. The same bit pattern, interpreted
// as another type, is likely interesting.
constexpr auto fixed_size = 16;
// Casts data to a char pointer.
template <typename T> inline const char* as_chars(const T* data) {
return reinterpret_cast<const char*>(data);
}
// Casts data to a byte pointer.
template <typename T> inline const std::uint8_t* as_bytes(const T* data) {
return reinterpret_cast<const std::uint8_t*>(data);
}
// Blits bytes from data to form an (assumed trivially constructible) object
// of type Item.
template <class Item> inline Item assign_from_buf(const std::uint8_t* data) {
auto item = Item();
std::memcpy(&item, data, sizeof(Item));
return item;
}
// Reads a boolean value by looking at the first byte from data.
template <> inline bool assign_from_buf<bool>(const std::uint8_t* data) {
return *data != 0;
}
struct data_to_string {
#if FMT_FUZZ_SEPARATE_ALLOCATION
std::vector<char> buffer;
data_to_string(const uint8_t* data, size_t size, bool add_terminator = false)
: buffer(size + (add_terminator ? 1 : 0)) {
if (size) {
std::memcpy(buffer.data(), data, size);
}
}
fmt::string_view get() const { return {buffer.data(), buffer.size()}; }
#else
fmt::string_view sv;
data_to_string(const uint8_t* data, size_t size, bool = false)
: str(as_chars(data), size) {}
fmt::string_view get() const { return sv; }
#endif
const char* data() const { return get().data(); }
};
#endif // FUZZER_COMMON_H

View File

@ -1,67 +0,0 @@
#ifndef FUZZER_COMMON_H
#define FUZZER_COMMON_H
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <cstdint> // std::uint8_t
#include <cstring> // memcpy
#include <type_traits> // trivially copyable
// one can format to either a string, or a buf. buf is faster,
// but one may be interested in formatting to a string instead to
// verify it works as intended. to avoid a combinatoric explosion,
// select this at compile time instead of dynamically from the fuzz data
#define FMT_FUZZ_FORMAT_TO_STRING 0
// if fmt is given a buffer that is separately allocated,
// chances that address sanitizer detects out of bound reads is
// much higher. However, it slows down the fuzzing.
#define FMT_FUZZ_SEPARATE_ALLOCATION 1
// To let the the fuzzer mutation be efficient at cross pollinating
// between different types, use a fixed size format.
// The same bit pattern, interpreted as another type,
// is likely interesting.
// For this, we must know the size of the largest possible type in use.
// There are some problems on travis, claiming Nfixed is not a constant
// expression which seems to be an issue with older versions of libstdc++
#if _GLIBCXX_RELEASE >= 7
# include <algorithm>
namespace fmt_fuzzer {
constexpr auto Nfixed = std::max(sizeof(long double), sizeof(std::intmax_t));
}
#else
namespace fmt_fuzzer {
constexpr auto Nfixed = 16;
}
#endif
namespace fmt_fuzzer {
// view data as a c char pointer.
template <typename T> inline const char* as_chars(const T* data) {
return static_cast<const char*>(static_cast<const void*>(data));
}
// view data as a byte pointer
template <typename T> inline const std::uint8_t* as_bytes(const T* data) {
return static_cast<const std::uint8_t*>(static_cast<const void*>(data));
}
// blits bytes from Data to form an (assumed trivially constructible) object
// of type Item
template <class Item> inline Item assignFromBuf(const std::uint8_t* Data) {
Item item{};
std::memcpy(&item, Data, sizeof(Item));
return item;
}
// reads a boolean value by looking at the first byte from Data
template <> inline bool assignFromBuf<bool>(const std::uint8_t* Data) {
return !!Data[0];
}
} // namespace fmt_fuzzer
#endif // FUZZER_COMMON_H

22
test/fuzzing/main.cc Normal file
View File

@ -0,0 +1,22 @@
#include <cassert>
#include <fstream>
#include <vector>
#include "fuzzer-common.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
int main(int argc, char** argv) {
for (int i = 1; i < argc; ++i) {
std::ifstream in(argv[i]);
assert(in);
in.seekg(0, std::ios_base::end);
const auto size = in.tellg();
assert(size >= 0);
in.seekg(0, std::ios_base::beg);
std::vector<char> buf(static_cast<size_t>(size));
in.read(buf.data(), size);
assert(in.gcount() == size);
LLVMFuzzerTestOneInput(as_bytes(buf.data()), buf.size());
}
}

View File

@ -1,21 +0,0 @@
#include <cassert>
#include <fstream>
#include <sstream>
#include <vector>
#include "fuzzer_common.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, std::size_t Size);
int main(int argc, char* argv[]) {
for (int i = 1; i < argc; ++i) {
std::ifstream in(argv[i]);
assert(in);
in.seekg(0, std::ios_base::end);
const auto pos = in.tellg();
assert(pos >= 0);
in.seekg(0, std::ios_base::beg);
std::vector<char> buf(static_cast<std::size_t>(pos));
in.read(buf.data(), static_cast<long>(buf.size()));
assert(in.gcount() == pos);
LLVMFuzzerTestOneInput(fmt_fuzzer::as_bytes(buf.data()), buf.size());
}
}

102
test/fuzzing/named-arg.cc Normal file
View File

@ -0,0 +1,102 @@
// Copyright (c) 2019, Paul Dreik
// For the license information refer to format.h.
#include <fmt/chrono.h>
#include <cstdint>
#include <type_traits>
#include <vector>
#include "fuzzer-common.h"
template <typename T>
void invoke_fmt(const uint8_t* data, size_t size, unsigned arg_name_size) {
static_assert(sizeof(T) <= fixed_size, "fixed_size too small");
if (size <= fixed_size) return;
const T value = assign_from_buf<T>(data);
data += fixed_size;
size -= fixed_size;
if (arg_name_size <= 0 || arg_name_size >= size) return;
data_to_string arg_name(data, arg_name_size, true);
data += arg_name_size;
size -= arg_name_size;
data_to_string format_str(data, size);
try {
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message =
fmt::format(format_str.get(), fmt::arg(arg_name.data(), value));
#else
fmt::memory_buffer out;
fmt::format_to(std::back_inserter(out), format_str.get(),
fmt::arg(arg_name.data(), value));
#endif
} catch (std::exception&) {
}
}
// For dynamic dispatching to an explicit instantiation.
template <typename Callback> void invoke(int type, Callback callback) {
switch (type) {
case 0:
callback(bool());
break;
case 1:
callback(char());
break;
case 2:
using sc = signed char;
callback(sc());
break;
case 3:
using uc = unsigned char;
callback(uc());
break;
case 4:
callback(short());
break;
case 5:
using us = unsigned short;
callback(us());
break;
case 6:
callback(int());
break;
case 7:
callback(unsigned());
break;
case 8:
callback(long());
break;
case 9:
using ul = unsigned long;
callback(ul());
break;
case 10:
callback(float());
break;
case 11:
callback(double());
break;
case 12:
using LD = long double;
callback(LD());
break;
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (size <= 3) return 0;
// Switch types depending on the first byte of the input.
const auto type = data[0] & 0x0F;
const unsigned arg_name_size = (data[0] & 0xF0) >> 4;
data++;
size--;
invoke(type, [=](auto arg) {
invoke_fmt<decltype(arg)>(data, size, arg_name_size);
});
return 0;
}

View File

@ -1,128 +0,0 @@
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <fmt/chrono.h>
#include <fmt/core.h>
#include <cstdint>
#include <stdexcept>
#include <type_traits>
#include <vector>
#include "fuzzer_common.h"
template <typename Item1>
void invoke_fmt(const uint8_t* Data, std::size_t Size, unsigned int argsize) {
constexpr auto N1 = sizeof(Item1);
static_assert(N1 <= fmt_fuzzer::Nfixed, "Nfixed too small");
if (Size <= fmt_fuzzer::Nfixed) {
return;
}
const Item1 item1 = fmt_fuzzer::assignFromBuf<Item1>(Data);
Data += fmt_fuzzer::Nfixed;
Size -= fmt_fuzzer::Nfixed;
// how many chars should be used for the argument name?
if (argsize <= 0 || argsize >= Size) {
return;
}
// allocating buffers separately is slower, but increases chances
// of detecting memory errors
#if FMT_FUZZ_SEPARATE_ALLOCATION
std::vector<char> argnamebuffer(argsize);
std::memcpy(argnamebuffer.data(), Data, argsize);
auto argname = fmt::string_view(argnamebuffer.data(), argsize);
#else
auto argname = fmt::string_view(fmt_fuzzer::as_chars(Data), argsize);
#endif
Data += argsize;
Size -= argsize;
#if FMT_FUZZ_SEPARATE_ALLOCATION
// allocates as tight as possible, making it easier to catch buffer overruns.
std::vector<char> fmtstringbuffer(Size);
std::memcpy(fmtstringbuffer.data(), Data, Size);
auto fmtstring = fmt::string_view(fmtstringbuffer.data(), Size);
#else
auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
#endif
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(fmtstring, fmt::arg(argname, item1));
#else
fmt::memory_buffer outbuf;
fmt::format_to(outbuf, fmtstring, fmt::arg(argname, item1));
#endif
}
// for dynamic dispatching to an explicit instantiation
template <typename Callback> void invoke(int index, Callback callback) {
switch (index) {
case 0:
callback(bool{});
break;
case 1:
callback(char{});
break;
case 2:
using sc = signed char;
callback(sc{});
break;
case 3:
using uc = unsigned char;
callback(uc{});
break;
case 4:
callback(short{});
break;
case 5:
using us = unsigned short;
callback(us{});
break;
case 6:
callback(int{});
break;
case 7:
callback(unsigned{});
break;
case 8:
callback(long{});
break;
case 9:
using ul = unsigned long;
callback(ul{});
break;
case 10:
callback(float{});
break;
case 11:
callback(double{});
break;
case 12:
using LD = long double;
callback(LD{});
break;
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, std::size_t Size) {
if (Size <= 3) {
return 0;
}
// switch types depending on the first byte of the input
const auto first = Data[0] & 0x0F;
const unsigned int second = (Data[0] & 0xF0) >> 4;
Data++;
Size--;
auto outerfcn = [=](auto param1) {
invoke_fmt<decltype(param1)>(Data, Size, second);
};
try {
invoke(first, outerfcn);
} catch (std::exception& /*e*/) {
}
return 0;
}

92
test/fuzzing/one-arg.cc Normal file
View File

@ -0,0 +1,92 @@
// Copyright (c) 2019, Paul Dreik
// For the license information refer to format.h.
#include <fmt/chrono.h>
#include <cstdint>
#include <exception>
#include "fuzzer-common.h"
template <typename T, typename Repr> const T* from_repr(const Repr& r) {
return &r;
}
template <> const std::tm* from_repr<std::tm>(const std::time_t& t) {
return std::localtime(&t);
}
template <typename T, typename Repr = T>
void invoke_fmt(const uint8_t* data, size_t size) {
static_assert(sizeof(Repr) <= fixed_size, "Nfixed is too small");
if (size <= fixed_size) return;
auto repr = assign_from_buf<Repr>(data);
const T* value = from_repr<T>(repr);
if (!value) return;
data += fixed_size;
size -= fixed_size;
data_to_string format_str(data, size);
try {
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(format_str.get(), *value);
#else
auto buf = fmt::memory_buffer();
fmt::format_to(std::back_inserter(buf), format_str.get(), *value);
#endif
} catch (std::exception&) {
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (size <= 3) return 0;
const auto first = data[0];
data++;
size--;
switch (first) {
case 0:
invoke_fmt<bool>(data, size);
break;
case 1:
invoke_fmt<char>(data, size);
break;
case 2:
invoke_fmt<unsigned char>(data, size);
break;
case 3:
invoke_fmt<signed char>(data, size);
break;
case 4:
invoke_fmt<short>(data, size);
break;
case 5:
invoke_fmt<unsigned short>(data, size);
break;
case 6:
invoke_fmt<int>(data, size);
break;
case 7:
invoke_fmt<unsigned int>(data, size);
break;
case 8:
invoke_fmt<long>(data, size);
break;
case 9:
invoke_fmt<unsigned long>(data, size);
break;
case 10:
invoke_fmt<float>(data, size);
break;
case 11:
invoke_fmt<double>(data, size);
break;
case 12:
invoke_fmt<long double>(data, size);
break;
case 13:
invoke_fmt<std::tm, std::time_t>(data, size);
break;
}
return 0;
}

View File

@ -1,131 +0,0 @@
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <fmt/core.h>
#include <cstdint>
#include <stdexcept>
#include <type_traits>
#include <vector>
#include <fmt/chrono.h>
#include "fuzzer_common.h"
using fmt_fuzzer::Nfixed;
template <typename Item>
void invoke_fmt(const uint8_t* Data, std::size_t Size) {
constexpr auto N = sizeof(Item);
static_assert(N <= Nfixed, "Nfixed is too small");
if (Size <= Nfixed) {
return;
}
const Item item = fmt_fuzzer::assignFromBuf<Item>(Data);
Data += Nfixed;
Size -= Nfixed;
#if FMT_FUZZ_SEPARATE_ALLOCATION
// allocates as tight as possible, making it easier to catch buffer overruns.
std::vector<char> fmtstringbuffer(Size);
std::memcpy(fmtstringbuffer.data(), Data, Size);
auto fmtstring = fmt::string_view(fmtstringbuffer.data(), Size);
#else
auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
#endif
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(fmtstring, item);
#else
fmt::memory_buffer message;
fmt::format_to(message, fmtstring, item);
#endif
}
void invoke_fmt_time(const uint8_t* Data, std::size_t Size) {
using Item = std::time_t;
constexpr auto N = sizeof(Item);
static_assert(N <= Nfixed, "Nfixed too small");
if (Size <= Nfixed) {
return;
}
const Item item = fmt_fuzzer::assignFromBuf<Item>(Data);
Data += Nfixed;
Size -= Nfixed;
#if FMT_FUZZ_SEPARATE_ALLOCATION
// allocates as tight as possible, making it easier to catch buffer overruns.
std::vector<char> fmtstringbuffer(Size);
std::memcpy(fmtstringbuffer.data(), Data, Size);
auto fmtstring = fmt::string_view(fmtstringbuffer.data(), Size);
#else
auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
#endif
auto* b = std::localtime(&item);
if (b) {
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(fmtstring, *b);
#else
fmt::memory_buffer message;
fmt::format_to(message, fmtstring, *b);
#endif
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, std::size_t Size) {
if (Size <= 3) {
return 0;
}
const auto first = Data[0];
Data++;
Size--;
try {
switch (first) {
case 0:
invoke_fmt<bool>(Data, Size);
break;
case 1:
invoke_fmt<char>(Data, Size);
break;
case 2:
invoke_fmt<unsigned char>(Data, Size);
break;
case 3:
invoke_fmt<signed char>(Data, Size);
break;
case 4:
invoke_fmt<short>(Data, Size);
break;
case 5:
invoke_fmt<unsigned short>(Data, Size);
break;
case 6:
invoke_fmt<int>(Data, Size);
break;
case 7:
invoke_fmt<unsigned int>(Data, Size);
break;
case 8:
invoke_fmt<long>(Data, Size);
break;
case 9:
invoke_fmt<unsigned long>(Data, Size);
break;
case 10:
invoke_fmt<float>(Data, Size);
break;
case 11:
invoke_fmt<double>(Data, Size);
break;
case 12:
invoke_fmt<long double>(Data, Size);
break;
case 13:
invoke_fmt_time(Data, Size);
break;
default:
break;
}
} catch (std::exception& /*e*/) {
}
return 0;
}

View File

@ -1,116 +0,0 @@
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <fmt/format.h>
#include <fmt/printf.h>
#include <cstdint>
#include <stdexcept>
#include "fuzzer_common.h"
using fmt_fuzzer::Nfixed;
template <typename Item1, typename Item2>
void invoke_fmt(const uint8_t* Data, std::size_t Size) {
constexpr auto N1 = sizeof(Item1);
constexpr auto N2 = sizeof(Item2);
static_assert(N1 <= Nfixed, "size1 exceeded");
static_assert(N2 <= Nfixed, "size2 exceeded");
if (Size <= Nfixed + Nfixed) {
return;
}
Item1 item1 = fmt_fuzzer::assignFromBuf<Item1>(Data);
Data += Nfixed;
Size -= Nfixed;
Item2 item2 = fmt_fuzzer::assignFromBuf<Item2>(Data);
Data += Nfixed;
Size -= Nfixed;
auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(fmtstring, item1, item2);
#else
fmt::memory_buffer message;
fmt::format_to(message, fmtstring, item1, item2);
#endif
}
// for dynamic dispatching to an explicit instantiation
template <typename Callback> void invoke(int index, Callback callback) {
switch (index) {
case 0:
callback(bool{});
break;
case 1:
callback(char{});
break;
case 2:
using sc = signed char;
callback(sc{});
break;
case 3:
using uc = unsigned char;
callback(uc{});
break;
case 4:
callback(short{});
break;
case 5:
using us = unsigned short;
callback(us{});
break;
case 6:
callback(int{});
break;
case 7:
callback(unsigned{});
break;
case 8:
callback(long{});
break;
case 9:
using ul = unsigned long;
callback(ul{});
break;
case 10:
callback(float{});
break;
case 11:
callback(double{});
break;
case 12:
using LD = long double;
callback(LD{});
break;
case 13:
using ptr = void*;
callback(ptr{});
break;
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, std::size_t Size) {
if (Size <= 3) {
return 0;
}
// switch types depending on the first byte of the input
const auto first = Data[0] & 0x0F;
const auto second = (Data[0] & 0xF0) >> 4;
Data++;
Size--;
auto outer = [=](auto param1) {
auto inner = [=](auto param2) {
invoke_fmt<decltype(param1), decltype(param2)>(Data, Size);
};
invoke(second, inner);
};
try {
invoke(first, outer);
} catch (std::exception& /*e*/) {
}
return 0;
}

106
test/fuzzing/two-args.cc Normal file
View File

@ -0,0 +1,106 @@
// Copyright (c) 2019, Paul Dreik
// For the license information refer to format.h.
#include <fmt/format.h>
#include <cstdint>
#include <exception>
#include <string>
#include "fuzzer-common.h"
template <typename Item1, typename Item2>
void invoke_fmt(const uint8_t* data, size_t size) {
static_assert(sizeof(Item1) <= fixed_size, "size1 exceeded");
static_assert(sizeof(Item2) <= fixed_size, "size2 exceeded");
if (size <= fixed_size + fixed_size) return;
const Item1 item1 = assign_from_buf<Item1>(data);
data += fixed_size;
size -= fixed_size;
const Item2 item2 = assign_from_buf<Item2>(data);
data += fixed_size;
size -= fixed_size;
auto format_str = fmt::string_view(as_chars(data), size);
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(format_str, item1, item2);
#else
auto buf = fmt::memory_buffer();
fmt::format_to(std::back_inserter(buf), format_str, item1, item2);
#endif
}
// For dynamic dispatching to an explicit instantiation.
template <typename Callback> void invoke(int index, Callback callback) {
switch (index) {
case 0:
callback(bool());
break;
case 1:
callback(char());
break;
case 2:
using sc = signed char;
callback(sc());
break;
case 3:
using uc = unsigned char;
callback(uc());
break;
case 4:
callback(short());
break;
case 5:
using us = unsigned short;
callback(us());
break;
case 6:
callback(int());
break;
case 7:
callback(unsigned());
break;
case 8:
callback(long());
break;
case 9:
using ul = unsigned long;
callback(ul());
break;
case 10:
callback(float());
break;
case 11:
callback(double());
break;
case 12:
using LD = long double;
callback(LD());
break;
case 13:
using ptr = void*;
callback(ptr());
break;
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (size <= 3) return 0;
// Switch types depending on the first byte of the input.
const auto type1 = data[0] & 0x0F;
const auto type2 = (data[0] & 0xF0) >> 4;
data++;
size--;
try {
invoke(type1, [=](auto param1) {
invoke(type2, [=](auto param2) {
invoke_fmt<decltype(param1), decltype(param2)>(data, size);
});
});
} catch (std::exception&) {
}
return 0;
}

View File

@ -1,112 +0,0 @@
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <fmt/format.h>
#include <cstdint>
#include <stdexcept>
#include <type_traits>
#include "fuzzer_common.h"
constexpr auto Nfixed = fmt_fuzzer::Nfixed;
template <typename Item1, typename Item2>
void invoke_fmt(const uint8_t* Data, std::size_t Size) {
constexpr auto N1 = sizeof(Item1);
constexpr auto N2 = sizeof(Item2);
static_assert(N1 <= Nfixed, "size1 exceeded");
static_assert(N2 <= Nfixed, "size2 exceeded");
if (Size <= Nfixed + Nfixed) {
return;
}
const Item1 item1 = fmt_fuzzer::assignFromBuf<Item1>(Data);
Data += Nfixed;
Size -= Nfixed;
const Item2 item2 = fmt_fuzzer::assignFromBuf<Item2>(Data);
Data += Nfixed;
Size -= Nfixed;
auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(fmtstring, item1, item2);
#else
fmt::memory_buffer message;
fmt::format_to(message, fmtstring, item1, item2);
#endif
}
// for dynamic dispatching to an explicit instantiation
template <typename Callback> void invoke(int index, Callback callback) {
switch (index) {
case 0:
callback(bool{});
break;
case 1:
callback(char{});
break;
case 2:
using sc = signed char;
callback(sc{});
break;
case 3:
using uc = unsigned char;
callback(uc{});
break;
case 4:
callback(short{});
break;
case 5:
using us = unsigned short;
callback(us{});
break;
case 6:
callback(int{});
break;
case 7:
callback(unsigned{});
break;
case 8:
callback(long{});
break;
case 9:
using ul = unsigned long;
callback(ul{});
break;
case 10:
callback(float{});
break;
case 11:
callback(double{});
break;
case 12:
using LD = long double;
callback(LD{});
break;
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, std::size_t Size) {
if (Size <= 3) {
return 0;
}
// switch types depending on the first byte of the input
const auto first = Data[0] & 0x0F;
const auto second = (Data[0] & 0xF0) >> 4;
Data++;
Size--;
auto outer = [=](auto param1) {
auto inner = [=](auto param2) {
invoke_fmt<decltype(param1), decltype(param2)>(Data, Size);
};
invoke(second, inner);
};
try {
invoke(first, outer);
} catch (std::exception& /*e*/) {
}
return 0;
}

Some files were not shown because too many files have changed in this diff Show More