Compare commits

...

35 Commits

Author SHA1 Message Date
Victor Zverovich
a6e871e39b Don't pull in locale dependency 2025-12-04 06:28:37 -08:00
Watal M. Iwasaki
e137db699a
Fix doc CSS to display white-space properly (#4622)
See fmtlib/fmt.dev#25
2025-12-03 11:35:04 -08:00
dependabot[bot]
d6712ff2c0
Bump actions/checkout from 5.0.0 to 6.0.0 (#4621)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5.0.0 to 6.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](08c6903cd8...1af3b93b68)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 09:04:20 -08:00
Victor Zverovich
2d839bbc61 Fix format_to_n 2025-11-30 07:12:48 -08:00
Victor Zverovich
5bc56e24a9 Update clang-format to version 21 2025-11-28 20:05:18 -08:00
bigmoonbit
2727215c11
chore: minor improvement for docs (#4616)
Signed-off-by: bigmoonbit <bigmoonbit@outlook.com>
2025-11-28 12:55:25 -08:00
Victor Zverovich
790b9389ae
Update README for clarity on performance comparison 2025-11-23 11:15:23 -08:00
Victor Zverovich
a731c73fd5 Make FMT_USE_FULL_CACHE_DRAGONBOX depend on __OPTIMIZE_SIZE__ by default
Thanks to Matthias Kretz for the idea.
2025-11-23 09:03:02 -08:00
Victor Zverovich
3391f9e992 Cleanup test 2025-11-22 19:14:32 -08:00
friedkeenan
9f197b22ae
Make FMT_STRING redundant when FMT_USE_CONSTEVAL is enabled (#4612) 2025-11-22 14:36:29 -08:00
Victor Zverovich
f20b16617e Fix formatting 2025-11-22 13:48:03 -08:00
Victor Zverovich
14451704d5 Opt out std::complex from tuple formatting 2025-11-22 08:23:11 -08:00
Victor Zverovich
7a0da1c68a Merge compile-time FP tests into other compile-time tests 2025-11-22 07:46:38 -08:00
Victor Zverovich
e3d2174b3c Remove more invalid tests 2025-11-22 07:30:11 -08:00
Victor Zverovich
a6fb4d3b06 Remove invalid tests 2025-11-22 07:00:06 -08:00
Victor Zverovich
706fecea30 Apply clang-format 2025-11-22 06:45:50 -08:00
Victor Zverovich
e00fd756cc
Update link 2025-11-19 06:58:44 -08:00
Victor Zverovich
fc17e825d9 Remove the broken fmt::say function 2025-11-12 11:06:01 -08:00
Victor Zverovich
3fccfb8a80
Update benchmark table formatting in README 2025-11-07 10:05:56 -08:00
Victor Zverovich
690c9c71a0
Update benchmark results 2025-11-06 17:25:24 -08:00
Victor Zverovich
1122268510 Make path formatting lossless with WTF-8 2025-11-05 10:59:06 -10:00
Victor Zverovich
a4c7e17133 Improve build speed, take 2 2025-11-04 10:19:39 -10:00
Victor Zverovich
bfd0129b91 Improve build speed 2025-11-04 09:33:18 -10:00
Victor Zverovich
62f57b2496 Fix the macOS build 2025-11-04 09:12:57 -10:00
Victor Zverovich
ef7a566413 Reduce bloat-test result in debug mode from ~200k to ~85k 2025-11-03 16:21:10 -10:00
Victor Zverovich
42840cb415
Update benchmark results 2025-11-03 16:50:43 -08:00
Victor Zverovich
5ac44cd128 Fix a warning 2025-11-03 13:39:29 -10:00
Victor Zverovich
23c13b3060 Handle ulink in docs 2025-11-03 13:14:48 -10:00
Victor Zverovich
29c46fb82d Add support for more doxygen tags 2025-11-03 10:57:41 -10:00
Victor Zverovich
a0571f3f59 Document output_file 2025-11-03 10:11:31 -10:00
dependabot[bot]
a195dd6b37
Bump github/codeql-action from 3.30.5 to 4.31.2 (#4599)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.30.5 to 4.31.2.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](3599b3baa1...0499de31b9)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.31.2
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-03 08:53:27 -08:00
Victor Zverovich
33ad559eb8 Fix fuzzer 2025-11-02 07:52:16 -10:00
dependabot[bot]
b6cd356196
Bump actions/upload-artifact from 4.6.0 to 5.0.0 (#4598)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.0 to 5.0.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](65c4c4a1dd...330a01c490)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-01 09:39:15 -07:00
J. Berger
c3be070b7e
When using MSVC x86 to compile v12.0.0 or v12.1.0, conversions from __int64 to a 32bit unsigned int trigger warnings. (#4594)
This is a follow-up for PR #4572.
2025-11-01 09:38:30 -07:00
Stéén
27bf8b47fe
Add FMT_CONSTEXPR to static_format_result members (#4591)
Co-authored-by: Robin Oger <roger@qcify.com>
2025-10-29 18:34:42 -07:00
28 changed files with 834 additions and 857 deletions

View File

@ -25,7 +25,7 @@ jobs:
language: c++ language: c++
- name: Upload crash - name: Upload crash
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
if: failure() && steps.build.outcome == 'success' if: failure() && steps.build.outcome == 'success'
with: with:
name: artifacts name: artifacts

View File

@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Add Ubuntu mirrors - name: Add Ubuntu mirrors
run: | run: |

View File

@ -13,16 +13,16 @@ jobs:
format_code: format_code:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Install clang-format - name: Install clang-format
run: | run: |
wget https://apt.llvm.org/llvm.sh wget https://apt.llvm.org/llvm.sh
sudo bash ./llvm.sh 17 sudo bash ./llvm.sh 21
sudo apt install clang-format-17 sudo apt install clang-format-21
- name: Run clang-format - name: Run clang-format
run: | run: |
find include src -name '*.h' -o -name '*.cc' | \ find include src -name '*.h' -o -name '*.cc' | \
xargs clang-format-17 -i -style=file -fallback-style=none xargs clang-format-21 -i -style=file -fallback-style=none
git diff --exit-code git diff --exit-code

View File

@ -55,7 +55,7 @@ jobs:
install: sudo apt install libc++-14-dev libc++abi-14-dev install: sudo apt install libc++-14-dev libc++abi-14-dev
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Set timezone - name: Set timezone
run: sudo timedatectl set-timezone 'Europe/Kyiv' run: sudo timedatectl set-timezone 'Europe/Kyiv'

View File

@ -9,13 +9,10 @@ jobs:
build: build:
strategy: strategy:
matrix: matrix:
os: [macos-13, macos-14] os: [macos-14]
build_type: [Debug, Release] build_type: [Debug, Release]
std: [11, 17, 20] std: [11, 17, 20, 23]
shared: [""] shared: [""]
exclude:
- { os: macos-13, std: 11 }
- { os: macos-13, std: 17 }
include: include:
- os: macos-14 - os: macos-14
std: 23 std: 23
@ -25,7 +22,7 @@ jobs:
runs-on: '${{ matrix.os }}' runs-on: '${{ matrix.os }}'
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Set timezone - name: Set timezone
run: sudo systemsetup -settimezone 'Europe/Minsk' run: sudo systemsetup -settimezone 'Europe/Minsk'

View File

@ -29,7 +29,7 @@ jobs:
steps: steps:
- name: "Checkout code" - name: "Checkout code"
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
persist-credentials: false persist-credentials: false
@ -52,7 +52,7 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab. # format to the repository Actions tab.
- name: "Upload artifact" - name: "Upload artifact"
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with: with:
name: SARIF file name: SARIF file
path: results.sarif path: results.sarif
@ -60,6 +60,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard. # Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning" - name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.29.5 uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # v3.29.5
with: with:
sarif_file: results.sarif sarif_file: results.sarif

View File

@ -32,7 +32,7 @@ jobs:
standard: 20 standard: 20
steps: steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Set timezone - name: Set timezone
run: tzutil /s "FLE Standard Time" run: tzutil /s "FLE Standard Time"
@ -79,7 +79,7 @@ jobs:
release: false release: false
msystem: ${{matrix.sys}} msystem: ${{matrix.sys}}
pacboy: cc:p cmake:p ninja:p lld:p pacboy: cc:p cmake:p ninja:p lld:p
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Configure - name: Configure
run: cmake -B ../build -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Debug run: cmake -B ../build -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Debug
env: { LDFLAGS: -fuse-ld=lld } env: { LDFLAGS: -fuse-ld=lld }

View File

@ -12,7 +12,7 @@
alternative to C stdio and C++ iostreams. alternative to C stdio and C++ iostreams.
If you like this project, please consider donating to one of the funds 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/>. that help victims of the war in Ukraine: <https://u24.gov.ua/>.
[Documentation](https://fmt.dev) [Documentation](https://fmt.dev)
@ -150,8 +150,8 @@ int main() {
} }
``` ```
This can be [5 to 9 times faster than This can be [up to 9 times faster than `fprintf`](
fprintf](http://www.zverovich.net/2020/08/04/optimal-file-buffer-size.html). http://www.zverovich.net/2020/08/04/optimal-file-buffer-size.html).
**Print with colors and text styles** **Print with colors and text styles**
@ -178,17 +178,17 @@ Output on a modern terminal with Unicode support:
| Library | Method | Run Time, s | | Library | Method | Run Time, s |
|-------------------|---------------|-------------| |-------------------|---------------|-------------|
| libc | printf | 0.91 | | libc | printf | 0.66 |
| libc++ | std::ostream | 2.49 | | libc++ | std::ostream | 1.63 |
| {fmt} 9.1 | fmt::print | 0.74 | | {fmt} 12.1 | fmt::print | 0.44 |
| Boost Format 1.80 | boost::format | 6.26 | | Boost Format 1.88 | boost::format | 3.89 |
| Folly Format | folly::format | 1.87 | | Folly Format | folly::format | 1.28 |
{fmt} is the fastest of the benchmarked methods, \~20% faster than {fmt} is the fastest of the benchmarked methods, \~50% faster than
`printf`. `printf`.
The above results were generated by building `tinyformat_test.cpp` on The above results were generated by building `tinyformat_test.cpp` on
macOS 12.6.1 with `clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT`, and macOS 15.6.1 with `clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT`, and
taking the best of three runs. In the test, the format string 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 `"%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 times with output sent to `/dev/null`; for further details refer to the
@ -217,11 +217,11 @@ in the following tables.
**Optimized build (-O3)** **Optimized build (-O3)**
| Method | Compile Time, s | Executable size, KiB | Stripped size, KiB | | Method | Compile Time, s | Executable size, KiB | Stripped size, KiB |
|---------------|-----------------|----------------------|--------------------| |-----------------|-----------------|----------------------|--------------------|
| printf | 1.6 | 54 | 50 | | printf | 1.6 | 54 | 50 |
| IOStreams | 25.9 | 98 | 84 | | IOStreams | 28.4 | 98 | 84 |
| fmt 83652df | 4.8 | 54 | 50 | | {fmt} `1122268` | 5.0 | 54 | 50 |
| tinyformat | 29.1 | 161 | 136 | | tinyformat | 32.6 | 164 | 136 |
| Boost Format | 55.0 | 530 | 317 | | Boost Format | 55.0 | 530 | 317 |
{fmt} is fast to compile and is comparable to `printf` in terms of per-call {fmt} is fast to compile and is comparable to `printf` in terms of per-call
@ -230,12 +230,12 @@ binary size (within a rounding error on this system).
**Non-optimized build** **Non-optimized build**
| Method | Compile Time, s | Executable size, KiB | Stripped size, KiB | | Method | Compile Time, s | Executable size, KiB | Stripped size, KiB |
|---------------|-----------------|----------------------|--------------------| |-----------------|-----------------|----------------------|--------------------|
| printf | 1.4 | 54 | 50 | | printf | 1.4 | 54 | 50 |
| IOStreams | 23.4 | 92 | 68 | | IOStreams | 27.0 | 88 | 68 |
| {fmt} 83652df | 4.4 | 89 | 85 | | {fmt} `1122268` | 4.7 | 87 | 84 |
| tinyformat | 24.5 | 204 | 161 | | tinyformat | 28.1 | 185 | 145 |
| Boost Format | 36.4 | 831 | 462 | | Boost Format | 38.9 | 678 | 381 |
`libc`, `lib(std)c++`, and `libfmt` are all linked as shared libraries `libc`, `lib(std)c++`, and `libfmt` are all linked as shared libraries
to compare formatting function overhead only. Boost Format is a to compare formatting function overhead only. Boost Format is a

View File

@ -624,6 +624,8 @@ Example:
::: ostream ::: ostream
::: output_file(cstring_view, T...)
::: windows_error ::: windows_error
<a id="ostream-api"></a> <a id="ostream-api"></a>
@ -706,7 +708,7 @@ following differences:
precision that provides round-trip guarantees similarly to other languages precision that provides round-trip guarantees similarly to other languages
like Java and Python. `std::format` is currently specified in terms of like Java and Python. `std::format` is currently specified in terms of
`std::to_chars` which tries to generate the smallest number of characters `std::to_chars` which tries to generate the smallest number of characters
(ignoring redundant digits and sign in exponent) and may procude more (ignoring redundant digits and sign in exponent) and may produce more
decimal digits than necessary. decimal digits than necessary.
## Configuration Options ## Configuration Options
@ -746,7 +748,7 @@ configuring CMake.
- `0` - off (default) - `0` - off (default)
- `1` - disables locale support and applies some optimizations - `1` - disables locale support and applies some optimizations
- `2` - disables some Unicode features, named arguments and applies more - `2` - disables some Unicode features, named arguments and applies more
aggresive optimizations aggressive optimizations
### Binary Size Optimization ### Binary Size Optimization

View File

@ -20,6 +20,7 @@
margin-left: 1em; margin-left: 1em;
} }
code,
pre > code.decl { pre > code.decl {
white-space: pre-wrap; white-space: pre-wrap;
} }

View File

@ -76,7 +76,7 @@ hide:
<p> <p>
The default is <b>locale-independent</b>, but you can opt into localized The default is <b>locale-independent</b>, but you can opt into localized
formatting and {fmt} makes it work with Unicode, addressing issues in the formatting and {fmt} makes it work with Unicode, addressing issues in the
standard libary. standard library.
</p> </p>
</div> </div>

View File

@ -233,7 +233,6 @@
FMT_PRAGMA_GCC(push_options) FMT_PRAGMA_GCC(push_options)
#if !defined(__OPTIMIZE__) && !defined(__CUDACC__) && !defined(FMT_MODULE) #if !defined(__OPTIMIZE__) && !defined(__CUDACC__) && !defined(FMT_MODULE)
FMT_PRAGMA_GCC(optimize("Og")) FMT_PRAGMA_GCC(optimize("Og"))
# define FMT_GCC_OPTIMIZED
#endif #endif
FMT_PRAGMA_CLANG(diagnostic push) FMT_PRAGMA_CLANG(diagnostic push)
FMT_PRAGMA_GCC(diagnostic push) FMT_PRAGMA_GCC(diagnostic push)
@ -246,7 +245,7 @@ FMT_PRAGMA_GCC(diagnostic push)
# define FMT_ALWAYS_INLINE inline # define FMT_ALWAYS_INLINE inline
#endif #endif
// A version of FMT_ALWAYS_INLINE to prevent code bloat in debug mode. // A version of FMT_ALWAYS_INLINE to prevent code bloat in debug mode.
#if defined(NDEBUG) || defined(FMT_GCC_OPTIMIZED) #ifdef NDEBUG
# define FMT_INLINE FMT_ALWAYS_INLINE # define FMT_INLINE FMT_ALWAYS_INLINE
#else #else
# define FMT_INLINE inline # define FMT_INLINE inline
@ -927,7 +926,7 @@ class locale_ref {
template <typename Locale, FMT_ENABLE_IF(sizeof(Locale::collate) != 0)> template <typename Locale, FMT_ENABLE_IF(sizeof(Locale::collate) != 0)>
locale_ref(const Locale& loc) : locale_(&loc) { locale_ref(const Locale& loc) : locale_(&loc) {
// Check if std::isalpha is found via ADL to reduce the chance of misuse. // Check if std::isalpha is found via ADL to reduce the chance of misuse.
isalpha('x', loc); detail::ignore_unused(sizeof(isalpha('x', loc)));
} }
inline explicit operator bool() const noexcept { return locale_ != nullptr; } inline explicit operator bool() const noexcept { return locale_ != nullptr; }
@ -1851,8 +1850,7 @@ template <typename T> class buffer {
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1940 #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1940
FMT_CONSTEXPR20 FMT_CONSTEXPR20
#endif #endif
void void append(const U* begin, const U* end) {
append(const U* begin, const U* end) {
while (begin != end) { while (begin != end) {
auto size = size_; auto size = size_;
auto free_cap = capacity_ - size; auto free_cap = capacity_ - size;
@ -2756,7 +2754,9 @@ template <typename... T> struct fstring {
static_assert(count<(is_view<remove_cvref_t<T>>::value && static_assert(count<(is_view<remove_cvref_t<T>>::value &&
std::is_reference<T>::value)...>() == 0, std::is_reference<T>::value)...>() == 0,
"passing views as lvalues is disallowed"); "passing views as lvalues is disallowed");
if (FMT_USE_CONSTEVAL) parse_format_string<char>(s, checker(s, arg_pack())); #if FMT_USE_CONSTEVAL
parse_format_string<char>(s, checker(s, arg_pack()));
#endif
#ifdef FMT_ENFORCE_COMPILE_STRING #ifdef FMT_ENFORCE_COMPILE_STRING
static_assert( static_assert(
FMT_USE_CONSTEVAL && sizeof(s) != 0, FMT_USE_CONSTEVAL && sizeof(s) != 0,

View File

@ -522,7 +522,7 @@ auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args)
-> format_to_n_result<OutputIt> { -> format_to_n_result<OutputIt> {
using traits = detail::fixed_buffer_traits; using traits = detail::fixed_buffer_traits;
auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n); auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n);
fmt::format_to(std::back_inserter(buf), fmt, std::forward<T>(args)...); fmt::format_to(appender(buf), fmt, std::forward<T>(args)...);
return {buf.out(), buf.count()}; return {buf.out(), buf.count()};
} }
@ -559,8 +559,8 @@ template <size_t N> class static_format_result {
*fmt::format_to(data, fmt, std::forward<T>(args)...) = '\0'; *fmt::format_to(data, fmt, std::forward<T>(args)...) = '\0';
} }
auto str() const -> fmt::string_view { return {data, N - 1}; } FMT_CONSTEXPR auto str() const -> fmt::string_view { return {data, N - 1}; }
auto c_str() const -> const char* { return data; } FMT_CONSTEXPR auto c_str() const -> const char* { return data; }
}; };
/** /**

View File

@ -30,6 +30,14 @@
# define FMT_FUNC # define FMT_FUNC
#endif #endif
#if defined(FMT_USE_FULL_CACHE_DRAGONBOX)
// Use the provided definition.
#elif defined(__OPTIMIZE_SIZE__)
# define FMT_USE_FULL_CACHE_DRAGONBOX 0
#else
# define FMT_USE_FULL_CACHE_DRAGONBOX 1
#endif
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
#ifndef FMT_CUSTOM_ASSERT_FAIL #ifndef FMT_CUSTOM_ASSERT_FAIL

View File

@ -493,8 +493,8 @@ template <typename OutputIt,
#if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION #if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION
__attribute__((no_sanitize("undefined"))) __attribute__((no_sanitize("undefined")))
#endif #endif
FMT_CONSTEXPR20 inline auto FMT_CONSTEXPR20 inline auto reserve(OutputIt it, size_t n) ->
reserve(OutputIt it, size_t n) -> typename OutputIt::value_type* { typename OutputIt::value_type* {
auto& c = get_container(it); auto& c = get_container(it);
size_t size = c.size(); size_t size = c.size();
c.resize(size + n); c.resize(size + n);
@ -736,12 +736,8 @@ using fast_float_t = conditional_t<sizeof(T) == sizeof(double), double, float>;
template <typename T> template <typename T>
using is_double_double = bool_constant<std::numeric_limits<T>::digits == 106>; using is_double_double = bool_constant<std::numeric_limits<T>::digits == 106>;
#ifndef FMT_USE_FULL_CACHE_DRAGONBOX
# define FMT_USE_FULL_CACHE_DRAGONBOX 0
#endif
// An allocator that uses malloc/free to allow removing dependency on the C++ // An allocator that uses malloc/free to allow removing dependency on the C++
// standard libary runtime. std::decay is used for back_inserter to be found by // standard library runtime. std::decay is used for back_inserter to be found by
// ADL when applied to memory_buffer. // ADL when applied to memory_buffer.
template <typename T> struct allocator : private std::decay<void> { template <typename T> struct allocator : private std::decay<void> {
using value_type = T; using value_type = T;
@ -1311,7 +1307,13 @@ class utf8_to_utf16 {
inline auto str() const -> std::wstring { return {&buffer_[0], size()}; } inline auto str() const -> std::wstring { return {&buffer_[0], size()}; }
}; };
enum class to_utf8_error_policy { abort, replace }; enum class to_utf8_error_policy { abort, replace, wtf };
inline void to_utf8_3bytes(buffer<char>& buf, uint32_t cp) {
buf.push_back(static_cast<char>(0xe0 | (cp >> 12)));
buf.push_back(static_cast<char>(0x80 | ((cp & 0xfff) >> 6)));
buf.push_back(static_cast<char>(0x80 | (cp & 0x3f)));
}
// A converter from UTF-16/UTF-32 (host endian) to UTF-8. // A converter from UTF-16/UTF-32 (host endian) to UTF-8.
template <typename WChar, typename Buffer = memory_buffer> class to_utf8 { template <typename WChar, typename Buffer = memory_buffer> class to_utf8 {
@ -1353,8 +1355,13 @@ template <typename WChar, typename Buffer = memory_buffer> class to_utf8 {
// Handle a surrogate pair. // Handle a surrogate pair.
++p; ++p;
if (p == s.end() || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) { if (p == s.end() || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) {
if (policy == to_utf8_error_policy::abort) return false; switch (policy) {
case to_utf8_error_policy::abort: return false;
case to_utf8_error_policy::replace:
buf.append(string_view("\xEF\xBF\xBD")); buf.append(string_view("\xEF\xBF\xBD"));
break;
case to_utf8_error_policy::wtf: to_utf8_3bytes(buf, c); break;
}
--p; --p;
continue; continue;
} }
@ -1366,9 +1373,7 @@ template <typename WChar, typename Buffer = memory_buffer> class to_utf8 {
buf.push_back(static_cast<char>(0xc0 | (c >> 6))); buf.push_back(static_cast<char>(0xc0 | (c >> 6)));
buf.push_back(static_cast<char>(0x80 | (c & 0x3f))); buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
} else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) { } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) {
buf.push_back(static_cast<char>(0xe0 | (c >> 12))); to_utf8_3bytes(buf, c);
buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
} else if (c >= 0x10000 && c <= 0x10ffff) { } else if (c >= 0x10000 && c <= 0x10ffff) {
buf.push_back(static_cast<char>(0xf0 | (c >> 18))); buf.push_back(static_cast<char>(0xf0 | (c >> 18)));
buf.push_back(static_cast<char>(0x80 | ((c & 0x3ffff) >> 12))); buf.push_back(static_cast<char>(0x80 | ((c & 0x3ffff) >> 12)));
@ -2534,7 +2539,7 @@ FMT_CONSTEXPR20 auto write_fixed(OutputIt out, const DecimalFP& f,
auto grouping = Grouping(loc, specs.localized()); auto grouping = Grouping(loc, specs.localized());
size += grouping.count_separators(exp); size += grouping.count_separators(exp);
return write_padded<Char, align::right>( return write_padded<Char, align::right>(
out, specs, to_unsigned(size), [&](iterator it) { out, specs, static_cast<size_t>(size), [&](iterator it) {
if (s != sign::none) *it++ = detail::getsign<Char>(s); if (s != sign::none) *it++ = detail::getsign<Char>(s);
it = write_significand(it, f.significand, significand_size, exp, it = write_significand(it, f.significand, significand_size, exp,
decimal_point, grouping); decimal_point, grouping);
@ -2550,7 +2555,7 @@ FMT_CONSTEXPR20 auto write_fixed(OutputIt out, const DecimalFP& f,
bool pointy = num_zeros != 0 || significand_size != 0 || specs.alt(); bool pointy = num_zeros != 0 || significand_size != 0 || specs.alt();
size += 1 + (pointy ? 1 : 0) + num_zeros; size += 1 + (pointy ? 1 : 0) + num_zeros;
return write_padded<Char, align::right>( return write_padded<Char, align::right>(
out, specs, to_unsigned(size), [&](iterator it) { out, specs, static_cast<size_t>(size), [&](iterator it) {
if (s != sign::none) *it++ = detail::getsign<Char>(s); if (s != sign::none) *it++ = detail::getsign<Char>(s);
*it++ = Char('0'); *it++ = Char('0');
if (!pointy) return it; if (!pointy) return it;
@ -2594,7 +2599,7 @@ FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f,
*it++ = Char(exp_char); *it++ = Char(exp_char);
return write_exponent<Char>(exp, it); return write_exponent<Char>(exp, it);
}; };
auto usize = to_unsigned(size); size_t usize = static_cast<size_t>(size);
return specs.width > 0 return specs.width > 0
? write_padded<Char, align::right>(out, specs, usize, write) ? write_padded<Char, align::right>(out, specs, usize, write)
: base_iterator(out, write(reserve(out, usize))); : base_iterator(out, write(reserve(out, usize)));
@ -4248,7 +4253,11 @@ class format_int {
* // A compile-time error because 'd' is an invalid specifier for strings. * // A compile-time error because 'd' is an invalid specifier for strings.
* std::string s = fmt::format(FMT_STRING("{:d}"), "foo"); * std::string s = fmt::format(FMT_STRING("{:d}"), "foo");
*/ */
#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string) #if FMT_USE_CONSTEVAL
# define FMT_STRING(s) s
#else
# define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string)
#endif // FMT_USE_CONSTEVAL
FMT_API auto vsystem_error(int error_code, string_view fmt, format_args args) FMT_API auto vsystem_error(int error_code, string_view fmt, format_args args)
-> std::system_error; -> std::system_error;

View File

@ -161,14 +161,6 @@ inline auto system_category() noexcept -> const std::error_category& {
} }
#endif // _WIN32 #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& fmt, Args&&... args) {
std::system(format("say \"{}\"", format(fmt, args...)).c_str());
}
#endif
// A buffered file. // A buffered file.
class buffered_file { class buffered_file {
private: private:

View File

@ -38,7 +38,7 @@ namespace detail {
namespace { namespace {
struct file_access_tag {}; struct file_access_tag {};
} // namespace } // namespace
template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr> template <typename Tag, typename BufType, FILE* BufType::* FileMemberPtr>
class file_access { class file_access {
friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; } friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
}; };

View File

@ -84,10 +84,12 @@ namespace detail {
template <typename Char, typename PathChar> template <typename Char, typename PathChar>
auto get_path_string(const std::filesystem::path& p, auto get_path_string(const std::filesystem::path& p,
const std::basic_string<PathChar>& native) { const std::basic_string<PathChar>& native) {
if constexpr (std::is_same_v<Char, char> && std::is_same_v<PathChar, wchar_t>) if constexpr (std::is_same_v<Char, char> &&
return to_utf8<wchar_t>(native, to_utf8_error_policy::replace); std::is_same_v<PathChar, wchar_t>) {
else return to_utf8<wchar_t>(native, to_utf8_error_policy::wtf);
} else {
return p.string<Char>(); return p.string<Char>();
}
} }
template <typename Char, typename PathChar> template <typename Char, typename PathChar>
@ -645,6 +647,11 @@ struct formatter<std::atomic_flag, Char> : formatter<bool, Char> {
}; };
#endif // __cpp_lib_atomic_flag_test #endif // __cpp_lib_atomic_flag_test
template <typename T> struct is_tuple_like;
template <typename T>
struct is_tuple_like<std::complex<T>> : std::false_type {};
template <typename T, typename Char> struct formatter<std::complex<T>, Char> { template <typename T, typename Char> struct formatter<std::complex<T>, Char> {
private: private:
detail::dynamic_format_specs<Char> specs_; detail::dynamic_format_specs<Char> specs_;

View File

@ -34,8 +34,8 @@ tag_map = {
'emphasis': 'em', 'emphasis': 'em',
'computeroutput': 'code', 'computeroutput': 'code',
'para': 'p', 'para': 'p',
'programlisting': 'pre', 'itemizedlist': 'ul',
'verbatim': 'pre' 'listitem': 'li'
} }
# A map from Doxygen tags to text. # A map from Doxygen tags to text.
@ -50,21 +50,37 @@ def escape_html(s: str) -> str:
return s.replace("<", "&lt;") return s.replace("<", "&lt;")
# Converts a node from doxygen to HTML format.
def convert_node(node: ElementTree.Element, tag: str, attrs: dict = {}):
out = '<' + tag
for key, value in attrs.items():
out += ' ' + key + '="' + value + '"'
out += '>'
if node.text:
out += escape_html(node.text)
out += doxyxml2html(list(node))
out += '</' + tag + '>'
if node.tail:
out += node.tail
return out
def doxyxml2html(nodes: List[ElementTree.Element]): def doxyxml2html(nodes: List[ElementTree.Element]):
out = '' out = ''
for n in nodes: for n in nodes:
tag = tag_map.get(n.tag) tag = tag_map.get(n.tag)
if not tag: if tag:
out += convert_node(n, tag)
continue
if n.tag == 'programlisting' or n.tag == 'verbatim':
out += '<pre>'
out += convert_node(n, 'code', {'class': 'language-cpp'})
out += '</pre>'
continue
if n.tag == 'ulink':
out += convert_node(n, 'a', {'href': n.attrib['url']})
continue
out += tag_text_map[n.tag] out += tag_text_map[n.tag]
out += '<' + tag + '>' if tag else ''
out += '<code class="language-cpp">' if tag == 'pre' else ''
if n.text:
out += escape_html(n.text)
out += doxyxml2html(list(n))
out += '</code>' if tag == 'pre' else ''
out += '</' + tag + '>' if tag else ''
if n.tail:
out += n.tail
return out return out

View File

@ -62,11 +62,6 @@ if (NOT (MSVC AND BUILD_SHARED_LIBS))
endif () endif ()
add_fmt_test(ostream-test) add_fmt_test(ostream-test)
add_fmt_test(compile-test) add_fmt_test(compile-test)
add_fmt_test(compile-fp-test)
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(printf-test)
add_fmt_test(ranges-test ranges-odr-test.cc) add_fmt_test(ranges-test ranges-odr-test.cc)
add_fmt_test(no-builtin-types-test HEADER_ONLY) add_fmt_test(no-builtin-types-test HEADER_ONLY)

View File

@ -1,62 +0,0 @@
// 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 FMT_USE_CONSTEVAL
template <size_t max_string_length, typename Char = char> struct test_string {
Char buffer[max_string_length] = {};
template <typename T> constexpr bool operator==(const T& rhs) const noexcept {
return fmt::basic_string_view<Char>(rhs).compare(buffer) == 0;
}
};
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 // FMT_USE_CONSTEVAL

View File

@ -90,9 +90,6 @@ TEST(compile_test, format_escape) {
EXPECT_EQ("\"abc\" ", fmt::format(FMT_COMPILE("{0:<7?}"), "abc")); EXPECT_EQ("\"abc\" ", fmt::format(FMT_COMPILE("{0:<7?}"), "abc"));
} }
TEST(compile_test, format_wide_string) {
EXPECT_EQ(L"42", fmt::format(FMT_COMPILE(L"{}"), 42));
}
TEST(compile_test, format_specs) { TEST(compile_test, format_specs) {
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42)); EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42));
@ -124,7 +121,6 @@ TEST(compile_test, manual_ordering) {
"true 42 42 foo 0x1234 foo", "true 42 42 foo 0x1234 foo",
fmt::format(FMT_COMPILE("{0} {1} {2} {3} {4} {5}"), true, 42, 42.0f, fmt::format(FMT_COMPILE("{0} {1} {2} {3} {4} {5}"), true, 42, 42.0f,
"foo", reinterpret_cast<void*>(0x1234), test_formattable())); "foo", reinterpret_cast<void*>(0x1234), test_formattable()));
EXPECT_EQ(L"42", fmt::format(FMT_COMPILE(L"{0}"), 42));
} }
TEST(compile_test, named) { TEST(compile_test, named) {
@ -133,10 +129,6 @@ TEST(compile_test, named) {
static_assert(std::is_same_v<decltype(runtime_named_field_compiled), static_assert(std::is_same_v<decltype(runtime_named_field_compiled),
fmt::detail::runtime_named_field<char>>); 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", EXPECT_EQ("foobar",
fmt::format(FMT_COMPILE("{a0}{a1}"), fmt::arg("a0", "foo"), fmt::format(FMT_COMPILE("{a0}{a1}"), fmt::arg("a0", "foo"),
fmt::arg("a1", "bar"))); fmt::arg("a1", "bar")));
@ -318,7 +310,6 @@ TEST(compile_test, compile_format_string_literal) {
using namespace fmt::literals; using namespace fmt::literals;
EXPECT_EQ("", fmt::format(""_cf)); EXPECT_EQ("", fmt::format(""_cf));
EXPECT_EQ("42", fmt::format("{}"_cf, 42)); EXPECT_EQ("42", fmt::format("{}"_cf, 42));
EXPECT_EQ(L"42", fmt::format(L"{}"_cf, 42));
} }
#endif #endif
@ -426,6 +417,40 @@ TEST(compile_time_formatting_test, custom_type) {
TEST(compile_time_formatting_test, multibyte_fill) { TEST(compile_time_formatting_test, multibyte_fill) {
EXPECT_EQ("жж42", test_format<8>(FMT_COMPILE("{:ж>4}"), 42)); EXPECT_EQ("жж42", test_format<8>(FMT_COMPILE("{:ж>4}"), 42));
} }
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 #endif
#if FMT_USE_CONSTEXPR_STRING #if FMT_USE_CONSTEXPR_STRING

View File

@ -2036,11 +2036,6 @@ TEST(format_test, unpacked_args) {
6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f', 'g')); 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f', 'g'));
} }
constexpr char with_null[3] = {'{', '}', '\0'};
constexpr char no_null[2] = {'{', '}'};
static constexpr char static_with_null[3] = {'{', '}', '\0'};
static constexpr char static_no_null[2] = {'{', '}'};
TEST(format_test, compile_time_string) { TEST(format_test, compile_time_string) {
EXPECT_EQ(fmt::format(FMT_STRING("foo")), "foo"); EXPECT_EQ(fmt::format(FMT_STRING("foo")), "foo");
EXPECT_EQ(fmt::format(FMT_STRING("{}"), 42), "42"); EXPECT_EQ(fmt::format(FMT_STRING("{}"), 42), "42");
@ -2055,19 +2050,12 @@ TEST(format_test, compile_time_string) {
EXPECT_EQ(fmt::format(FMT_STRING("{} {two}"), 1, "two"_a = 2), "1 2"); EXPECT_EQ(fmt::format(FMT_STRING("{} {two}"), 1, "two"_a = 2), "1 2");
#endif #endif
(void)static_with_null; static constexpr char format_str[3] = {'{', '}', '\0'};
(void)static_no_null; (void)format_str;
#ifndef _MSC_VER #ifndef _MSC_VER
EXPECT_EQ(fmt::format(FMT_STRING(static_with_null), 42), "42"); EXPECT_EQ(fmt::format(FMT_STRING(format_str), 42), "42");
EXPECT_EQ(fmt::format(FMT_STRING(static_no_null), 42), "42");
#endif #endif
(void)with_null;
(void)no_null;
#if FMT_CPLUSPLUS >= 201703L
EXPECT_EQ(fmt::format(FMT_STRING(with_null), 42), "42");
EXPECT_EQ(fmt::format(FMT_STRING(no_null), 42), "42");
#endif
#if defined(FMT_USE_STRING_VIEW) && FMT_CPLUSPLUS >= 201703L #if defined(FMT_USE_STRING_VIEW) && FMT_CPLUSPLUS >= 201703L
EXPECT_EQ(fmt::format(FMT_STRING(std::string_view("{}")), 42), "42"); EXPECT_EQ(fmt::format(FMT_STRING(std::string_view("{}")), 42), "42");
#endif #endif

View File

@ -12,10 +12,10 @@ void invoke_inner(fmt::string_view format_str, Rep rep) {
auto value = std::chrono::duration<Rep, Period>(rep); auto value = std::chrono::duration<Rep, Period>(rep);
try { try {
#if FMT_FUZZ_FORMAT_TO_STRING #if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(format_str, value); std::string message = fmt::format(fmt::runtime(format_str), value);
#else #else
auto buf = fmt::memory_buffer(); auto buf = fmt::memory_buffer();
fmt::format_to(std::back_inserter(buf), format_str, value); fmt::format_to(std::back_inserter(buf), fmt::runtime(format_str), value);
#endif #endif
} catch (std::exception&) { } catch (std::exception&) {
} }

View File

@ -22,7 +22,7 @@
#define FMT_FUZZ_SEPARATE_ALLOCATION 1 #define FMT_FUZZ_SEPARATE_ALLOCATION 1
// The size of the largest possible type in use. // The size of the largest possible type in use.
// To let the the fuzzer mutation be efficient at cross pollinating between // To let the fuzzer mutation be efficient at cross pollinating between
// different types, use a fixed size format. The same bit pattern, interpreted // different types, use a fixed size format. The same bit pattern, interpreted
// as another type, is likely interesting. // as another type, is likely interesting.
constexpr auto fixed_size = 16; constexpr auto fixed_size = 16;

View File

@ -265,7 +265,7 @@ template <> struct formatter<abstract> : ostream_formatter {};
} // namespace fmt } // namespace fmt
void format_abstract_compiles(const abstract& a) { void format_abstract_compiles(const abstract& a) {
fmt::format(FMT_COMPILE("{}"), a); (void)fmt::format(FMT_COMPILE("{}"), a);
} }
TEST(ostream_test, is_formattable) { TEST(ostream_test, is_formattable) {

View File

@ -39,13 +39,12 @@ TEST(std_test, path) {
EXPECT_EQ(fmt::format("{}", path(L"\x0428\x0447\x0443\x0447\x044B\x043D\x0448" EXPECT_EQ(fmt::format("{}", path(L"\x0428\x0447\x0443\x0447\x044B\x043D\x0448"
L"\x0447\x044B\x043D\x0430")), L"\x0447\x044B\x043D\x0430")),
"Шчучыншчына"); "Шчучыншчына");
EXPECT_EQ(fmt::format("{}", path(L"\xd800")), "<EFBFBD>"); EXPECT_EQ(fmt::format("{}", path(L"\xD800")), "\xED\xA0\x80");
EXPECT_EQ(fmt::format("{}", path(L"HEAD \xd800 TAIL")), "HEAD <20> TAIL"); EXPECT_EQ(fmt::format("{}", path(L"[\xD800]")), "[\xED\xA0\x80]");
EXPECT_EQ(fmt::format("{}", path(L"HEAD \xD83D\xDE00 TAIL")), EXPECT_EQ(fmt::format("{}", path(L"[\xD83D\xDE00]")), "[\xF0\x9F\x98\x80]");
"HEAD \xF0\x9F\x98\x80 TAIL"); EXPECT_EQ(fmt::format("{}", path(L"[\xD83D\xD83D\xDE00]")),
EXPECT_EQ(fmt::format("{}", path(L"HEAD \xD83D\xD83D\xDE00 TAIL")), "[\xED\xA0\xBD\xF0\x9F\x98\x80]");
"HEAD <20>\xF0\x9F\x98\x80 TAIL"); EXPECT_EQ(fmt::format("{:?}", path(L"\xD800")), "\"\\ud800\"");
EXPECT_EQ(fmt::format("{:?}", path(L"\xd800")), "\"\\ud800\"");
# endif # endif
} }