mirror of
https://github.com/fmtlib/fmt.git
synced 2025-12-06 16:57:03 +08:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6e871e39b | ||
|
|
e137db699a | ||
|
|
d6712ff2c0 | ||
|
|
2d839bbc61 | ||
|
|
5bc56e24a9 | ||
|
|
2727215c11 | ||
|
|
790b9389ae | ||
|
|
a731c73fd5 | ||
|
|
3391f9e992 | ||
|
|
9f197b22ae | ||
|
|
f20b16617e | ||
|
|
14451704d5 | ||
|
|
7a0da1c68a | ||
|
|
e3d2174b3c | ||
|
|
a6fb4d3b06 | ||
|
|
706fecea30 | ||
|
|
e00fd756cc | ||
|
|
fc17e825d9 | ||
|
|
3fccfb8a80 | ||
|
|
690c9c71a0 | ||
|
|
1122268510 | ||
|
|
a4c7e17133 | ||
|
|
bfd0129b91 | ||
|
|
62f57b2496 | ||
|
|
ef7a566413 | ||
|
|
42840cb415 | ||
|
|
5ac44cd128 | ||
|
|
23c13b3060 | ||
|
|
29c46fb82d | ||
|
|
a0571f3f59 | ||
|
|
a195dd6b37 | ||
|
|
33ad559eb8 | ||
|
|
b6cd356196 | ||
|
|
c3be070b7e | ||
|
|
27bf8b47fe |
2
.github/workflows/cifuzz.yml
vendored
2
.github/workflows/cifuzz.yml
vendored
@ -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
|
||||||
|
|||||||
2
.github/workflows/doc.yml
vendored
2
.github/workflows/doc.yml
vendored
@ -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: |
|
||||||
|
|||||||
8
.github/workflows/lint.yml
vendored
8
.github/workflows/lint.yml
vendored
@ -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
|
||||||
|
|||||||
2
.github/workflows/linux.yml
vendored
2
.github/workflows/linux.yml
vendored
@ -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'
|
||||||
|
|||||||
9
.github/workflows/macos.yml
vendored
9
.github/workflows/macos.yml
vendored
@ -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'
|
||||||
|
|||||||
6
.github/workflows/scorecard.yml
vendored
6
.github/workflows/scorecard.yml
vendored
@ -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
|
||||||
|
|||||||
4
.github/workflows/windows.yml
vendored
4
.github/workflows/windows.yml
vendored
@ -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 }
|
||||||
|
|||||||
38
README.md
38
README.md
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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>
|
||||||
|
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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");
|
||||||
*/
|
*/
|
||||||
|
#if FMT_USE_CONSTEVAL
|
||||||
|
# define FMT_STRING(s) s
|
||||||
|
#else
|
||||||
# define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string)
|
# 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;
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -84,11 +84,13 @@ 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>
|
||||||
void write_escaped_path(basic_memory_buffer<Char>& quoted,
|
void write_escaped_path(basic_memory_buffer<Char>& quoted,
|
||||||
@ -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_;
|
||||||
|
|||||||
@ -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("<", "<")
|
return s.replace("<", "<")
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
|
||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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&) {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user