mirror of
https://github.com/fmtlib/fmt.git
synced 2026-07-30 16:26:27 +08:00
Merge branch 'main' into libcxx-fix
This commit is contained in:
commit
6a0e898ae0
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
@ -0,0 +1 @@
|
||||
* @vitaut
|
||||
8
.github/SECURITY.md
vendored
Normal file
8
.github/SECURITY.md
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Security Policy
|
||||
|
||||
To report a security issue, please disclose it at [security
|
||||
advisory](https://github.com/fmtlib/fmt/security/advisories/new).
|
||||
|
||||
This project is maintained by a team of volunteers on a
|
||||
reasonable-effort basis. As such, please give us at least 90 days to
|
||||
work on a fix before public disclosure.
|
||||
33
.github/workflows/codeql.yml
vendored
Normal file
33
.github/workflows/codeql.yml
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
name: codeql
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
actions: read
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- uses: github/codeql-action/init@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v3.29.5
|
||||
with:
|
||||
languages: c-cpp
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake -B build -DFMT_DOC=OFF -DFMT_TEST=OFF
|
||||
cmake --build build --parallel
|
||||
|
||||
- uses: github/codeql-action/analyze@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v3.29.5
|
||||
with:
|
||||
category: /language:c-cpp
|
||||
6
.github/workflows/doc.yml
vendored
6
.github/workflows/doc.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Add Ubuntu mirrors
|
||||
run: |
|
||||
@ -24,7 +24,7 @@ jobs:
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install doxygen
|
||||
pip install mkdocs-material==9.7.0 mkdocstrings==1.0.0 mike==2.1.3 typing_extensions==4.15.0
|
||||
pip install --require-hashes -r support/doc-requirements.txt
|
||||
cmake -E make_directory ${{runner.workspace}}/build
|
||||
# Workaround https://github.com/actions/checkout/issues/13:
|
||||
git config --global user.name "$(git --no-pager log --format=format:'%an' -n 1)"
|
||||
@ -37,6 +37,6 @@ jobs:
|
||||
- name: Deploy
|
||||
env:
|
||||
KEY: "${{secrets.KEY}}"
|
||||
if: env.KEY != '' && github.ref == 'refs/heads/master'
|
||||
if: env.KEY != '' && github.ref == 'refs/heads/main'
|
||||
working-directory: ${{runner.workspace}}/fmt/build/fmt.dev
|
||||
run: git push https://$KEY@github.com/fmtlib/fmt.dev.git
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
name: CIFuzz
|
||||
name: fuzz
|
||||
on: [pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
Fuzzing:
|
||||
fuzz:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Build fuzzers
|
||||
23
.github/workflows/lint.yml
vendored
23
.github/workflows/lint.yml
vendored
@ -2,11 +2,6 @@ name: lint
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.h'
|
||||
- '**.cc'
|
||||
- '**.cmake'
|
||||
- '**/CMakeLists.txt'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@ -15,13 +10,19 @@ jobs:
|
||||
clang-format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Install clang-format
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
sudo bash ./llvm.sh 21
|
||||
sudo apt install clang-format-21
|
||||
sudo install -D -m 0644 support/llvm-snapshot.gpg.key \
|
||||
/etc/apt/keyrings/apt.llvm.org.asc
|
||||
codename=$(lsb_release -cs)
|
||||
echo "deb [signed-by=/etc/apt/keyrings/apt.llvm.org.asc]" \
|
||||
"https://apt.llvm.org/$codename/" \
|
||||
"llvm-toolchain-$codename-21 main" \
|
||||
| sudo tee /etc/apt/sources.list.d/llvm.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y clang-format-21
|
||||
|
||||
- name: Run clang-format
|
||||
run: |
|
||||
@ -32,10 +33,10 @@ jobs:
|
||||
cmake-format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Install cmake-format
|
||||
run: pip install cmakelang
|
||||
run: pip install --require-hashes -r support/cmake-format-requirements.txt
|
||||
|
||||
- name: Run cmake-format
|
||||
run: |
|
||||
|
||||
50
.github/workflows/linux.yml
vendored
50
.github/workflows/linux.yml
vendored
@ -7,7 +7,12 @@ permissions:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
name: >-
|
||||
${{matrix.cxx}} c++${{matrix.std}} ${{matrix.build_type}}
|
||||
${{matrix.gen}} ${{matrix.fuzz && 'Fuzz' || ''}}
|
||||
${{matrix.shared && 'Shared' || ''}}
|
||||
${{matrix.cxxflags_extra && 'Sanitize' || ''}}
|
||||
runs-on: ${{ matrix.os || 'ubuntu-22.04' }}
|
||||
strategy:
|
||||
matrix:
|
||||
cxx: [g++-4.9, g++-11, clang++-3.6, clang++-11]
|
||||
@ -16,7 +21,6 @@ jobs:
|
||||
shared: [""]
|
||||
include:
|
||||
- cxx: g++-4.9
|
||||
- cxx: clang++-3.6
|
||||
- cxx: g++-11
|
||||
build_type: Debug
|
||||
std: 14
|
||||
@ -31,8 +35,14 @@ jobs:
|
||||
- cxx: g++-13
|
||||
build_type: Release
|
||||
std: 23
|
||||
install: sudo apt install g++-13
|
||||
os: ubuntu-24.04
|
||||
shared: -DBUILD_SHARED_LIBS=ON
|
||||
- cxx: g++-14
|
||||
build_type: Release
|
||||
std: 23
|
||||
os: ubuntu-24.04
|
||||
gen: Ninja
|
||||
- cxx: clang++-3.6
|
||||
- cxx: clang++-11
|
||||
build_type: Debug
|
||||
std: 17
|
||||
@ -48,14 +58,22 @@ jobs:
|
||||
- cxx: clang++-14
|
||||
build_type: Debug
|
||||
std: 20
|
||||
cxxflags: -fsanitize=address
|
||||
cxxflags_extra: -fno-sanitize-recover=all -fno-omit-frame-pointer
|
||||
- cxx: clang++-14
|
||||
build_type: Debug
|
||||
std: 20
|
||||
cxxflags: -stdlib=libc++
|
||||
install: sudo apt install libc++-14-dev libc++abi-14-dev
|
||||
- cxx: clang++-20
|
||||
build_type: Debug
|
||||
std: 20
|
||||
cxxflags: -stdlib=libc++
|
||||
install: sudo apt install clang-20 libc++-20-dev libc++abi-20-dev
|
||||
gen: Ninja
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Set timezone
|
||||
run: sudo timedatectl set-timezone 'Europe/Kyiv'
|
||||
@ -126,10 +144,16 @@ jobs:
|
||||
clang-3.6_3.6.2-3ubuntu2_amd64.deb
|
||||
if: ${{ matrix.cxx == 'clang++-3.6' }}
|
||||
|
||||
- name: Add repositories for newer GCC
|
||||
- name: Install LLVM-20
|
||||
run: |
|
||||
sudo apt-add-repository ppa:ubuntu-toolchain-r/test
|
||||
if: ${{ matrix.cxx == 'g++-13' }}
|
||||
sudo install -D -m 0644 support/llvm-snapshot.gpg.key \
|
||||
/etc/apt/keyrings/apt.llvm.org.asc
|
||||
codename=$(lsb_release -cs)
|
||||
echo "deb [signed-by=/etc/apt/keyrings/apt.llvm.org.asc]" \
|
||||
"https://apt.llvm.org/$codename/" \
|
||||
"llvm-toolchain-$codename-20 main" \
|
||||
| sudo tee /etc/apt/sources.list.d/llvm.list
|
||||
if: ${{ matrix.cxx == 'clang++-20' }}
|
||||
|
||||
- name: Add Ubuntu mirrors
|
||||
run: |
|
||||
@ -154,14 +178,18 @@ jobs:
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
env:
|
||||
CXX: ${{matrix.cxx}}
|
||||
CXXFLAGS: ${{matrix.cxxflags}}
|
||||
CXXFLAGS: ${{matrix.cxxflags}} ${{matrix.cxxflags_extra}}
|
||||
run: |
|
||||
cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
|
||||
cmake ${{matrix.gen && '-G' || ''}} ${{matrix.gen}} \
|
||||
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
|
||||
-DCMAKE_CXX_STANDARD=${{matrix.std}} \
|
||||
-DCMAKE_CXX_VISIBILITY_PRESET=hidden \
|
||||
-DCMAKE_VISIBILITY_INLINES_HIDDEN=ON \
|
||||
-DFMT_DOC=OFF -DFMT_PEDANTIC=ON -DFMT_WERROR=ON \
|
||||
${{matrix.fuzz}} ${{matrix.shared}} $GITHUB_WORKSPACE
|
||||
-DFMT_DOC=OFF -DFMT_PEDANTIC=ON \
|
||||
-DFMT_WERROR=ON \
|
||||
${{matrix.fuzz}} \
|
||||
${{matrix.shared}} \
|
||||
$GITHUB_WORKSPACE
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
|
||||
5
.github/workflows/macos.yml
vendored
5
.github/workflows/macos.yml
vendored
@ -7,6 +7,9 @@ permissions:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: >-
|
||||
c++${{matrix.std }} ${{ matrix.build_type}}
|
||||
${{matrix.shared && 'Shared' || ''}}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-14]
|
||||
@ -22,7 +25,7 @@ jobs:
|
||||
runs-on: '${{ matrix.os }}'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Set timezone
|
||||
run: sudo systemsetup -settimezone 'Europe/Minsk'
|
||||
|
||||
143
.github/workflows/release.yml
vendored
Normal file
143
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
# Builds the release source package in CI for a draft release (typically
|
||||
# created via support/release.py), uploads the zip to that release, and
|
||||
# attaches a SLSA v1.0 provenance attestation generated by the OpenSSF
|
||||
# slsa-github-generator. The maintainer reviews the draft (which by then has
|
||||
# both the zip and *.intoto.jsonl attached) and clicks Publish to finalize.
|
||||
#
|
||||
# The source package includes the pre-rendered HTML documentation (doc-html/),
|
||||
# so this workflow builds the docs and stages them into the source tree before
|
||||
# running CPack's package_source target.
|
||||
#
|
||||
# This makes the provenance attest to the actual build that produced the
|
||||
# artifact, rather than just attesting to a hash observed after the fact.
|
||||
#
|
||||
# GitHub does not fire `release: created` for draft releases, so release.py
|
||||
# triggers this workflow explicitly via workflow_dispatch, passing the tag to
|
||||
# attach to and the ref to build from. The `release: created` trigger is kept
|
||||
# for non-draft releases created directly through the GitHub UI.
|
||||
|
||||
name: release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag_name:
|
||||
description: "Release tag to attach the artifacts to (e.g. 12.2.0)"
|
||||
required: true
|
||||
type: string
|
||||
ref:
|
||||
description: "Git ref to build the source package from"
|
||||
required: false
|
||||
default: release
|
||||
type: string
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build source package
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
outputs:
|
||||
hashes: ${{ steps.hash.outputs.hashes }}
|
||||
package: ${{ steps.build.outputs.package }}
|
||||
tag: ${{ steps.vars.outputs.tag }}
|
||||
steps:
|
||||
- name: Resolve tag and ref for both event types
|
||||
id: vars
|
||||
run: |
|
||||
echo "tag=${{ github.event.release.tag_name || inputs.tag_name }}" >> "$GITHUB_OUTPUT"
|
||||
echo "ref=${{ github.event.release.target_commitish || inputs.ref }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Checkout the release ref
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
ref: ${{ steps.vars.outputs.ref }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install the documentation toolchain
|
||||
# The source zip ships the pre-rendered HTML docs (doc-html/), so the
|
||||
# docs must be built before packaging. doxygen feeds the API reference;
|
||||
# mkdocs plus the pinned, hash-verified deps render the site. The venv
|
||||
# lives outside the checkout so it is not swept into the source zip, and
|
||||
# is added to PATH so CMake's find_program(MKDOCS) and the doxygen call
|
||||
# in the mkdocstrings handler both resolve in later steps.
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y doxygen
|
||||
python3 -m venv "$RUNNER_TEMP/doc-venv"
|
||||
"$RUNNER_TEMP/doc-venv/bin/pip" install --quiet --upgrade pip
|
||||
"$RUNNER_TEMP/doc-venv/bin/pip" install --quiet --require-hashes \
|
||||
-r support/doc-requirements.txt
|
||||
echo "$RUNNER_TEMP/doc-venv/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Build source zip via CPack
|
||||
id: build
|
||||
# Build the docs and stage the rendered site at the top level so the
|
||||
# CPack source package includes doc-html/. The build/ tree itself is
|
||||
# excluded by CPACK_SOURCE_IGNORE_FILES.
|
||||
run: |
|
||||
cmake -B build .
|
||||
cmake --build build --target doc
|
||||
cp -r build/doc-html doc-html
|
||||
cmake --build build --target package_source
|
||||
pkg=$(ls build/fmt-*.zip)
|
||||
test -f "$pkg"
|
||||
echo "package=$pkg" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Compute base64-encoded SHA-256 subjects
|
||||
id: hash
|
||||
run: |
|
||||
file="${{ steps.build.outputs.package }}"
|
||||
subjects=$(cd "$(dirname "$file")" && sha256sum "$(basename "$file")")
|
||||
echo "hashes=$(printf '%s' "$subjects" | base64 -w0)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Upload zip to the release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh release upload "${{ steps.vars.outputs.tag }}" \
|
||||
"${{ steps.build.outputs.package }}" \
|
||||
--repo "${{ github.repository }}" --clobber
|
||||
|
||||
# Generate the provenance only; do not let the generator upload it. With
|
||||
# upload-assets, the generator creates and publishes its own release (and
|
||||
# tag) to host the attestation, which duplicates our draft. Instead we
|
||||
# download the attestation artifact and attach it to the draft below.
|
||||
provenance:
|
||||
needs: [build]
|
||||
permissions:
|
||||
actions: read
|
||||
id-token: write
|
||||
# contents: write is required because the generator's (skipped)
|
||||
# upload-assets job declares it, and a reusable workflow's job
|
||||
# permissions may not exceed the caller's, or the run fails at startup.
|
||||
contents: write
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0
|
||||
with:
|
||||
base64-subjects: ${{ needs.build.outputs.hashes }}
|
||||
provenance-name: "fmt-${{ needs.build.outputs.tag }}.intoto.jsonl"
|
||||
upload-assets: false
|
||||
|
||||
attach-provenance:
|
||||
name: Attach provenance to the release
|
||||
needs: [build, provenance]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Download the provenance attestation
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: ${{ needs.provenance.outputs.provenance-name }}
|
||||
|
||||
- name: Attach provenance to the draft release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh release upload "${{ needs.build.outputs.tag }}" \
|
||||
"${{ needs.provenance.outputs.provenance-name }}" \
|
||||
--repo "${{ github.repository }}" --clobber
|
||||
@ -1,9 +1,6 @@
|
||||
# This workflow uses actions that are not certified by GitHub. They are provided
|
||||
# by a third-party and are governed by separate terms of service, privacy
|
||||
# policy, and support documentation.
|
||||
|
||||
name: Scorecard supply-chain security
|
||||
name: supply-chain
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# For Branch-Protection check. Only the default branch is supported. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
|
||||
branch_protection_rule:
|
||||
@ -12,14 +9,13 @@ on:
|
||||
schedule:
|
||||
- cron: '26 14 * * 5'
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
branches: [main]
|
||||
|
||||
# Declare default permissions as read only.
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
name: Scorecard analysis
|
||||
scorecard:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# Needed to upload the results to code-scanning dashboard.
|
||||
@ -28,20 +24,15 @@ jobs:
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
- name: Run analysis
|
||||
uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
|
||||
# - you want to enable the Branch-Protection check on a *public* repository, or
|
||||
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
|
||||
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
|
||||
|
||||
# Public repositories:
|
||||
# - Publish results to OpenSSF REST API for easy access by consumers
|
||||
@ -49,17 +40,8 @@ jobs:
|
||||
# - See https://github.com/ossf/scorecard-action#publishing-results.
|
||||
publish_results: true
|
||||
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v3.29.5
|
||||
- name: Upload to code-scanning
|
||||
uses: github/codeql-action/upload-sarif@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v3.29.5
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
7
.github/workflows/windows.yml
vendored
7
.github/workflows/windows.yml
vendored
@ -7,6 +7,9 @@ permissions:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: >-
|
||||
${{matrix.platform}} ${{matrix.toolset}} c++${{matrix.standard}}
|
||||
${{matrix.build_type}} ${{matrix.shared && 'Shared' || ''}}
|
||||
runs-on: ${{matrix.os}}
|
||||
strategy:
|
||||
matrix:
|
||||
@ -32,7 +35,7 @@ jobs:
|
||||
standard: 20
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Set timezone
|
||||
run: tzutil /s "FLE Standard Time"
|
||||
@ -79,7 +82,7 @@ jobs:
|
||||
release: false
|
||||
msystem: ${{matrix.sys}}
|
||||
pacboy: cc:p cmake:p ninja:p lld:p
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- name: Configure
|
||||
run: cmake -B ../build -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Debug
|
||||
env: { LDFLAGS: -fuse-ld=lld }
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@
|
||||
*.so*
|
||||
*.xcodeproj
|
||||
*~
|
||||
*.gradle/
|
||||
.vscode/
|
||||
.cache/
|
||||
.vs/
|
||||
|
||||
@ -63,7 +63,7 @@ if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.28 AND CMAKE_CXX_STANDARD
|
||||
OUTPUT_VARIABLE NINJA_VERSION)
|
||||
if (NINJA_VERSION VERSION_GREATER_EQUAL 1.11)
|
||||
if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION
|
||||
GREATER_EQUAL 14)
|
||||
GREATER_EQUAL 15)
|
||||
OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
|
||||
AND CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 16)
|
||||
OR (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION
|
||||
@ -256,11 +256,13 @@ function (setup_target target kind)
|
||||
target_compile_definitions(${target} ${kind} FMT_UNICODE=0)
|
||||
endif ()
|
||||
|
||||
set_target_properties(
|
||||
${target}
|
||||
PROPERTIES VERSION ${FMT_VERSION}
|
||||
SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
|
||||
DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}")
|
||||
if (NOT "${kind}" STREQUAL "INTERFACE")
|
||||
set_target_properties(
|
||||
${target}
|
||||
PROPERTIES VERSION ${FMT_VERSION}
|
||||
SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
|
||||
DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}")
|
||||
endif ()
|
||||
endfunction ()
|
||||
|
||||
set(FMT_HEADERS)
|
||||
@ -417,8 +419,19 @@ target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)
|
||||
target_compile_features(fmt-header-only INTERFACE cxx_std_11)
|
||||
setup_target(fmt-header-only INTERFACE)
|
||||
|
||||
add_library(fmt-c STATIC src/fmt-c.cc)
|
||||
add_library(fmt-c src/fmt-c.cc)
|
||||
target_compile_features(fmt-c INTERFACE c_std_11)
|
||||
if (BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(
|
||||
fmt-c
|
||||
PRIVATE FMT_LIB_EXPORT
|
||||
INTERFACE FMT_SHARED)
|
||||
endif ()
|
||||
set_target_properties(
|
||||
fmt-c
|
||||
PROPERTIES VERSION ${FMT_VERSION}
|
||||
SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
|
||||
DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}")
|
||||
if (MSVC)
|
||||
target_compile_options(fmt-c PUBLIC /Zc:preprocessor)
|
||||
endif ()
|
||||
@ -428,6 +441,16 @@ add_library(fmt::fmt-c ALIAS fmt-c)
|
||||
set_target_properties(fmt-c PROPERTIES PUBLIC_HEADER include/fmt/fmt-c.h)
|
||||
|
||||
# Install targets.
|
||||
set(targets_export_name fmt-targets)
|
||||
set(INSTALL_TARGETS fmt fmt-header-only fmt-c)
|
||||
|
||||
if (FMT_MODULE)
|
||||
list(APPEND INSTALL_TARGETS fmt-module)
|
||||
if (FMT_USE_CMAKE_MODULES)
|
||||
set(INSTALL_FILE_SET FILE_SET fmt DESTINATION ${FMT_INC_DIR}/fmt)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (FMT_INSTALL)
|
||||
include(CMakePackageConfigHelpers)
|
||||
set_verbose(
|
||||
@ -441,7 +464,6 @@ if (FMT_INSTALL)
|
||||
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_verbose(
|
||||
FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING
|
||||
@ -472,15 +494,6 @@ 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 fmt-c)
|
||||
|
||||
if (FMT_MODULE)
|
||||
list(APPEND INSTALL_TARGETS fmt-module)
|
||||
if (FMT_USE_CMAKE_MODULES)
|
||||
set(INSTALL_FILE_SET FILE_SET fmt DESTINATION ${FMT_INC_DIR}/fmt)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# Install the library and headers.
|
||||
install(
|
||||
TARGETS ${INSTALL_TARGETS}
|
||||
@ -491,13 +504,6 @@ if (FMT_INSTALL)
|
||||
PUBLIC_HEADER DESTINATION ${FMT_INC_DIR}/fmt
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ${INSTALL_FILE_SET})
|
||||
|
||||
# Use a namespace because CMake provides better diagnostics for namespaced
|
||||
# imported targets.
|
||||
export(
|
||||
TARGETS ${INSTALL_TARGETS}
|
||||
NAMESPACE fmt::
|
||||
FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake)
|
||||
|
||||
# Install version, config and target files.
|
||||
install(
|
||||
FILES ${project_config} ${version_config}
|
||||
@ -515,6 +521,15 @@ if (FMT_INSTALL)
|
||||
COMPONENT fmt_core)
|
||||
endif ()
|
||||
|
||||
# Generate an export file in the build tree so that fmt can be used by
|
||||
# add_subdirectory() or FetchContent without being installed. Use a
|
||||
# namespace because CMake provides better diagnostics for namespaced
|
||||
# imported targets.
|
||||
export(
|
||||
TARGETS ${INSTALL_TARGETS}
|
||||
NAMESPACE fmt::
|
||||
FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake)
|
||||
|
||||
function (add_doc_target)
|
||||
find_program(DOXYGEN doxygen PATHS "$ENV{ProgramFiles}/doxygen/bin"
|
||||
"$ENV{ProgramFiles\(x86\)}/doxygen/bin")
|
||||
@ -582,7 +597,9 @@ if (FMT_MASTER_PROJECT AND EXISTS ${gitignore})
|
||||
string(REPLACE "*" ".*" line "${line}")
|
||||
set(ignored_files ${ignored_files} "${line}$" "${line}/")
|
||||
endforeach ()
|
||||
set(ignored_files ${ignored_files} /.git /build/doxyxml .vagrant)
|
||||
# Exclude the whole build tree: the .gitignore-derived `build/` pattern does
|
||||
# not actually prune the directory or its contents from the source package.
|
||||
set(ignored_files ${ignored_files} /.git "/build($|/)" .vagrant)
|
||||
|
||||
set(CPACK_SOURCE_GENERATOR ZIP)
|
||||
set(CPACK_SOURCE_IGNORE_FILES ${ignored_files})
|
||||
|
||||
223
ChangeLog.md
223
ChangeLog.md
@ -1,3 +1,226 @@
|
||||
# 12.2.0 - 2026-06-16
|
||||
|
||||
- Added a C11 API that brings fast, type-safe formatting to C. The new
|
||||
`fmt-c` library and `fmt/fmt-c.h` header use `_Generic` to dispatch on
|
||||
argument types and outperform `printf`/`sprintf`. For example:
|
||||
|
||||
```c++
|
||||
#include <fmt/fmt-c.h>
|
||||
|
||||
fmt_print(stdout, "The answer is {}.\n", 42);
|
||||
```
|
||||
|
||||
(https://github.com/fmtlib/fmt/issues/4663,
|
||||
https://github.com/fmtlib/fmt/pull/4671,
|
||||
https://github.com/fmtlib/fmt/pull/4696,
|
||||
https://github.com/fmtlib/fmt/issues/4693,
|
||||
https://github.com/fmtlib/fmt/pull/4694,
|
||||
https://github.com/fmtlib/fmt/pull/4712,
|
||||
https://github.com/fmtlib/fmt/pull/4789).
|
||||
Thanks @Soumik15630m, @Ferdi265 and @localspook.
|
||||
|
||||
- Added a separate `fmt::fmt-module` CMake target for C++20 modules and a
|
||||
CI workflow that exercises module-based builds
|
||||
(https://github.com/fmtlib/fmt/issues/4684,
|
||||
https://github.com/fmtlib/fmt/pull/4685,
|
||||
https://github.com/fmtlib/fmt/issues/4707,
|
||||
https://github.com/fmtlib/fmt/pull/4708,
|
||||
https://github.com/fmtlib/fmt/pull/4702,
|
||||
https://github.com/fmtlib/fmt/pull/4709).
|
||||
Thanks @MathewBensonCode.
|
||||
|
||||
- Enabled the full Dragonbox lookup cache by default for floating-point
|
||||
formatting unless optimizing for binary size (`__OPTIMIZE_SIZE__`),
|
||||
giving a ~10–25% speedup. Thanks Matthias Kretz for the suggestion.
|
||||
Average time per `double` on Apple M1 Pro (clang 17, random digits,
|
||||
smaller is better) measured with
|
||||
[dtoa-benchmark](https://github.com/fmtlib/dtoa-benchmark):
|
||||
|
||||
| Method | Time (ns) |
|
||||
| ----------------------- | --------: |
|
||||
| fmt (full) | 22.07 |
|
||||
| fmt (compact) | 29.55 |
|
||||
| ryu | 35.21 |
|
||||
| double-conversion | 81.81 |
|
||||
| `sprintf` | 726.27 |
|
||||
| `ostringstream` | 864.34 |
|
||||
|
||||
- Improved integer formatting performance by ~3%
|
||||
(https://github.com/fmtlib/fmt/pull/4630). Thanks @user202729.
|
||||
|
||||
- Optimized formatting into back-insert iterators by using bulk container
|
||||
append/insert methods (e.g. on `std::vector<char>` and custom string
|
||||
types) (https://github.com/fmtlib/fmt/pull/4679). Thanks @user202729.
|
||||
|
||||
- Reduced binary size of debug builds (~200k to ~85k in the bloat test) and
|
||||
improved compile speed when `consteval` is unavailable.
|
||||
|
||||
- Made path formatting lossless, preserving ill-formed UTF-16
|
||||
sequences when converting `std::filesystem::path` to a narrow string.
|
||||
|
||||
- Added support for formatting `std::unexpected`
|
||||
(https://github.com/fmtlib/fmt/pull/4675). Thanks @17steen.
|
||||
|
||||
- Added overloads of `fmt::println` that take a `fmt::text_style`
|
||||
(https://github.com/fmtlib/fmt/pull/4782). Thanks @ahoarau.
|
||||
|
||||
- Added support for positional arguments as width and precision specifiers
|
||||
in `fmt::printf` (https://github.com/fmtlib/fmt/pull/4643).
|
||||
Thanks @KareemOtoum.
|
||||
|
||||
- Made `FMT_STRING` a no-op when `FMT_USE_CONSTEVAL` is enabled, since the
|
||||
consteval format-string constructor already provides compile-time
|
||||
validation
|
||||
(https://github.com/fmtlib/fmt/issues/4611,
|
||||
https://github.com/fmtlib/fmt/pull/4612). Thanks @friedkeenan.
|
||||
|
||||
- Promoted `fmt::detail::named_arg` to the public API as `fmt::named_arg` and
|
||||
deprecated the detail alias
|
||||
(https://github.com/fmtlib/fmt/issues/4683,
|
||||
https://github.com/fmtlib/fmt/pull/4687). Thanks @TPPPP72.
|
||||
|
||||
- Moved the `std::byte` formatter from `fmt/format.h` to `fmt/std.h`.
|
||||
|
||||
- Provided a default definition for `fmt::is_contiguous`
|
||||
(https://github.com/fmtlib/fmt/pull/4731,
|
||||
https://github.com/fmtlib/fmt/pull/4770). Thanks @user202729 and @phprus.
|
||||
|
||||
- Added the `FMT_USE_FLOCKFILE` macro to disable the use of `flockfile`
|
||||
(https://github.com/fmtlib/fmt/issues/4646,
|
||||
https://github.com/fmtlib/fmt/pull/4666). Thanks @mvastola.
|
||||
|
||||
- Added `include_guard(GLOBAL)` so that {fmt} can be used in multiple
|
||||
submodules of the same project
|
||||
(https://github.com/fmtlib/fmt/pull/4672). Thanks @torsten48.
|
||||
|
||||
- Improved `constexpr` support
|
||||
(https://github.com/fmtlib/fmt/pull/4659,
|
||||
https://github.com/fmtlib/fmt/pull/4591).
|
||||
Thanks @elbeno and @17steen.
|
||||
|
||||
- Deprecated the implicit conversion from `fmt::format_string` and
|
||||
`fmt::basic_fstring` to `string_view` to align with `std::format_string`;
|
||||
use `format_string::get()` instead.
|
||||
|
||||
- Opted out `std::complex` from tuple formatting so that the dedicated
|
||||
`std::complex` formatter is always used.
|
||||
|
||||
- Removed the `fmt::say` function.
|
||||
|
||||
- Deprecated the `std::initializer_list` overload of `fmt::join` and the array
|
||||
overload of `fmt::vformat_to`.
|
||||
|
||||
- Made the `<fmt/core.h>` header equivalent to `<fmt/base.h>` by
|
||||
default. Code that relied on `<fmt/core.h>` pulling in `<fmt/format.h>`
|
||||
must now either include `<fmt/format.h>` directly or define
|
||||
`FMT_DEPRECATED_HEAVY_CORE` to opt back in.
|
||||
|
||||
- Improved `wchar_t` support: `fmt::join` now accepts `wchar_t` and other
|
||||
non-`char` separators, and `fmt::format_to_n` now works with `fmt::runtime`
|
||||
on `wchar_t`
|
||||
(https://github.com/fmtlib/fmt/pull/4686,
|
||||
https://github.com/fmtlib/fmt/issues/4714,
|
||||
https://github.com/fmtlib/fmt/pull/4715).
|
||||
Thanks @Yancey2023 and @sunmy2019.
|
||||
|
||||
- Fixed formatting of `std::tm` with a null `tm_zone`
|
||||
(https://github.com/fmtlib/fmt/pull/4790). Thanks @Carmel0.
|
||||
|
||||
- Fixed compile-time formatting in `fmt/ranges.h`, `fmt/style.h` and
|
||||
`fmt/std.h` (https://github.com/fmtlib/fmt/pull/4759). Thanks @j4niwzis.
|
||||
|
||||
- Fixed an ambiguity between `formatter<std::optional<T>>` in `fmt/std.h`
|
||||
and `fmt/ranges.h` on C++26 (P3168R2)
|
||||
(https://github.com/fmtlib/fmt/pull/4761). Thanks @phprus.
|
||||
|
||||
- Fixed a GCC PCH breakage triggered by a scoped `#pragma GCC optimize`.
|
||||
|
||||
- Fixed a TSAN false positive in the locale handling code
|
||||
(https://github.com/fmtlib/fmt/issues/4755).
|
||||
|
||||
- Fixed compile-time format string checks truncating string literals at
|
||||
an embedded null byte
|
||||
(https://github.com/fmtlib/fmt/pull/4732). Thanks @user202729.
|
||||
|
||||
- Fixed out-of-bounds reads in `printf` formatting
|
||||
(https://github.com/fmtlib/fmt/issues/4741,
|
||||
https://github.com/fmtlib/fmt/pull/4742,
|
||||
https://github.com/fmtlib/fmt/pull/4800).
|
||||
Thanks @Algunenano and @aizu-m.
|
||||
|
||||
- Fixed the return type of the `f(un)lockfile` wrappers on Windows
|
||||
(https://github.com/fmtlib/fmt/pull/4739). Thanks @mvastola.
|
||||
|
||||
- Worked around a CUDA issue when handling UTF-32 literals
|
||||
(https://github.com/fmtlib/fmt/pull/4719). Thanks @Cazadorro.
|
||||
|
||||
- Fixed missing named-argument validation for compiled format strings
|
||||
(https://github.com/fmtlib/fmt/pull/4638). Thanks @JaeheonShim.
|
||||
|
||||
- Fixed `fmt::format_to_n` in `<fmt/compile.h>` failing to compile when
|
||||
`<iterator>` is not transitively included
|
||||
(https://github.com/fmtlib/fmt/issues/4615).
|
||||
|
||||
- Fixed handling of pointers in format string compilation with
|
||||
`FMT_BUILTIN_TYPES=0`.
|
||||
|
||||
- Stopped assuming nul termination of the format string in `fmt::printf`.
|
||||
Thanks @ZUENS2020 for reporting.
|
||||
|
||||
- Fixed a build error when locale support is disabled
|
||||
(https://github.com/fmtlib/fmt/pull/4627). Thanks @marcel-behlau-elfin.
|
||||
|
||||
- Fixed a fallback range formatter for types with a `container_type` member
|
||||
(https://github.com/fmtlib/fmt/issues/4123,
|
||||
https://github.com/fmtlib/fmt/pull/4660). Thanks @Soumik15630m.
|
||||
|
||||
- Fixed C++20 concept detection
|
||||
(https://github.com/fmtlib/fmt/pull/4653). Thanks @tearfur.
|
||||
|
||||
- Fixed a clang compilation failure
|
||||
(https://github.com/fmtlib/fmt/pull/4718). Thanks @mccakit.
|
||||
|
||||
- Fixed various MSVC warnings, including C4305 and conversion warnings on
|
||||
x86 (https://github.com/fmtlib/fmt/pull/4668,
|
||||
https://github.com/fmtlib/fmt/pull/4594).
|
||||
Thanks @kanren3 and @blizzard4591.
|
||||
|
||||
- Updated the Android Gradle Plugin to 9.x
|
||||
(https://github.com/fmtlib/fmt/issues/4651,
|
||||
https://github.com/fmtlib/fmt/pull/4658). Thanks @Soumik15630m.
|
||||
|
||||
- Made various code, build and test improvements
|
||||
(https://github.com/fmtlib/fmt/pull/4625,
|
||||
https://github.com/fmtlib/fmt/pull/4639,
|
||||
https://github.com/fmtlib/fmt/pull/4644,
|
||||
https://github.com/fmtlib/fmt/pull/4656,
|
||||
https://github.com/fmtlib/fmt/pull/4680,
|
||||
https://github.com/fmtlib/fmt/pull/4681,
|
||||
https://github.com/fmtlib/fmt/pull/4704,
|
||||
https://github.com/fmtlib/fmt/pull/4710,
|
||||
https://github.com/fmtlib/fmt/pull/4713,
|
||||
https://github.com/fmtlib/fmt/pull/4729,
|
||||
https://github.com/fmtlib/fmt/pull/4751,
|
||||
https://github.com/fmtlib/fmt/pull/4758,
|
||||
https://github.com/fmtlib/fmt/pull/4799).
|
||||
Thanks @ZephyrLykos, @togunchan, @kagancansit, @BerndPetrovitsch,
|
||||
@Skylion007, @st0rmbtw, @localspook and @EXtremeExploit.
|
||||
|
||||
- Improved documentation, including a rewrite of the format string syntax,
|
||||
better handling of doxygen tags, documenting `output_file`, fixing CSS so
|
||||
that whitespace is displayed properly, and various smaller fixes
|
||||
(https://github.com/fmtlib/fmt/pull/4622,
|
||||
https://github.com/fmtlib/fmt/pull/4626,
|
||||
https://github.com/fmtlib/fmt/pull/4631,
|
||||
https://github.com/fmtlib/fmt/pull/4667,
|
||||
https://github.com/fmtlib/fmt/pull/4616,
|
||||
https://github.com/fmtlib/fmt/pull/4748).
|
||||
Thanks @heavywatal, @ZephyrLykos, @user202729, @ssszcmawo, @bigmoonbit
|
||||
and @Powerbyte7.
|
||||
|
||||
- Added building of release artifacts and SLSA provenance in CI, added a
|
||||
CodeQL workflow, and added the security policy in `.github/SECURITY.md`.
|
||||
|
||||
# 12.1.0 - 2025-10-29
|
||||
|
||||
- Optimized `buffer::append`, resulting in up to ~16% improvement on spdlog
|
||||
|
||||
139
README.md
139
README.md
@ -1,19 +1,25 @@
|
||||
<img src="https://user-images.githubusercontent.com/576385/156254208-f5b743a9-88cf-439d-b0c0-923d53e8d551.png" alt="{fmt}" width="25%"/>
|
||||
|
||||
[](https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux)
|
||||
[](https://github.com/fmtlib/fmt/actions?query=workflow%3Amacos)
|
||||
[](https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows)
|
||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?\%0Acolspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20\%0ASummary&q=proj%3Dfmt&can=1)
|
||||
[](https://www.bestpractices.dev/projects/8880)
|
||||
[](https://securityscorecards.dev/viewer/?uri=github.com/fmtlib/fmt)
|
||||
[](https://stackoverflow.com/questions/tagged/fmt)
|
||||
[](
|
||||
https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux)
|
||||
[](
|
||||
https://github.com/fmtlib/fmt/actions?query=workflow%3Amacos)
|
||||
[](
|
||||
https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows)
|
||||
[](
|
||||
https://issues.oss-fuzz.com/issues?q=title:fmt%20cc:victor.zverovich@gmail.com)
|
||||
[](
|
||||
https://www.bestpractices.dev/projects/8880)
|
||||
[](
|
||||
https://securityscorecards.dev/viewer/?uri=github.com/fmtlib/fmt)
|
||||
[](https://stackoverflow.com/questions/tagged/fmt)
|
||||
[](https://novaukraine.org/)
|
||||
|
||||
**{fmt}** is an open-source formatting library providing a fast and safe
|
||||
alternative to C stdio and C++ iostreams.
|
||||
|
||||
If you like this project, please consider donating to one of the funds
|
||||
that help victims of the war in Ukraine: <https://u24.gov.ua/>.
|
||||
|
||||
[Documentation](https://fmt.dev)
|
||||
|
||||
[Cheat Sheets](https://hackingcpp.com/cpp/libs/fmt.html)
|
||||
@ -38,7 +44,7 @@ Try {fmt} in [Compiler Explorer](https://godbolt.org/z/8Mx1EW73v).
|
||||
[Dragonbox](https://github.com/jk-jeon/dragonbox) algorithm
|
||||
- Portable Unicode support
|
||||
- Safe [printf
|
||||
implementation](https://fmt.dev/latest/api/#printf-formatting)
|
||||
implementation](https://fmt.dev/latest/api/#printf-api)
|
||||
including the POSIX extension for positional arguments
|
||||
- Extensibility: [support for user-defined
|
||||
types](https://fmt.dev/latest/api/#formatting-user-defined-types)
|
||||
@ -46,7 +52,7 @@ Try {fmt} in [Compiler Explorer](https://godbolt.org/z/8Mx1EW73v).
|
||||
implementations of `(s)printf`, iostreams, `to_string` and
|
||||
`to_chars`, see [Speed tests](#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)
|
||||
second](https://vitaut.net/posts/2020/fast-int-to-string-revisited/)
|
||||
- Small code size both in terms of source code with the minimum
|
||||
configuration consisting of just three files, `base.h`, `format.h`
|
||||
and `format-inl.h`, and compiled code; see [Compile time and code
|
||||
@ -151,7 +157,7 @@ int main() {
|
||||
```
|
||||
|
||||
This can be [up to 9 times faster than `fprintf`](
|
||||
http://www.zverovich.net/2020/08/04/optimal-file-buffer-size.html).
|
||||
https://vitaut.net/posts/2020/optimal-file-buffer-size/).
|
||||
|
||||
**Print with colors and text styles**
|
||||
|
||||
@ -170,7 +176,7 @@ int main() {
|
||||
|
||||
Output on a modern terminal with Unicode support:
|
||||
|
||||

|
||||

|
||||
|
||||
# Benchmarks
|
||||
|
||||
@ -345,7 +351,7 @@ converts to `std::print`.)
|
||||
cluster proxy
|
||||
- [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
|
||||
- [rpclib](https://github.com/rpclib/rpclib): a modern C++ msgpack-RPC server and
|
||||
client library
|
||||
- [Salesforce Analytics
|
||||
Cloud](https://www.salesforce.com/analytics-cloud/overview/):
|
||||
@ -353,7 +359,7 @@ converts to `std::print`.)
|
||||
- [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
|
||||
- [Seastar](https://seastar.io/): an advanced, open-source
|
||||
C++ framework for high-performance server applications on modern
|
||||
hardware
|
||||
- [spdlog](https://github.com/gabime/spdlog): super fast C++ logging
|
||||
@ -374,98 +380,6 @@ If you are aware of other projects using this library, please let me
|
||||
know by [email](mailto:victor.zverovich@gmail.com) or by submitting an
|
||||
[issue](https://github.com/fmtlib/fmt/issues).
|
||||
|
||||
# Motivation
|
||||
|
||||
So why yet another formatting library?
|
||||
|
||||
There are plenty of methods for doing this task, from standard ones like
|
||||
the printf family of function and iostreams to Boost Format and
|
||||
FastFormat libraries. The reason for creating a new library is that
|
||||
every existing solution that I found either had serious issues or
|
||||
didn\'t provide all the features I needed.
|
||||
|
||||
## printf
|
||||
|
||||
The good thing about `printf` is that it is pretty fast and readily
|
||||
available being a part of the C standard library. The main drawback is
|
||||
that it doesn\'t support user-defined types. `printf` also has safety
|
||||
issues although they are somewhat mitigated with [\_\_attribute\_\_
|
||||
((format (printf,
|
||||
\...))](https://gcc.gnu.org/onlinedocs/gcc/Common-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
|
||||
platforms.
|
||||
|
||||
## iostreams
|
||||
|
||||
The main issue with iostreams is best illustrated with an example:
|
||||
|
||||
``` c++
|
||||
std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n";
|
||||
```
|
||||
|
||||
which is a lot of typing compared to printf:
|
||||
|
||||
``` c++
|
||||
printf("%.2f\n", 1.23456);
|
||||
```
|
||||
|
||||
Matthew Wilson, the author of FastFormat, called this \"chevron hell\".
|
||||
iostreams don\'t support positional arguments by design.
|
||||
|
||||
The good part is that iostreams support user-defined types and are safe
|
||||
although error handling is awkward.
|
||||
|
||||
## Boost Format
|
||||
|
||||
This is a very powerful library that supports both `printf`-like format
|
||||
strings and positional arguments. Its main drawback is performance.
|
||||
According to various benchmarks, it is much slower than other methods
|
||||
considered here. Boost Format also has excessive build times and severe
|
||||
code bloat issues (see [Benchmarks](#benchmarks)).
|
||||
|
||||
## FastFormat
|
||||
|
||||
This is an interesting library that is fast, safe and has positional
|
||||
arguments. However, it has significant limitations, citing its author:
|
||||
|
||||
> Three features that have no hope of being accommodated within the
|
||||
> current design are:
|
||||
>
|
||||
> - Leading zeros (or any other non-space padding)
|
||||
> - Octal/hexadecimal encoding
|
||||
> - Runtime width/alignment specification
|
||||
|
||||
It is also quite big and has a heavy dependency, on STLSoft, which might be
|
||||
too restrictive for use in some projects.
|
||||
|
||||
## Boost Spirit.Karma
|
||||
|
||||
This is not a formatting library but I decided to include it here for
|
||||
completeness. As iostreams, it suffers from the problem of mixing
|
||||
verbatim text with arguments. The library is pretty fast, but slower on
|
||||
integer formatting than `fmt::format_to` with format string compilation
|
||||
on Karma\'s own benchmark, see [Converting a hundred million integers to
|
||||
strings per
|
||||
second](http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html).
|
||||
|
||||
# License
|
||||
|
||||
{fmt} is distributed under the MIT
|
||||
[license](https://github.com/fmtlib/fmt/blob/master/LICENSE).
|
||||
|
||||
# Documentation License
|
||||
|
||||
The [Format String Syntax](https://fmt.dev/latest/syntax/) 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
|
||||
@ -475,12 +389,3 @@ people. See
|
||||
[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.
|
||||
|
||||
# Security Policy
|
||||
|
||||
To report a security issue, please disclose it at [security
|
||||
advisory](https://github.com/fmtlib/fmt/security/advisories/new).
|
||||
|
||||
This project is maintained by a team of volunteers on a
|
||||
reasonable-effort basis. As such, please give us at least *90* days to
|
||||
work on a fix before public exposure.
|
||||
|
||||
@ -130,7 +130,6 @@ hide:
|
||||
Where possible, the output of formatting functions is <b>consistent across
|
||||
platforms</b>.
|
||||
</p>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
|
||||
@ -1,290 +0,0 @@
|
||||
A. HISTORY OF THE SOFTWARE
|
||||
==========================
|
||||
|
||||
Python was created in the early 1990s by Guido van Rossum at Stichting
|
||||
Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
|
||||
as a successor of a language called ABC. Guido remains Python's
|
||||
principal author, although it includes many contributions from others.
|
||||
|
||||
In 1995, Guido continued his work on Python at the Corporation for
|
||||
National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
|
||||
in Reston, Virginia where he released several versions of the
|
||||
software.
|
||||
|
||||
In May 2000, Guido and the Python core development team moved to
|
||||
BeOpen.com to form the BeOpen PythonLabs team. In October of the same
|
||||
year, the PythonLabs team moved to Digital Creations (now Zope
|
||||
Corporation, see http://www.zope.com). In 2001, the Python Software
|
||||
Foundation (PSF, see http://www.python.org/psf/) was formed, a
|
||||
non-profit organization created specifically to own Python-related
|
||||
Intellectual Property. Zope Corporation is a sponsoring member of
|
||||
the PSF.
|
||||
|
||||
All Python releases are Open Source (see http://www.opensource.org for
|
||||
the Open Source Definition). Historically, most, but not all, Python
|
||||
releases have also been GPL-compatible; the table below summarizes
|
||||
the various releases.
|
||||
|
||||
Release Derived Year Owner GPL-
|
||||
from compatible? (1)
|
||||
|
||||
0.9.0 thru 1.2 1991-1995 CWI yes
|
||||
1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
|
||||
1.6 1.5.2 2000 CNRI no
|
||||
2.0 1.6 2000 BeOpen.com no
|
||||
1.6.1 1.6 2001 CNRI yes (2)
|
||||
2.1 2.0+1.6.1 2001 PSF no
|
||||
2.0.1 2.0+1.6.1 2001 PSF yes
|
||||
2.1.1 2.1+2.0.1 2001 PSF yes
|
||||
2.2 2.1.1 2001 PSF yes
|
||||
2.1.2 2.1.1 2002 PSF yes
|
||||
2.1.3 2.1.2 2002 PSF yes
|
||||
2.2.1 2.2 2002 PSF yes
|
||||
2.2.2 2.2.1 2002 PSF yes
|
||||
2.2.3 2.2.2 2003 PSF yes
|
||||
2.3 2.2.2 2002-2003 PSF yes
|
||||
2.3.1 2.3 2002-2003 PSF yes
|
||||
2.3.2 2.3.1 2002-2003 PSF yes
|
||||
2.3.3 2.3.2 2002-2003 PSF yes
|
||||
2.3.4 2.3.3 2004 PSF yes
|
||||
2.3.5 2.3.4 2005 PSF yes
|
||||
2.4 2.3 2004 PSF yes
|
||||
2.4.1 2.4 2005 PSF yes
|
||||
2.4.2 2.4.1 2005 PSF yes
|
||||
2.4.3 2.4.2 2006 PSF yes
|
||||
2.4.4 2.4.3 2006 PSF yes
|
||||
2.5 2.4 2006 PSF yes
|
||||
2.5.1 2.5 2007 PSF yes
|
||||
2.5.2 2.5.1 2008 PSF yes
|
||||
2.5.3 2.5.2 2008 PSF yes
|
||||
2.6 2.5 2008 PSF yes
|
||||
2.6.1 2.6 2008 PSF yes
|
||||
2.6.2 2.6.1 2009 PSF yes
|
||||
2.6.3 2.6.2 2009 PSF yes
|
||||
2.6.4 2.6.3 2009 PSF yes
|
||||
2.6.5 2.6.4 2010 PSF yes
|
||||
3.0 2.6 2008 PSF yes
|
||||
3.0.1 3.0 2009 PSF yes
|
||||
3.1 3.0.1 2009 PSF yes
|
||||
3.1.1 3.1 2009 PSF yes
|
||||
3.1.2 3.1.1 2010 PSF yes
|
||||
3.1.3 3.1.2 2010 PSF yes
|
||||
3.1.4 3.1.3 2011 PSF yes
|
||||
3.2 3.1 2011 PSF yes
|
||||
3.2.1 3.2 2011 PSF yes
|
||||
3.2.2 3.2.1 2011 PSF yes
|
||||
3.2.3 3.2.2 2012 PSF yes
|
||||
3.3.0 3.2 2012 PSF yes
|
||||
|
||||
Footnotes:
|
||||
|
||||
(1) GPL-compatible doesn't mean that we're distributing Python under
|
||||
the GPL. All Python licenses, unlike the GPL, let you distribute
|
||||
a modified version without making your changes open source. The
|
||||
GPL-compatible licenses make it possible to combine Python with
|
||||
other software that is released under the GPL; the others don't.
|
||||
|
||||
(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
|
||||
because its license has a choice of law clause. According to
|
||||
CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
|
||||
is "not incompatible" with the GPL.
|
||||
|
||||
Thanks to the many outside volunteers who have worked under Guido's
|
||||
direction to make these releases possible.
|
||||
|
||||
|
||||
B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
|
||||
===============================================================
|
||||
|
||||
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
||||
--------------------------------------------
|
||||
|
||||
1. This LICENSE AGREEMENT is between the Python Software Foundation
|
||||
("PSF"), and the Individual or Organization ("Licensee") accessing and
|
||||
otherwise using this software ("Python") in source or binary form and
|
||||
its associated documentation.
|
||||
|
||||
2. Subject to the terms and conditions of this License Agreement, PSF hereby
|
||||
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
|
||||
analyze, test, perform and/or display publicly, prepare derivative works,
|
||||
distribute, and otherwise use Python alone or in any derivative version,
|
||||
provided, however, that PSF's License Agreement and PSF's notice of copyright,
|
||||
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||
2011, 2012 Python Software Foundation; All Rights Reserved" are retained in Python
|
||||
alone or in any derivative version prepared by Licensee.
|
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on
|
||||
or incorporates Python or any part thereof, and wants to make
|
||||
the derivative work available to others as provided herein, then
|
||||
Licensee hereby agrees to include in any such work a brief summary of
|
||||
the changes made to Python.
|
||||
|
||||
4. PSF is making Python available to Licensee on an "AS IS"
|
||||
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
|
||||
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
6. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
7. Nothing in this License Agreement shall be deemed to create any
|
||||
relationship of agency, partnership, or joint venture between PSF and
|
||||
Licensee. This License Agreement does not grant permission to use PSF
|
||||
trademarks or trade name in a trademark sense to endorse or promote
|
||||
products or services of Licensee, or any third party.
|
||||
|
||||
8. By copying, installing or otherwise using Python, Licensee
|
||||
agrees to be bound by the terms and conditions of this License
|
||||
Agreement.
|
||||
|
||||
|
||||
BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
|
||||
-------------------------------------------
|
||||
|
||||
BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
|
||||
|
||||
1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
|
||||
office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
|
||||
Individual or Organization ("Licensee") accessing and otherwise using
|
||||
this software in source or binary form and its associated
|
||||
documentation ("the Software").
|
||||
|
||||
2. Subject to the terms and conditions of this BeOpen Python License
|
||||
Agreement, BeOpen hereby grants Licensee a non-exclusive,
|
||||
royalty-free, world-wide license to reproduce, analyze, test, perform
|
||||
and/or display publicly, prepare derivative works, distribute, and
|
||||
otherwise use the Software alone or in any derivative version,
|
||||
provided, however, that the BeOpen Python License is retained in the
|
||||
Software, alone or in any derivative version prepared by Licensee.
|
||||
|
||||
3. BeOpen is making the Software available to Licensee on an "AS IS"
|
||||
basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
|
||||
SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
|
||||
AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
|
||||
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
5. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
6. This License Agreement shall be governed by and interpreted in all
|
||||
respects by the law of the State of California, excluding conflict of
|
||||
law provisions. Nothing in this License Agreement shall be deemed to
|
||||
create any relationship of agency, partnership, or joint venture
|
||||
between BeOpen and Licensee. This License Agreement does not grant
|
||||
permission to use BeOpen trademarks or trade names in a trademark
|
||||
sense to endorse or promote products or services of Licensee, or any
|
||||
third party. As an exception, the "BeOpen Python" logos available at
|
||||
http://www.pythonlabs.com/logos.html may be used according to the
|
||||
permissions granted on that web page.
|
||||
|
||||
7. By copying, installing or otherwise using the software, Licensee
|
||||
agrees to be bound by the terms and conditions of this License
|
||||
Agreement.
|
||||
|
||||
|
||||
CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
|
||||
---------------------------------------
|
||||
|
||||
1. This LICENSE AGREEMENT is between the Corporation for National
|
||||
Research Initiatives, having an office at 1895 Preston White Drive,
|
||||
Reston, VA 20191 ("CNRI"), and the Individual or Organization
|
||||
("Licensee") accessing and otherwise using Python 1.6.1 software in
|
||||
source or binary form and its associated documentation.
|
||||
|
||||
2. Subject to the terms and conditions of this License Agreement, CNRI
|
||||
hereby grants Licensee a nonexclusive, royalty-free, world-wide
|
||||
license to reproduce, analyze, test, perform and/or display publicly,
|
||||
prepare derivative works, distribute, and otherwise use Python 1.6.1
|
||||
alone or in any derivative version, provided, however, that CNRI's
|
||||
License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
|
||||
1995-2001 Corporation for National Research Initiatives; All Rights
|
||||
Reserved" are retained in Python 1.6.1 alone or in any derivative
|
||||
version prepared by Licensee. Alternately, in lieu of CNRI's License
|
||||
Agreement, Licensee may substitute the following text (omitting the
|
||||
quotes): "Python 1.6.1 is made available subject to the terms and
|
||||
conditions in CNRI's License Agreement. This Agreement together with
|
||||
Python 1.6.1 may be located on the Internet using the following
|
||||
unique, persistent identifier (known as a handle): 1895.22/1013. This
|
||||
Agreement may also be obtained from a proxy server on the Internet
|
||||
using the following URL: http://hdl.handle.net/1895.22/1013".
|
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on
|
||||
or incorporates Python 1.6.1 or any part thereof, and wants to make
|
||||
the derivative work available to others as provided herein, then
|
||||
Licensee hereby agrees to include in any such work a brief summary of
|
||||
the changes made to Python 1.6.1.
|
||||
|
||||
4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
|
||||
basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||
1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
|
||||
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
6. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
7. This License Agreement shall be governed by the federal
|
||||
intellectual property law of the United States, including without
|
||||
limitation the federal copyright law, and, to the extent such
|
||||
U.S. federal law does not apply, by the law of the Commonwealth of
|
||||
Virginia, excluding Virginia's conflict of law provisions.
|
||||
Notwithstanding the foregoing, with regard to derivative works based
|
||||
on Python 1.6.1 that incorporate non-separable material that was
|
||||
previously distributed under the GNU General Public License (GPL), the
|
||||
law of the Commonwealth of Virginia shall govern this License
|
||||
Agreement only as to issues arising under or with respect to
|
||||
Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
|
||||
License Agreement shall be deemed to create any relationship of
|
||||
agency, partnership, or joint venture between CNRI and Licensee. This
|
||||
License Agreement does not grant permission to use CNRI trademarks or
|
||||
trade name in a trademark sense to endorse or promote products or
|
||||
services of Licensee, or any third party.
|
||||
|
||||
8. By clicking on the "ACCEPT" button where indicated, or by copying,
|
||||
installing or otherwise using Python 1.6.1, Licensee agrees to be
|
||||
bound by the terms and conditions of this License Agreement.
|
||||
|
||||
ACCEPT
|
||||
|
||||
|
||||
CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
|
||||
--------------------------------------------------
|
||||
|
||||
Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
|
||||
The Netherlands. All rights reserved.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose and without fee is hereby granted,
|
||||
provided that the above copyright notice appear in all copies and that
|
||||
both that copyright notice and this permission notice appear in
|
||||
supporting documentation, and that the name of Stichting Mathematisch
|
||||
Centrum or CWI not be used in advertising or publicity pertaining to
|
||||
distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
||||
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
|
||||
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
695
doc/syntax.md
695
doc/syntax.md
@ -1,14 +1,15 @@
|
||||
# Format String Syntax
|
||||
|
||||
Formatting functions such as [`fmt::format`](api.md#format) and [`fmt::print`](
|
||||
api.md#print) use the same format string syntax described in this section.
|
||||
The formatting functions in this library — most notably
|
||||
[`fmt::format`](api.md#format) and [`fmt::print`](api.md#print) — accept
|
||||
format strings written in the syntax described here.
|
||||
|
||||
Format strings contain "replacement fields" surrounded by curly braces `{}`.
|
||||
Anything that is not contained in braces is considered literal text, which is
|
||||
copied unchanged to the output. If you need to include a brace character in
|
||||
the literal text, it can be escaped by doubling: `{{` and `}}`.
|
||||
A format string is plain text with embedded *replacement fields* delimited by
|
||||
the braces `{` and `}`. Characters outside of any replacement field are
|
||||
copied to the output unchanged. To emit a literal brace, double it: `{{`
|
||||
yields a single `{` in the output, and `}}` yields a single `}`.
|
||||
|
||||
The grammar for a replacement field is as follows:
|
||||
A replacement field is described by the grammar below.
|
||||
|
||||
<a id="replacement-field"></a>
|
||||
<pre><code class="language-json"
|
||||
@ -22,55 +23,43 @@ id_start ::= "a"..."z" | "A"..."Z" | "_"
|
||||
id_continue ::= id_start | digit</code>
|
||||
</pre>
|
||||
|
||||
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.
|
||||
An *arg_id* selects which argument to format. It may be a non-negative
|
||||
integer (positional reference) or an identifier matching the name of an
|
||||
argument passed via [`fmt::arg`](api.md#arg) (named reference). When *arg_id*
|
||||
is omitted, arguments are consumed in left-to-right order; this *automatic*
|
||||
indexing must be used uniformly throughout the format string — mixing
|
||||
automatic and explicit numeric ids is a compile-time error (or a
|
||||
`format_error` at runtime).
|
||||
|
||||
See also the [Format Specification
|
||||
Mini-Language](#format-specification-mini-language) section.
|
||||
A *format_spec*, introduced by `:`, describes how the value should be
|
||||
rendered. Its grammar is type-dependent; the form used by the standard
|
||||
built-in types is documented in the next section.
|
||||
|
||||
If the numerical arg_ids in a format string are 0, 1, 2, ... in sequence,
|
||||
they can all be omitted (not just some) and the numbers 0, 1, 2, ... will be
|
||||
automatically inserted in that order.
|
||||
|
||||
Named arguments can be referred to by their names or indices.
|
||||
|
||||
Some simple format string examples:
|
||||
For example:
|
||||
|
||||
```c++
|
||||
"First, thou shalt count to {0}" // References the first argument
|
||||
"Bring me a {}" // Implicitly references the first argument
|
||||
"From {} to {}" // Same as "From {0} to {1}"
|
||||
fmt::format("hello, {}", "world");
|
||||
// Result: "hello, world"
|
||||
|
||||
fmt::format("{1}, {0}!", "world", "hello");
|
||||
// Result: "hello, world!"
|
||||
|
||||
fmt::format("{greeting}, {name}!",
|
||||
fmt::arg("greeting", "hi"), fmt::arg("name", "fmt"));
|
||||
// Result: "hi, fmt!"
|
||||
```
|
||||
|
||||
The *format_spec* field contains a specification of how the value should
|
||||
be presented, including such details as field width, alignment, padding,
|
||||
decimal precision and so on. Each value type can define its own
|
||||
"formatting mini-language" or interpretation of the *format_spec*.
|
||||
A *width* or *precision* inside a *format_spec* may itself be written as a
|
||||
nested replacement field — `{}` or `{arg_id}` — in which case it takes its
|
||||
value from an integer argument at runtime. Nested fields accept only an
|
||||
*arg_id*; they cannot themselves contain a *format_spec*.
|
||||
|
||||
Most built-in types support a common formatting mini-language, which is
|
||||
described in the next section.
|
||||
## Format Specification
|
||||
|
||||
A *format_spec* field can also include nested replacement fields in
|
||||
certain positions within it. These nested replacement fields can contain
|
||||
only an argument id; format specifications are not allowed. This allows
|
||||
the formatting of a value to be dynamically specified.
|
||||
|
||||
See the [Format Examples](#format-examples) section for some examples.
|
||||
|
||||
## Format Specification Mini-Language
|
||||
|
||||
"Format specifications" are used within replacement fields contained within a
|
||||
format string to define how individual values are presented. Each formattable
|
||||
type may define how the format specification is to be interpreted.
|
||||
|
||||
Most built-in types implement the following options for format
|
||||
specifications, although some of the formatting options are only
|
||||
supported by the numeric types.
|
||||
|
||||
The general form of a *standard format specifier* is:
|
||||
The grammar below describes the *format_spec* shared by the built-in
|
||||
types — integers, floating-point values, characters, strings, booleans, and
|
||||
pointers — as well as by any user-defined type whose `formatter` reuses
|
||||
fmt's parser.
|
||||
|
||||
<a id="format-spec"></a>
|
||||
<pre><code class="language-json"
|
||||
@ -86,318 +75,221 @@ type ::= "a" | "A" | "b" | "B" | "c" | "d" | "e" | "E" | "f" | "F" |
|
||||
"g" | "G" | "o" | "p" | "s" | "x" | "X" | "?"</code>
|
||||
</pre>
|
||||
|
||||
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.
|
||||
Whether a particular option is meaningful depends on the value being
|
||||
formatted; options that do not apply to a value's type are diagnosed at
|
||||
compile time when possible and otherwise raise a `format_error`.
|
||||
|
||||
The meaning of the various alignment options is as follows:
|
||||
### Fill and alignment
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Option</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'<'</code></td>
|
||||
<td>
|
||||
Forces the field to be left-aligned within the available space (this is the
|
||||
default for most objects).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'>'</code></td>
|
||||
<td>
|
||||
Forces the field to be right-aligned within the available space (this is
|
||||
the default for numbers).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'^'</code></td>
|
||||
<td>Forces the field to be centered within the available space.</td>
|
||||
</tr>
|
||||
</table>
|
||||
The *align* field selects where padding is placed when *width* makes the
|
||||
field wider than the value's natural rendering.
|
||||
|
||||
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.
|
||||
| Option | Effect |
|
||||
|--------|-------------------------------------------------------------------|
|
||||
| `<` | Left-align; pad on the right. Default for non-numeric types. |
|
||||
| `>` | Right-align; pad on the left. Default for numeric types. |
|
||||
| `^` | Center the value; if the padding cannot be split evenly, the extra padding character goes on the right. |
|
||||
|
||||
The *sign* option is only valid for floating point and signed integer types,
|
||||
and can be one of the following:
|
||||
The *fill* character is any single Unicode code point other than `{` or `}`,
|
||||
encoded the same way as the format string. It supplies the padding character
|
||||
in place of the default space. A fill character is recognized only when it is
|
||||
immediately followed by an *align* character — otherwise it would be
|
||||
indistinguishable from an option in another position — so to use a custom
|
||||
fill you must also specify an alignment.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Option</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'+'</code></td>
|
||||
<td>
|
||||
Indicates that a sign should be used for both nonnegative as well as
|
||||
negative numbers.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'-'</code></td>
|
||||
<td>
|
||||
Indicates that a sign should be used only for negative numbers (this is the
|
||||
default behavior).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>space</td>
|
||||
<td>
|
||||
Indicates that a leading space should be used on nonnegative numbers, and a
|
||||
minus sign on negative numbers.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
Alignment has no observable effect when the value's natural rendering is
|
||||
already at least as wide as *width*; the value is never truncated to fit.
|
||||
|
||||
The `'#'` option causes the "alternate form" to be used for the
|
||||
conversion. The alternate form is defined differently for different
|
||||
types. This option is only valid for integer and floating-point types.
|
||||
For integers, when binary, octal, or hexadecimal output is used, this
|
||||
option adds the prefix respective `"0b"` (`"0B"`), `"0"`, or `"0x"`
|
||||
(`"0X"`) to the output value. Whether the prefix is lower-case or
|
||||
upper-case is determined by the case of the type specifier, for example,
|
||||
the prefix `"0x"` is used for the type `'x'` and `"0X"` is used for
|
||||
`'X'`. For floating-point numbers the alternate form causes the result
|
||||
of the conversion to always contain a decimal-point character, even if
|
||||
no digits follow it. Normally, a decimal-point character appears in the
|
||||
result of these conversions only if a digit follows it. In addition, for
|
||||
`'g'` and `'G'` conversions, trailing zeros are not removed from the
|
||||
result.
|
||||
```c++
|
||||
fmt::format("[{:<10}]", "42"); // Result: "[42 ]"
|
||||
fmt::format("[{:>10}]", "42"); // Result: "[ 42]"
|
||||
fmt::format("[{:^10}]", "42"); // Result: "[ 42 ]"
|
||||
fmt::format("[{:*^10}]", "42"); // Result: "[****42****]" - '*' as fill
|
||||
```
|
||||
|
||||
*width* is a decimal integer defining the minimum field width. If not
|
||||
specified, then the field width will be determined by the content.
|
||||
### Sign
|
||||
|
||||
Preceding the *width* field by a zero (`'0'`) character enables
|
||||
sign-aware zero-padding for numeric types. It forces the padding to be
|
||||
placed after the sign or base (if any) but before the digits. This is
|
||||
used for printing fields in the form "+000000120". This option is only
|
||||
valid for numeric types and it has no effect on formatting of infinity
|
||||
and NaN. This option is ignored when any alignment specifier is present.
|
||||
The *sign* field controls how the sign of a numeric value is emitted. It
|
||||
applies to signed integer and floating-point types only.
|
||||
|
||||
The *precision* is a decimal number indicating how many digits should be
|
||||
displayed after the decimal point for a floating-point value formatted
|
||||
with `'f'` and `'F'`, or before and after the decimal point for a
|
||||
floating-point 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. Note that a
|
||||
C string must be null-terminated even if precision is specified.
|
||||
| Option | Effect |
|
||||
|--------|-------------------------------------------------------------------|
|
||||
| `+` | Always emit a sign (`+` for nonnegative values, `-` for negative).|
|
||||
| `-` | Emit `-` only for negative values. This is the default. |
|
||||
| space | Emit a leading space for nonnegative values and `-` for negative ones; useful for aligning columns of signed numbers. |
|
||||
|
||||
The `'L'` option uses the current locale setting to insert the appropriate
|
||||
number separator characters. This option is only valid for numeric types.
|
||||
The sign of `-0.0` is preserved in floating-point output.
|
||||
|
||||
Finally, the *type* determines how the data should be presented.
|
||||
```c++
|
||||
fmt::format("{:+d} {:+d}", 7, -7); // Result: "+7 -7"
|
||||
fmt::format("{: d} {: d}", 7, -7); // Result: " 7 -7"
|
||||
```
|
||||
|
||||
The available string presentation types are:
|
||||
### Alternate form (`#`)
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'s'</code></td>
|
||||
<td>
|
||||
String format. This is the default type for strings and may be omitted.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'?'</code></td>
|
||||
<td>Debug format. The string is quoted and special characters escaped.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>none</td>
|
||||
<td>The same as <code>'s'</code>.</td>
|
||||
</tr>
|
||||
</table>
|
||||
The `#` flag selects an *alternate form* whose exact meaning depends on the
|
||||
presentation type:
|
||||
|
||||
The available character presentation types are:
|
||||
- For integers rendered in binary, octal, or hexadecimal, it prepends the
|
||||
appropriate base prefix (`0b`/`0B`, `0`, or `0x`/`0X`). The case of the
|
||||
prefix follows the case of the type specifier — `0x` for `x`, `0X` for
|
||||
`X`, and so on.
|
||||
- For floating-point values, it forces the decimal point to appear in the
|
||||
output even if no fractional digits would otherwise be emitted, and
|
||||
prevents the `g`/`G` presentation types from removing trailing zeros from
|
||||
the significand.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'c'</code></td>
|
||||
<td>
|
||||
Character format. This is the default type for characters and may be
|
||||
omitted.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'?'</code></td>
|
||||
<td>Debug format. The character is quoted and special characters escaped.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>none</td>
|
||||
<td>The same as <code>'c'</code>.</td>
|
||||
</tr>
|
||||
</table>
|
||||
The `#` flag is not accepted by non-numeric types.
|
||||
|
||||
The available integer presentation types are:
|
||||
### Zero padding (`0`)
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'b'</code></td>
|
||||
<td>
|
||||
Binary format. Outputs the number in base 2. Using the <code>'#'</code>
|
||||
option with this type adds the prefix <code>"0b"</code> to the output value.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'B'</code></td>
|
||||
<td>
|
||||
Binary format. Outputs the number in base 2. Using the <code>'#'</code>
|
||||
option with this type adds the prefix <code>"0B"</code> to the output value.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'c'</code></td>
|
||||
<td>Character format. Outputs the number as a character.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'d'</code></td>
|
||||
<td>Decimal integer. Outputs the number in base 10.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'o'</code></td>
|
||||
<td>Octal format. Outputs the number in base 8.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'x'</code></td>
|
||||
<td>
|
||||
Hex format. Outputs the number in base 16, using lower-case letters for the
|
||||
digits above 9. Using the <code>'#'</code> option with this type adds the
|
||||
prefix <code>"0x"</code> to the output value.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'X'</code></td>
|
||||
<td>
|
||||
Hex format. Outputs the number in base 16, using upper-case letters for the
|
||||
digits above 9. Using the <code>'#'</code> option with this type adds the
|
||||
prefix <code>"0X"</code> to the output value.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>none</td>
|
||||
<td>The same as <code>'d'</code>.</td>
|
||||
</tr>
|
||||
</table>
|
||||
A `0` placed immediately before *width* enables sign-aware zero padding for
|
||||
numeric types. Zeros are inserted between the sign (or base prefix, if any)
|
||||
and the most significant digit, so that a sign or `0x` prefix stays adjacent
|
||||
to the digits rather than being separated by spaces. For example, `{:+08d}`
|
||||
applied to `120` produces `+0000120`.
|
||||
|
||||
Integer presentation types can also be used with character and Boolean values
|
||||
with the only exception that `'c'` cannot be used with `bool`. Boolean values
|
||||
are formatted using textual representation, either `true` or `false`, if the
|
||||
presentation type is not specified.
|
||||
Zero padding:
|
||||
|
||||
The available presentation types for floating-point values are:
|
||||
- applies only to numeric types;
|
||||
- has no effect on `inf` or `nan`;
|
||||
- is ignored when an explicit *align* is also present.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'a'</code></td>
|
||||
<td>
|
||||
Hexadecimal floating point format. Prints the number in base 16 with
|
||||
prefix <code>"0x"</code> and lower-case letters for digits above 9.
|
||||
Uses <code>'p'</code> to indicate the exponent.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'A'</code></td>
|
||||
<td>
|
||||
Same as <code>'a'</code> except it uses upper-case letters for the
|
||||
prefix, digits above 9 and to indicate the exponent.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'e'</code></td>
|
||||
<td>
|
||||
Exponent notation. Prints the number in scientific notation using
|
||||
the letter 'e' to indicate the exponent.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'E'</code></td>
|
||||
<td>
|
||||
Exponent notation. Same as <code>'e'</code> except it uses an
|
||||
upper-case <code>'E'</code> as the separator character.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'f'</code></td>
|
||||
<td>Fixed point. Displays the number as a fixed-point number.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'F'</code></td>
|
||||
<td>
|
||||
Fixed point. Same as <code>'f'</code>, but converts <code>nan</code>
|
||||
to <code>NAN</code> and <code>inf</code> to <code>INF</code>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'g'</code></td>
|
||||
<td>
|
||||
<p>General format. For a given precision <code>p >= 1</code>,
|
||||
this rounds the number to <code>p</code> significant digits and then
|
||||
formats the result in either fixed-point format or in scientific
|
||||
notation, depending on its magnitude.</p>
|
||||
<p>A precision of <code>0</code> is treated as equivalent to a precision
|
||||
of <code>1</code>.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'G'</code></td>
|
||||
<td>
|
||||
General format. Same as <code>'g'</code> except switches to
|
||||
<code>'E'</code> if the number gets too large. The representations of
|
||||
infinity and NaN are uppercased, too.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>none</td>
|
||||
<td>
|
||||
Similar to <code>'g'</code>, except that the default precision is as
|
||||
high as needed to represent the particular value.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
### Width
|
||||
|
||||
The available presentation types for pointers are:
|
||||
*width* is a non-negative decimal integer giving the minimum number of
|
||||
characters that the field should occupy. If the formatted value is shorter
|
||||
than *width*, it is padded according to *align* and *fill*; if it is longer,
|
||||
the value is written in full. *width* never causes the value to be
|
||||
truncated.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>'p'</code></td>
|
||||
<td>
|
||||
Pointer format. This is the default type for pointers and may be omitted.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>none</td>
|
||||
<td>The same as <code>'p'</code>.</td>
|
||||
</tr>
|
||||
</table>
|
||||
To supply *width* at runtime, write the field as `{}` to consume the next
|
||||
argument, or as `{arg_id}` to reference an integer argument by position or
|
||||
by name.
|
||||
|
||||
## Chrono Format Specifications
|
||||
When formatting strings, "width" is measured in display columns using a
|
||||
Unicode-aware estimate (East Asian wide and fullwidth characters, plus
|
||||
common emoji ranges, count as two columns; everything else counts as one).
|
||||
This keeps fixed *width* values visually consistent in monospace renderings
|
||||
that combine Latin and CJK text.
|
||||
|
||||
Format specifications for chrono duration and time point types as well as
|
||||
`std::tm` have the following syntax:
|
||||
```c++
|
||||
fmt::format("[{:6}]", 42);
|
||||
// Result: "[ 42]" - right-aligned by default
|
||||
fmt::format("[{:6}]", "hi");
|
||||
// Result: "[hi ]" - left-aligned by default
|
||||
fmt::format("[{:{}}]", 42, 6);
|
||||
// Result: "[ 42]" - width from an argument
|
||||
```
|
||||
|
||||
### Precision
|
||||
|
||||
*precision* is a non-negative decimal integer (introduced by `.`) whose
|
||||
meaning depends on the value being formatted. As with *width*, it may be
|
||||
supplied as a nested replacement field for runtime evaluation.
|
||||
|
||||
| Type | Meaning of `.precision` |
|
||||
|-------------------------------|-----------------------------------------------|
|
||||
| `e`, `E`, `f`, `F` | Digits emitted after the decimal point. |
|
||||
| `g`, `G` | Total number of significant digits. |
|
||||
| `a`, `A` | Digits after the decimal point in the hexadecimal significand. If omitted, just enough digits are emitted to round-trip the value exactly. |
|
||||
| Strings (`s`, `?`, or default) | Upper bound on the number of code points copied from the value. |
|
||||
|
||||
A *precision* is not accepted for integer, character, boolean, or pointer
|
||||
types. When a *precision* limits the number of characters taken from a C
|
||||
string, the string must still be null-terminated.
|
||||
|
||||
```c++
|
||||
fmt::format("{:.2f}", 3.14159); // Result: "3.14"
|
||||
fmt::format("{:.3g}", 3.14159); // Result: "3.14"
|
||||
fmt::format("{:.4}", "hello, world"); // Result: "hell"
|
||||
fmt::format("{:.{}f}", 3.14159, 4);
|
||||
// Result: "3.1416" - precision from an argument
|
||||
```
|
||||
|
||||
### Locale (`L`)
|
||||
|
||||
The `L` flag selects locale-sensitive formatting for numeric types. The
|
||||
formatter inspects the C++ locale supplied to the formatting function (or
|
||||
the global locale, if none was passed) and inserts the locale's digit
|
||||
grouping characters and — for floating-point values — its decimal point.
|
||||
The flag has no effect on non-numeric types.
|
||||
|
||||
```c++
|
||||
auto loc = std::locale("en_US.UTF-8");
|
||||
fmt::format(loc, "{:L}", 1234567890); // Result: "1,234,567,890"
|
||||
fmt::format(loc, "{:.2Lf}", 1234567.89); // Result: "1,234,567.89"
|
||||
```
|
||||
|
||||
### Presentation type
|
||||
|
||||
The *type* field chooses the representation for the value. Specifiers are
|
||||
grouped below by the value categories they apply to.
|
||||
|
||||
**Integers, booleans, and characters:**
|
||||
|
||||
| Type | Effect |
|
||||
|------|---------------------------------------------------------------------|
|
||||
| `b` | Base 2. The `#` flag adds a `0b` prefix. |
|
||||
| `B` | Base 2. The `#` flag adds a `0B` prefix. |
|
||||
| `c` | Render the integer as the character with that code point. Not allowed for `bool`. |
|
||||
| `d` | Base 10. The default for integer types. |
|
||||
| `o` | Base 8. |
|
||||
| `x` | Base 16, lower-case digits. The `#` flag adds a `0x` prefix. |
|
||||
| `X` | Base 16, upper-case digits. The `#` flag adds a `0X` prefix. |
|
||||
| none | Same as `d` for integers, `c` for characters, and the textual form (`true`/`false`) for `bool`. |
|
||||
|
||||
```c++
|
||||
fmt::format("{:d} {:#x} {:#o} {:#b}", 42, 42, 42, 42);
|
||||
// Result: "42 0x2a 052 0b101010"
|
||||
|
||||
fmt::format("{:#06x}", 0xfe); // # adds the prefix, 06 zero-pads to width 6
|
||||
// Result: "0x00fe"
|
||||
```
|
||||
|
||||
**Floating-point values:**
|
||||
|
||||
| Type | Effect |
|
||||
|------|---------------------------------------------------------------------|
|
||||
| `a` | Hexadecimal-significand form (e.g. `0x1.8p+1`). Lower-case digits and a lower-case `p` for the binary exponent. The `0x` prefix is always emitted, matching printf's `%a`. The `#` flag forces a decimal point (e.g. `0x1.p+1`).
|
||||
| `A` | Same as `a`, but upper-case throughout. |
|
||||
| `e` | Scientific notation with a lower-case `e` for the decimal exponent. |
|
||||
| `E` | Scientific notation with an upper-case `E`. |
|
||||
| `f` | Fixed-point notation. |
|
||||
| `F` | Same as `f`, but renders `nan` as `NAN` and `inf` as `INF`. |
|
||||
| `g` | General form: scientific notation when the exponent would be less than −4 or not less than the precision, otherwise fixed-point; trailing zeros are removed from the fractional part unless `#` is set. A precision of `0` is interpreted as `1`. |
|
||||
| `G` | Same as `g`, but uses `E` for the exponent and upper-case `INF`/`NAN`. |
|
||||
| none | Shortest round-trip representation: the formatted value, when parsed back into the same floating-point type, reproduces the input bit for bit. |
|
||||
|
||||
**Strings and characters:**
|
||||
|
||||
| Type | Effect |
|
||||
|------|---------------------------------------------------------------------|
|
||||
| `s` | Plain string output. Default for string types and for `bool` (which is rendered as `true` or `false`). |
|
||||
| `c` | Character output. Default for character types. Not allowed for `bool`. |
|
||||
| `?` | Debug output: the value is wrapped in single quotes (characters) or double quotes (strings), and non-printable, non-ASCII, and special characters are escaped using C-style escape sequences such as `\n`, `\t`, `\"`, and `\u{...}`. |
|
||||
| none | Same as `s` for strings and `bool`, and as `c` for characters. |
|
||||
|
||||
```c++
|
||||
fmt::format("{}", "tab\there"); // Result contains a literal tab character.
|
||||
fmt::format("{:?}", "tab\there"); // Result: "\"tab\\there\""
|
||||
```
|
||||
|
||||
**Pointers:**
|
||||
|
||||
| Type | Effect |
|
||||
|------|---------------------------------------------------------------------|
|
||||
| `p` | Hexadecimal address prefixed by `0x`. Default for pointer types. |
|
||||
| none | Same as `p`. |
|
||||
|
||||
A C string (`char*` or `const char*`) accepts both the string presentation
|
||||
types and `p`, so the same value can be formatted as either text or an
|
||||
address.
|
||||
|
||||
## Chrono Format Specification
|
||||
|
||||
The format specification for chrono duration and time point types as well
|
||||
as `std::tm` has the following syntax:
|
||||
|
||||
<a id="chrono-format-spec"></a>
|
||||
<pre><code class="language-json"
|
||||
@ -713,9 +605,25 @@ The available padding modifiers (*padding_modifier*) are:
|
||||
These modifiers are only supported for the `'H'`, `'I'`, `'M'`, `'S'`, `'U'`,
|
||||
`'V'`, `'W'`, `'Y'`, `'d'`, `'j'` and `'m'` presentation types.
|
||||
|
||||
## Range Format Specifications
|
||||
Example:
|
||||
|
||||
Format specifications for range types have the following syntax:
|
||||
```c++
|
||||
#include <fmt/chrono.h>
|
||||
|
||||
auto t = std::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
|
||||
```
|
||||
|
||||
## Range Format Specification
|
||||
|
||||
The format specification for range types has the following syntax:
|
||||
|
||||
<pre><code class="language-json"
|
||||
>range_format_spec ::= ["n"][range_type][":" range_underlying_spec]</code>
|
||||
@ -765,87 +673,11 @@ fmt::print("{:n:f}", std::array{std::numbers::pi, std::numbers::e});
|
||||
// Output: 3.141593, 2.718282
|
||||
```
|
||||
|
||||
## Format Examples
|
||||
## A Combined Example
|
||||
|
||||
This section contains examples of the format syntax and comparison with
|
||||
the `printf` formatting.
|
||||
|
||||
In most of the cases the syntax is similar to the `printf` formatting,
|
||||
with the addition of the `{}` and with `:` used instead of `%`. For
|
||||
example, `"%03.2f"` can be translated to `"{:03.2f}"`.
|
||||
|
||||
The new format syntax also supports new and different options, shown in
|
||||
the following examples.
|
||||
|
||||
Accessing arguments by position:
|
||||
|
||||
```c++
|
||||
fmt::format("{0}, {1}, {2}", 'a', 'b', 'c');
|
||||
// Result: "a, b, c"
|
||||
fmt::format("{}, {}, {}", 'a', 'b', 'c');
|
||||
// Result: "a, b, c"
|
||||
fmt::format("{2}, {1}, {0}", 'a', 'b', 'c');
|
||||
// Result: "c, b, a"
|
||||
fmt::format("{0}{1}{0}", "abra", "cad"); // arguments' indices can be repeated
|
||||
// Result: "abracadabra"
|
||||
```
|
||||
|
||||
Aligning the text and specifying a width:
|
||||
|
||||
```c++
|
||||
fmt::format("{:<30}", "left aligned");
|
||||
// Result: "left aligned "
|
||||
fmt::format("{:>30}", "right aligned");
|
||||
// Result: " right aligned"
|
||||
fmt::format("{:^30}", "centered");
|
||||
// Result: " centered "
|
||||
fmt::format("{:*^30}", "centered"); // use '*' as a fill char
|
||||
// Result: "***********centered***********"
|
||||
```
|
||||
|
||||
Dynamic width:
|
||||
|
||||
```c++
|
||||
fmt::format("{:<{}}", "left aligned", 30);
|
||||
// Result: "left aligned "
|
||||
```
|
||||
|
||||
Dynamic precision:
|
||||
|
||||
```c++
|
||||
fmt::format("{:.{}f}", 3.14, 1);
|
||||
// Result: "3.1"
|
||||
```
|
||||
|
||||
Replacing `%+f`, `%-f`, and `% f` and specifying a sign:
|
||||
|
||||
```c++
|
||||
fmt::format("{:+f}; {:+f}", 3.14, -3.14); // show it always
|
||||
// Result: "+3.140000; -3.140000"
|
||||
fmt::format("{: f}; {: f}", 3.14, -3.14); // show a space for positive numbers
|
||||
// Result: " 3.140000; -3.140000"
|
||||
fmt::format("{:-f}; {:-f}", 3.14, -3.14); // show only the minus -- same as '{:f}; {:f}'
|
||||
// Result: "3.140000; -3.140000"
|
||||
```
|
||||
|
||||
Replacing `%x` and `%o` and converting the value to different bases:
|
||||
|
||||
```c++
|
||||
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:
|
||||
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:
|
||||
|
||||
```c++
|
||||
fmt::format("{:#04x}", 0);
|
||||
// Result: "0x00"
|
||||
```
|
||||
|
||||
Box drawing using Unicode fill:
|
||||
The example below ties together several elements introduced above — nested
|
||||
replacement fields, fill characters, and centering — to draw a fixed-width
|
||||
box around a message:
|
||||
|
||||
```c++
|
||||
fmt::print(
|
||||
@ -854,35 +686,10 @@ fmt::print(
|
||||
"└{0:─^{2}}┘\n", "", "Hello, world!", 20);
|
||||
```
|
||||
|
||||
prints:
|
||||
Output:
|
||||
|
||||
```
|
||||
┌────────────────────┐
|
||||
│ Hello, world! │
|
||||
└────────────────────┘
|
||||
```
|
||||
|
||||
Using type-specific formatting:
|
||||
|
||||
```c++
|
||||
#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:
|
||||
|
||||
```c++
|
||||
#include <fmt/format.h>
|
||||
|
||||
auto s = fmt::format(std::locale("en_US.UTF-8"), "{:L}", 1234567890);
|
||||
// s == "1,234,567,890"
|
||||
```
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - dynamic argument lists
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - the base API for char/UTF-8
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -21,7 +21,7 @@
|
||||
#endif
|
||||
|
||||
// The fmt library version in the form major * 10000 + minor * 100 + patch.
|
||||
#define FMT_VERSION 120101
|
||||
#define FMT_VERSION 120200
|
||||
|
||||
// Detect compiler versions.
|
||||
#if defined(__clang__) && !defined(__ibmxl__)
|
||||
@ -223,13 +223,26 @@
|
||||
#else
|
||||
# define FMT_PRAGMA_CLANG(x)
|
||||
#endif
|
||||
#if FMT_MSC_VERSION
|
||||
# define FMT_PRAGMA_MSVC(x) __pragma(x)
|
||||
#else
|
||||
# define FMT_PRAGMA_MSVC(x)
|
||||
#endif
|
||||
|
||||
#ifndef FMT_USE_OPTIMIZE_PRAGMA
|
||||
# define FMT_USE_OPTIMIZE_PRAGMA 1
|
||||
#endif
|
||||
|
||||
// Enable minimal optimizations for more compact code in debug mode.
|
||||
FMT_PRAGMA_GCC(push_options)
|
||||
#if !defined(__OPTIMIZE__) && !defined(__CUDACC__) && !defined(FMT_MODULE)
|
||||
#if FMT_USE_OPTIMIZE_PRAGMA && !defined(__OPTIMIZE__) && \
|
||||
!defined(__CUDACC__) && !defined(FMT_MODULE)
|
||||
FMT_PRAGMA_GCC(optimize("Og"))
|
||||
#endif
|
||||
|
||||
FMT_PRAGMA_MSVC(warning(push))
|
||||
FMT_PRAGMA_MSVC(warning(disable : 4702))
|
||||
|
||||
#ifdef FMT_DEPRECATED
|
||||
// Use the provided definition.
|
||||
#elif FMT_HAS_CPP14_ATTRIBUTE(deprecated)
|
||||
@ -484,6 +497,15 @@ inline FMT_CONSTEXPR auto get_container(OutputIt it) ->
|
||||
};
|
||||
return *accessor(it).container;
|
||||
}
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct is_contiguous : std::false_type {};
|
||||
template <typename T>
|
||||
struct is_contiguous<T,
|
||||
void_t<decltype(std::declval<T&>().data()),
|
||||
decltype(std::declval<T&>().size()),
|
||||
decltype(std::declval<T&>().operator[](size_t()))>>
|
||||
: std::true_type {};
|
||||
} // namespace detail
|
||||
|
||||
// Parsing-related public API and forward declarations.
|
||||
@ -587,9 +609,6 @@ using string_view = basic_string_view<char>;
|
||||
template <typename T> class basic_appender;
|
||||
using appender = basic_appender<char>;
|
||||
|
||||
// Checks whether T is a container with contiguous storage.
|
||||
template <typename T> struct is_contiguous : std::false_type {};
|
||||
|
||||
class context;
|
||||
template <typename OutputIt, typename Char> class generic_context;
|
||||
template <typename Char> class parse_context;
|
||||
@ -608,6 +627,8 @@ using buffered_context =
|
||||
conditional_t<std::is_same<Char, char>::value, context,
|
||||
generic_context<basic_appender<Char>, Char>>;
|
||||
|
||||
template <typename T> struct is_contiguous : detail::is_contiguous<T> {};
|
||||
|
||||
template <typename Context> class basic_format_arg;
|
||||
template <typename Context> class basic_format_args;
|
||||
|
||||
@ -1858,6 +1879,54 @@ class fixed_buffer_traits {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename OutputIt, typename InputIt, typename = void>
|
||||
struct has_append : std::false_type {};
|
||||
|
||||
template <typename OutputIt, typename InputIt>
|
||||
struct has_append<OutputIt, InputIt,
|
||||
void_t<decltype(get_container(std::declval<OutputIt>())
|
||||
.append(std::declval<InputIt>(),
|
||||
std::declval<InputIt>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename OutputIt, typename T, typename = void>
|
||||
struct has_insert : std::false_type {};
|
||||
|
||||
template <typename OutputIt, typename T>
|
||||
struct has_insert<
|
||||
OutputIt, T,
|
||||
void_t<decltype(get_container(std::declval<OutputIt>())
|
||||
.insert({}, std::declval<T>(), std::declval<T>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
// An optimized version of std::copy with the output value type (T).
|
||||
template <typename T, typename InputIt, typename OutputIt,
|
||||
FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>() &&
|
||||
has_append<OutputIt, InputIt>())>
|
||||
FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
|
||||
get_container(out).append(begin, end);
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename T, typename InputIt, typename OutputIt,
|
||||
FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>() &&
|
||||
!has_append<OutputIt, InputIt>() &&
|
||||
has_insert<OutputIt, InputIt>())>
|
||||
FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
|
||||
auto& c = get_container(out);
|
||||
c.insert(c.end(), begin, end);
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename T, typename InputIt, typename OutputIt,
|
||||
FMT_ENABLE_IF(!is_back_insert_iterator<OutputIt>() ||
|
||||
!(has_append<OutputIt, InputIt>() ||
|
||||
has_insert<OutputIt, InputIt>()))>
|
||||
FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
|
||||
while (begin != end) *out++ = static_cast<T>(*begin++);
|
||||
return out;
|
||||
}
|
||||
|
||||
// A buffer that writes to an output iterator when flushed.
|
||||
template <typename OutputIt, typename T, typename Traits = buffer_traits>
|
||||
class iterator_buffer : public Traits, public buffer<T> {
|
||||
@ -1875,7 +1944,7 @@ class iterator_buffer : public Traits, public buffer<T> {
|
||||
this->clear();
|
||||
const T* begin = data_;
|
||||
const T* end = begin + this->limit(size);
|
||||
while (begin != end) *out_++ = *begin++;
|
||||
out_ = copy<T>(begin, end, out_);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -2533,7 +2602,7 @@ template <typename Context> class basic_format_args {
|
||||
FMT_CONSTEXPR auto get(int id) const -> format_arg {
|
||||
auto arg = format_arg();
|
||||
if (!is_packed()) {
|
||||
if (id < max_size()) arg = args_[id];
|
||||
if (unsigned(id) < unsigned(max_size())) arg = args_[id];
|
||||
return arg;
|
||||
}
|
||||
if (unsigned(id) >= detail::max_packed_args) return arg;
|
||||
@ -2644,16 +2713,16 @@ template <typename... T> struct fstring {
|
||||
static_assert(count<(is_view<remove_cvref_t<T>>::value &&
|
||||
std::is_reference<T>::value)...>() == 0,
|
||||
"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>(str, checker(str, arg_pack()));
|
||||
constexpr bool unused = detail::enforce_compile_checks<sizeof(s) != 0>();
|
||||
(void)unused;
|
||||
}
|
||||
template <typename S,
|
||||
FMT_ENABLE_IF(std::is_convertible<const S&, string_view>::value)>
|
||||
FMT_CONSTEVAL FMT_ALWAYS_INLINE fstring(const S& s) : str(s) {
|
||||
auto sv = string_view(str);
|
||||
if (FMT_USE_CONSTEVAL)
|
||||
detail::parse_format_string<char>(sv, checker(sv, arg_pack()));
|
||||
detail::parse_format_string<char>(str, checker(str, arg_pack()));
|
||||
constexpr bool unused = detail::enforce_compile_checks<sizeof(s) != 0>();
|
||||
(void)unused;
|
||||
}
|
||||
@ -2877,6 +2946,7 @@ FMT_INLINE void println(format_string<T...> fmt, T&&... args) {
|
||||
}
|
||||
|
||||
FMT_PRAGMA_GCC(pop_options)
|
||||
FMT_PRAGMA_MSVC(warning(pop))
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - chrono support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -934,10 +934,9 @@ inline auto to_nonnegative_int(T value, Int upper) -> Int {
|
||||
}
|
||||
template <typename T, typename Int, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||
inline auto to_nonnegative_int(T value, Int upper) -> Int {
|
||||
auto int_value = static_cast<Int>(value);
|
||||
if (int_value < 0 || value > static_cast<T>(upper))
|
||||
if (value < 0 || value >= static_cast<T>(upper) + 1)
|
||||
FMT_THROW(format_error("invalid value"));
|
||||
return int_value;
|
||||
return static_cast<Int>(value);
|
||||
}
|
||||
|
||||
constexpr auto pow10(std::uint32_t n) -> long long {
|
||||
@ -1192,6 +1191,7 @@ class tm_writer {
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(has_tm_zone<T>::value)>
|
||||
void format_tz_name(const T& tm) {
|
||||
if (!tm.tm_zone) FMT_THROW(format_error("no timezone"));
|
||||
out_ = write_tm_str<Char>(out_, tm.tm_zone, loc_);
|
||||
}
|
||||
template <typename T, FMT_ENABLE_IF(!has_tm_zone<T>::value)>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - color support
|
||||
//
|
||||
// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors
|
||||
// Copyright (c) 2018 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -471,7 +471,7 @@ template <typename Char> inline void reset_color(buffer<Char>& buffer) {
|
||||
template <typename T> struct styled_arg : view {
|
||||
const T& value;
|
||||
text_style style;
|
||||
styled_arg(const T& v, text_style s) : value(v), style(s) {}
|
||||
FMT_CONSTEXPR styled_arg(const T& v, text_style s) : value(v), style(s) {}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
@ -528,6 +528,42 @@ void print(text_style ts, format_string<T...> fmt, T&&... args) {
|
||||
return print(stdout, ts, fmt, std::forward<T>(args)...);
|
||||
}
|
||||
|
||||
inline void vprintln(FILE* f, text_style ts, string_view fmt,
|
||||
format_args args) {
|
||||
auto buf = memory_buffer();
|
||||
detail::vformat_to(buf, ts, fmt, args);
|
||||
buf.push_back('\n');
|
||||
print(f, FMT_STRING("{}"), string_view(buf.begin(), buf.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a string and prints it to the specified file stream followed by a
|
||||
* newline, using ANSI escape sequences to specify text formatting.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::println(fmt::emphasis::bold | fg(fmt::color::red),
|
||||
* "Elapsed time: {0:.2f} seconds", 1.23);
|
||||
*/
|
||||
template <typename... T>
|
||||
void println(FILE* f, text_style ts, format_string<T...> fmt, T&&... args) {
|
||||
vprintln(f, ts, fmt.str, vargs<T...>{{args...}});
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a string and prints it to stdout followed by a newline, using ANSI
|
||||
* escape sequences to specify text formatting.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* fmt::println(fmt::emphasis::bold | fg(fmt::color::red),
|
||||
* "Elapsed time: {0:.2f} seconds", 1.23);
|
||||
*/
|
||||
template <typename... T>
|
||||
void println(text_style ts, format_string<T...> fmt, T&&... args) {
|
||||
return println(stdout, ts, fmt, std::forward<T>(args)...);
|
||||
}
|
||||
|
||||
inline auto vformat(text_style ts, string_view fmt, format_args args)
|
||||
-> std::string {
|
||||
auto buf = memory_buffer();
|
||||
@ -583,8 +619,8 @@ inline auto format_to(OutputIt out, text_style ts, format_string<T...> fmt,
|
||||
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()) {
|
||||
FMT_CONSTEXPR auto format(const detail::styled_arg<T>& arg,
|
||||
FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
const auto& ts = arg.style;
|
||||
auto out = ctx.out();
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - experimental format string compilation
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -178,6 +178,10 @@ template <typename Char, typename V, int N> struct field {
|
||||
if constexpr (std::is_convertible<V, basic_string_view<Char>>::value) {
|
||||
auto s = basic_string_view<Char>(arg);
|
||||
return copy<Char>(s.begin(), s.end(), out);
|
||||
} else if constexpr (use_format_as<V>::value) {
|
||||
return write<Char>(out, format_as(arg));
|
||||
} else if constexpr (use_format_as_member<V>::value) {
|
||||
return write<Char>(out, formatter<V>::format_as(arg));
|
||||
} else {
|
||||
return write<Char>(out, arg);
|
||||
}
|
||||
|
||||
@ -1,3 +1,10 @@
|
||||
// Formatting library for C++ - core API
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#include "base.h"
|
||||
|
||||
// Using fmt::format via fmt/core.h has been deprecated since version 11
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - the C API
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -10,6 +10,24 @@
|
||||
|
||||
#include <stdbool.h> // bool
|
||||
#include <stddef.h> // size_t
|
||||
#include <stdio.h> // FILE
|
||||
|
||||
#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
|
||||
# if defined(FMT_LIB_EXPORT)
|
||||
# define FMT_CAPI __declspec(dllexport)
|
||||
# elif defined(FMT_SHARED)
|
||||
# define FMT_CAPI __declspec(dllimport)
|
||||
# endif
|
||||
#elif defined(FMT_LIB_EXPORT) || defined(FMT_SHARED)
|
||||
# ifdef __GNUC__
|
||||
# define FMT_CAPI __attribute__((visibility("default")))
|
||||
# else
|
||||
# define FMT_CAPI
|
||||
# endif
|
||||
#endif
|
||||
#ifndef FMT_CAPI
|
||||
# define FMT_CAPI
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -44,8 +62,10 @@ typedef struct {
|
||||
|
||||
enum { fmt_error = -1, fmt_error_invalid_arg = -2 };
|
||||
|
||||
int fmt_vformat(char* buffer, size_t size, const char* fmt, const fmt_arg* args,
|
||||
size_t num_args);
|
||||
int FMT_CAPI fmt_vformat(char* buffer, size_t size, const char* fmt,
|
||||
const fmt_arg* args, size_t num_args);
|
||||
int FMT_CAPI fmt_vprint(FILE* stream, const char* fmt, const fmt_arg* args,
|
||||
size_t num_args);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@ -89,7 +109,7 @@ static inline fmt_arg fmt_from_ptr(const void* x) {
|
||||
return (fmt_arg){.type = fmt_pointer, .value.pointer = x};
|
||||
}
|
||||
|
||||
void fmt_unsupported_type(void);
|
||||
void FMT_CAPI fmt_unsupported_type(void);
|
||||
|
||||
# if !defined(_MSC_VER) || defined(__clang__)
|
||||
typedef signed char fmt_signed_char;
|
||||
@ -181,12 +201,17 @@ typedef enum {} fmt_signed_char;
|
||||
(fmt_arg[]) { FMT_MAP(FMT_MAKE_ARG, ##__VA_ARGS__) }
|
||||
# define FMT_EXPAND(v) v
|
||||
|
||||
# define fmt_format(buffer, size, fmt, ...) \
|
||||
fmt_vformat( \
|
||||
(buffer), (size), (fmt), \
|
||||
FMT_EXPAND(FMT_VA_SELECT( \
|
||||
FMT_MAKE_NULL, FMT_MAKE_ARGLIST, ##__VA_ARGS__)(__VA_ARGS__)), \
|
||||
FMT_NARG(, ##__VA_ARGS__))
|
||||
# define FMT_FORMAT_ARGS(fmt, ...) \
|
||||
(fmt), \
|
||||
FMT_EXPAND(FMT_VA_SELECT(FMT_MAKE_NULL, FMT_MAKE_ARGLIST, \
|
||||
##__VA_ARGS__)(__VA_ARGS__)), \
|
||||
FMT_NARG(, ##__VA_ARGS__)
|
||||
|
||||
# define fmt_format(buffer, size, fmt, ...) \
|
||||
fmt_vformat((buffer), (size), FMT_FORMAT_ARGS((fmt), ##__VA_ARGS__))
|
||||
|
||||
# define fmt_print(stream, fmt, ...) \
|
||||
fmt_vprint((stream), FMT_FORMAT_ARGS((fmt), ##__VA_ARGS__))
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - implementation
|
||||
//
|
||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -8,15 +8,17 @@
|
||||
#ifndef FMT_FORMAT_INL_H_
|
||||
#define FMT_FORMAT_INL_H_
|
||||
|
||||
#ifdef __SANITIZE_THREAD__
|
||||
extern "C" void __tsan_acquire(void*);
|
||||
extern "C" void __tsan_release(void*);
|
||||
#endif
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <stddef.h> // ptrdiff_t
|
||||
|
||||
# include <algorithm>
|
||||
# include <cerrno> // errno
|
||||
# include <climits>
|
||||
# include <cmath>
|
||||
# include <exception>
|
||||
# include <new> // std::bad_alloc
|
||||
# include <new> // std::bad_alloc
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(FMT_USE_WRITE_CONSOLE)
|
||||
@ -1477,10 +1479,10 @@ template <typename T> struct span {
|
||||
};
|
||||
|
||||
template <typename F> auto flockfile(F* f) -> decltype(_lock_file(f)) {
|
||||
_lock_file(f);
|
||||
return _lock_file(f);
|
||||
}
|
||||
template <typename F> auto funlockfile(F* f) -> decltype(_unlock_file(f)) {
|
||||
_unlock_file(f);
|
||||
return _unlock_file(f);
|
||||
}
|
||||
|
||||
#ifndef getc_unlocked
|
||||
@ -1524,7 +1526,10 @@ template <typename F> class file_base {
|
||||
FMT_THROW(system_error(errno, FMT_STRING("ungetc failed")));
|
||||
}
|
||||
|
||||
void flush() { fflush(this->file_); }
|
||||
void flush() {
|
||||
if (fflush(this->file_) != 0)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("fflush failed")));
|
||||
}
|
||||
};
|
||||
|
||||
// A FILE wrapper for glibc.
|
||||
@ -1570,7 +1575,10 @@ template <typename F> class glibc_file : public file_base<F> {
|
||||
return memchr(end, '\n', static_cast<size_t>(size));
|
||||
}
|
||||
|
||||
void flush() { fflush_unlocked(this->file_); }
|
||||
void flush() {
|
||||
if (fflush_unlocked(this->file_) != 0)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("fflush failed")));
|
||||
}
|
||||
};
|
||||
|
||||
// A FILE wrapper for Apple's libc.
|
||||
@ -1696,6 +1704,9 @@ class file_print_buffer<F, enable_if_t<has_flockfile<F>::value>>
|
||||
public:
|
||||
explicit file_print_buffer(F* f) : buffer(grow, size_t()), file_(f) {
|
||||
flockfile(f);
|
||||
#ifdef __SANITIZE_THREAD__
|
||||
__tsan_acquire(f);
|
||||
#endif
|
||||
file_.init_buffer();
|
||||
auto buf = file_.get_write_buffer();
|
||||
set(buf.data, buf.size);
|
||||
@ -1703,7 +1714,10 @@ class file_print_buffer<F, enable_if_t<has_flockfile<F>::value>>
|
||||
~file_print_buffer() {
|
||||
file_.advance_write_buffer(size());
|
||||
bool flush = file_.needs_flush();
|
||||
F* f = file_; // Make funlockfile depend on the template parameter F
|
||||
F* f = file_; // Make funlockfile depend on the template parameter F.
|
||||
#ifdef __SANITIZE_THREAD__
|
||||
__tsan_release(f);
|
||||
#endif
|
||||
funlockfile(f); // for the system API detection to work.
|
||||
if (flush) fflush(file_);
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
Formatting library for C++
|
||||
|
||||
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
|
||||
@ -326,6 +326,9 @@ class uint128 {
|
||||
-> uint128 {
|
||||
return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_};
|
||||
}
|
||||
friend constexpr auto operator~(const uint128& n) -> uint128 {
|
||||
return {~n.hi_, ~n.lo_};
|
||||
}
|
||||
friend FMT_CONSTEXPR auto operator+(const uint128& lhs, const uint128& rhs)
|
||||
-> uint128 {
|
||||
auto result = uint128(lhs);
|
||||
@ -548,60 +551,6 @@ FMT_CONSTEXPR20 auto fill_n(T* out, Size count, char value) -> T* {
|
||||
return out + count;
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename InputIt, typename = void>
|
||||
struct has_back_insert_iterator_container_append : std::false_type {};
|
||||
|
||||
template <typename OutputIt, typename InputIt>
|
||||
struct has_back_insert_iterator_container_append<
|
||||
OutputIt, InputIt,
|
||||
void_t<decltype(get_container(std::declval<OutputIt>())
|
||||
.append(std::declval<InputIt>(),
|
||||
std::declval<InputIt>()))>> : std::true_type {};
|
||||
|
||||
template <typename OutputIt, typename InputIt, typename = void>
|
||||
struct has_back_insert_iterator_container_insert_at_end : std::false_type {};
|
||||
|
||||
template <typename OutputIt, typename InputIt>
|
||||
struct has_back_insert_iterator_container_insert_at_end<
|
||||
OutputIt, InputIt,
|
||||
void_t<decltype(get_container(std::declval<OutputIt>())
|
||||
.insert(get_container(std::declval<OutputIt>()).end(),
|
||||
std::declval<InputIt>(),
|
||||
std::declval<InputIt>()))>> : std::true_type {};
|
||||
|
||||
// An optimized version of std::copy with the output value type (T).
|
||||
template <typename T, typename InputIt, typename OutputIt,
|
||||
FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value&&
|
||||
has_back_insert_iterator_container_append<
|
||||
OutputIt, InputIt>::value)>
|
||||
FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
|
||||
get_container(out).append(begin, end);
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename T, typename InputIt, typename OutputIt,
|
||||
FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value &&
|
||||
!has_back_insert_iterator_container_append<
|
||||
OutputIt, InputIt>::value &&
|
||||
has_back_insert_iterator_container_insert_at_end<
|
||||
OutputIt, InputIt>::value)>
|
||||
FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
|
||||
auto& c = get_container(out);
|
||||
c.insert(c.end(), begin, end);
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename T, typename InputIt, typename OutputIt,
|
||||
FMT_ENABLE_IF(!(is_back_insert_iterator<OutputIt>::value &&
|
||||
(has_back_insert_iterator_container_append<
|
||||
OutputIt, InputIt>::value ||
|
||||
has_back_insert_iterator_container_insert_at_end<
|
||||
OutputIt, InputIt>::value)))>
|
||||
FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
|
||||
while (begin != end) *out++ = static_cast<T>(*begin++);
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename T, typename V, typename OutputIt>
|
||||
FMT_CONSTEXPR auto copy(basic_string_view<V> s, OutputIt out) -> OutputIt {
|
||||
return copy<T>(s.begin(), s.end(), out);
|
||||
@ -1115,12 +1064,6 @@ template <typename T> FMT_CONSTEXPR auto count_digits_fallback(T n) -> int {
|
||||
count += 4;
|
||||
}
|
||||
}
|
||||
#if FMT_USE_INT128
|
||||
FMT_CONSTEXPR inline auto count_digits(native_uint128 n) -> int {
|
||||
return count_digits_fallback(n);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FMT_BUILTIN_CLZLL
|
||||
// It is a separate function rather than a part of count_digits to workaround
|
||||
// the lack of static constexpr in constexpr functions.
|
||||
@ -1151,6 +1094,20 @@ FMT_CONSTEXPR20 inline auto count_digits(uint64_t n) -> int {
|
||||
return count_digits_fallback(n);
|
||||
}
|
||||
|
||||
#if FMT_USE_INT128
|
||||
FMT_CONSTEXPR20 inline auto count_digits(native_uint128 n) -> int {
|
||||
if (is_constant_evaluated()) return count_digits_fallback(n);
|
||||
// 128-bit division is a slow library call, so reduce to 64-bit chunks via
|
||||
// 10^19 (the largest power of 10 fitting in uint64_t).
|
||||
const uint64_t pow10_19 = 10000000000000000000ULL;
|
||||
if ((n >> 64) == 0) return count_digits(static_cast<uint64_t>(n));
|
||||
n /= pow10_19;
|
||||
if ((n >> 64) == 0) return count_digits(static_cast<uint64_t>(n)) + 19;
|
||||
n /= pow10_19;
|
||||
return count_digits(static_cast<uint64_t>(n)) + 38;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Counts the number of digits in n. BITS = log2(radix).
|
||||
template <int BITS, typename UInt>
|
||||
FMT_CONSTEXPR auto count_digits(UInt n) -> int {
|
||||
@ -1282,10 +1239,30 @@ template <typename Char, typename UInt>
|
||||
FMT_CONSTEXPR20 auto do_format_decimal(Char* out, UInt value, int size)
|
||||
-> Char* {
|
||||
FMT_ASSERT(size >= count_digits(value), "invalid digit count");
|
||||
#if FMT_USE_INT128
|
||||
// Avoid slow 128-bit division by formatting 64-bit chunks of 19 digits each.
|
||||
if (!is_constant_evaluated() && num_bits<UInt>() == 128) {
|
||||
const uint64_t pow10_19 = 10000000000000000000ULL;
|
||||
auto v = static_cast<native_uint128>(value);
|
||||
unsigned pos = to_unsigned(size);
|
||||
while ((v >> 64) != 0) {
|
||||
auto chunk = static_cast<uint64_t>(v % pow10_19);
|
||||
v /= pow10_19;
|
||||
pos -= 19;
|
||||
fill_n(out + pos, 19, Char('0'));
|
||||
do_format_decimal(out + pos, chunk, 19);
|
||||
}
|
||||
auto top = static_cast<uint64_t>(v);
|
||||
int top_digits = count_digits(top);
|
||||
pos -= to_unsigned(top_digits);
|
||||
do_format_decimal(out + pos, top, top_digits);
|
||||
return out + pos;
|
||||
}
|
||||
#endif // FMT_USE_INT128
|
||||
unsigned n = to_unsigned(size);
|
||||
while (value >= 100) {
|
||||
n -= 2;
|
||||
if (!is_constant_evaluated() && sizeof(UInt) == 4) {
|
||||
if (!is_constant_evaluated() && num_bits<UInt>() == 32) {
|
||||
auto p = value * static_cast<uint64_t>((1ull << 39) / 100 + 1);
|
||||
write2digits_i(out + n, p >> (39 - 7) & ((1 << 7) - 1));
|
||||
value = static_cast<UInt>(p >> 39) +
|
||||
@ -2012,6 +1989,15 @@ FMT_CONSTEXPR inline void prefix_append(unsigned& prefix, unsigned value) {
|
||||
prefix += (1u + (value > 0xff ? 1 : 0)) << 24;
|
||||
}
|
||||
|
||||
// Writes an integer as a character, treating chars as unsigned.
|
||||
template <typename Char, typename OutputIt, typename UInt>
|
||||
FMT_CONSTEXPR auto write_int_chr(OutputIt out, UInt abs_value, bool negative,
|
||||
const format_specs& specs) -> OutputIt {
|
||||
if (negative || abs_value > max_value<make_unsigned_t<Char>>())
|
||||
report_error("character value out of range");
|
||||
return write_char<Char>(out, static_cast<Char>(abs_value), specs);
|
||||
}
|
||||
|
||||
// Writes a decimal integer with digit grouping.
|
||||
template <typename OutputIt, typename UInt, typename Char>
|
||||
auto write_int(OutputIt out, UInt value, unsigned prefix,
|
||||
@ -2048,7 +2034,7 @@ auto write_int(OutputIt out, UInt value, unsigned prefix,
|
||||
format_base2e<char>(1, appender(buffer), value, num_digits);
|
||||
break;
|
||||
case presentation_type::chr:
|
||||
return write_char<Char>(out, static_cast<Char>(value), specs);
|
||||
return write_int_chr<Char>(out, value, (prefix & 0xff) == '-', specs);
|
||||
}
|
||||
|
||||
unsigned size = (prefix != 0 ? prefix >> 24 : 0) + to_unsigned(num_digits) +
|
||||
@ -2175,7 +2161,7 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg<T> arg,
|
||||
prefix_append(prefix, unsigned(specs.upper() ? 'B' : 'b') << 8 | '0');
|
||||
break;
|
||||
case presentation_type::chr:
|
||||
return write_char<Char>(out, static_cast<Char>(abs_value), specs);
|
||||
return write_int_chr<Char>(out, abs_value, (prefix & 0xff) == '-', specs);
|
||||
}
|
||||
|
||||
// Write an integer in the format
|
||||
@ -2208,29 +2194,19 @@ FMT_CONSTEXPR FMT_NOINLINE auto write_int_noinline(OutputIt out,
|
||||
return write_int<Char>(out, arg, specs);
|
||||
}
|
||||
|
||||
template <typename Char, typename T,
|
||||
FMT_ENABLE_IF(is_integral<T>::value &&
|
||||
!std::is_same<T, bool>::value &&
|
||||
!std::is_same<T, Char>::value)>
|
||||
FMT_CONSTEXPR FMT_INLINE auto write(basic_appender<Char> out, T value,
|
||||
const format_specs& specs, locale_ref loc)
|
||||
-> basic_appender<Char> {
|
||||
if (specs.localized() && write_loc(out, value, specs, loc)) return out;
|
||||
return write_int_noinline<Char>(out, make_write_int_arg(value, specs.sign()),
|
||||
specs);
|
||||
}
|
||||
|
||||
// An inlined version of write used in format string compilation.
|
||||
template <typename Char, typename OutputIt, typename T,
|
||||
FMT_ENABLE_IF(is_integral<T>::value &&
|
||||
!std::is_same<T, bool>::value &&
|
||||
!std::is_same<T, Char>::value &&
|
||||
!std::is_same<OutputIt, basic_appender<Char>>::value)>
|
||||
!std::is_same<T, Char>::value)>
|
||||
FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value,
|
||||
const format_specs& specs, locale_ref loc)
|
||||
-> OutputIt {
|
||||
if (specs.localized() && write_loc(out, value, specs, loc)) return out;
|
||||
return write_int<Char>(out, make_write_int_arg(value, specs.sign()), specs);
|
||||
auto arg = make_write_int_arg(value, specs.sign());
|
||||
// Out of line for appenders to avoid bloat; inlined for compiled formatting.
|
||||
if FMT_CONSTEXPR20 (std::is_same<OutputIt, basic_appender<Char>>::value)
|
||||
return write_int_noinline<Char>(out, arg, specs);
|
||||
return write_int<Char>(out, arg, specs);
|
||||
}
|
||||
|
||||
template <typename Char, typename OutputIt>
|
||||
@ -3215,8 +3191,9 @@ constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t {
|
||||
// It is equal to ceil(2^31 + 2^32/10^(k + 1)).
|
||||
// These are stored in a string literal because we cannot have static arrays
|
||||
// in constexpr functions and non-static ones are poorly optimized.
|
||||
return U"\x9999999a\x828f5c29\x80418938\x80068db9\x8000a7c6\x800010c7"
|
||||
U"\x800001ae\x8000002b"[index];
|
||||
return uint32_t(u"\x9999\x828f\x8041\x8006\x8000\x8000\x8000\x8000"[index])
|
||||
<< 16u |
|
||||
uint32_t(u"\x999a\x5c29\x8938\x8db9\xa7c6\x10c7\x01ae\x002b"[index]);
|
||||
}
|
||||
|
||||
template <typename Float>
|
||||
@ -3941,7 +3918,7 @@ template <typename OutputIt, typename Char> class generic_context {
|
||||
|
||||
constexpr auto out() const -> iterator { return out_; }
|
||||
|
||||
void advance_to(iterator it) {
|
||||
FMT_CONSTEXPR void advance_to(iterator it) {
|
||||
if (!detail::is_back_insert_iterator<iterator>()) out_ = it;
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - optional OS-specific functionality
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - std::ostream support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - legacy printf implementation
|
||||
//
|
||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -330,6 +330,7 @@ template <typename Char, typename GetArg>
|
||||
auto parse_header(const Char*& it, const Char* end, format_specs& specs,
|
||||
GetArg get_arg) -> int {
|
||||
int arg_index = -1;
|
||||
if (it == end) return arg_index;
|
||||
Char c = *it;
|
||||
if (c >= '0' && c <= '9') {
|
||||
// Parse an argument index (if followed by '$') or a width possibly
|
||||
@ -437,6 +438,8 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
||||
}
|
||||
write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start)));
|
||||
|
||||
if (it == end) report_error("invalid format string");
|
||||
|
||||
auto specs = format_specs();
|
||||
specs.set_align(align::right);
|
||||
|
||||
|
||||
@ -69,11 +69,12 @@ struct has_member_fn_begin_end_t<T, void_t<decltype(*std::declval<T>().begin()),
|
||||
|
||||
// Member function overloads.
|
||||
template <typename T>
|
||||
auto range_begin(T&& rng) -> decltype(static_cast<T&&>(rng).begin()) {
|
||||
FMT_CONSTEXPR auto range_begin(T&& rng)
|
||||
-> decltype(static_cast<T&&>(rng).begin()) {
|
||||
return static_cast<T&&>(rng).begin();
|
||||
}
|
||||
template <typename T>
|
||||
auto range_end(T&& rng) -> decltype(static_cast<T&&>(rng).end()) {
|
||||
FMT_CONSTEXPR auto range_end(T&& rng) -> decltype(static_cast<T&&>(rng).end()) {
|
||||
return static_cast<T&&>(rng).end();
|
||||
}
|
||||
|
||||
@ -129,6 +130,13 @@ template <typename T> class is_tuple_like_ {
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
template <typename T, typename _ = void>
|
||||
struct is_optional_like_ : std::false_type {};
|
||||
template <typename T>
|
||||
struct is_optional_like_<T, void_t<decltype(std::declval<T>().has_value()),
|
||||
decltype(std::declval<T>().value())>>
|
||||
: std::true_type {};
|
||||
|
||||
// Check for integer_sequence
|
||||
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900
|
||||
template <typename T, T... N>
|
||||
@ -343,8 +351,9 @@ struct formatter<Tuple, Char,
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T, typename Char> struct is_range {
|
||||
static constexpr bool value =
|
||||
detail::is_range_<T>::value && !detail::has_to_string_view<T>::value;
|
||||
static constexpr bool value = detail::is_range_<T>::value &&
|
||||
!detail::is_optional_like_<T>::value &&
|
||||
!detail::has_to_string_view<T>::value;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
@ -460,7 +469,8 @@ struct range_formatter<
|
||||
}
|
||||
|
||||
template <typename R, typename FormatContext>
|
||||
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
FMT_CONSTEXPR auto format(R&& range, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
auto it = detail::range_begin(range);
|
||||
auto end = detail::range_end(range);
|
||||
@ -516,7 +526,7 @@ struct formatter<
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(range_type& range, FormatContext& ctx) const
|
||||
FMT_CONSTEXPR auto format(range_type& range, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return range_formatter_.format(range, ctx);
|
||||
}
|
||||
@ -625,7 +635,7 @@ struct join_view : detail::view {
|
||||
Sentinel end;
|
||||
basic_string_view<Char> sep;
|
||||
|
||||
join_view(It b, Sentinel e, basic_string_view<Char> s)
|
||||
FMT_CONSTEXPR join_view(It b, Sentinel e, basic_string_view<Char> s)
|
||||
: begin(std::move(b)), end(e), sep(s) {}
|
||||
};
|
||||
|
||||
@ -652,7 +662,8 @@ struct formatter<join_view<It, Sentinel, Char>, Char> {
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(view& value, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
FMT_CONSTEXPR auto format(view& value, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
using iter =
|
||||
conditional_t<std::is_copy_constructible<view>::value, It, It&>;
|
||||
iter it = value.begin;
|
||||
@ -675,7 +686,7 @@ template <typename Tuple, typename Char> struct tuple_join_view : detail::view {
|
||||
const Tuple& tuple;
|
||||
basic_string_view<Char> sep;
|
||||
|
||||
tuple_join_view(const Tuple& t, basic_string_view<Char> s)
|
||||
FMT_CONSTEXPR tuple_join_view(const Tuple& t, basic_string_view<Char> s)
|
||||
: tuple(t), sep{s} {}
|
||||
};
|
||||
|
||||
@ -694,8 +705,9 @@ struct formatter<tuple_join_view<Tuple, Char>, Char,
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const tuple_join_view<Tuple, Char>& value,
|
||||
FormatContext& ctx) const -> typename FormatContext::iterator {
|
||||
FMT_CONSTEXPR auto format(const tuple_join_view<Tuple, Char>& value,
|
||||
FormatContext& ctx) const ->
|
||||
typename FormatContext::iterator {
|
||||
return do_format(value, ctx, std::tuple_size<Tuple>());
|
||||
}
|
||||
|
||||
@ -726,15 +738,17 @@ struct formatter<tuple_join_view<Tuple, Char>, Char,
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto do_format(const tuple_join_view<Tuple, Char>&, FormatContext& ctx,
|
||||
std::integral_constant<size_t, 0>) const ->
|
||||
FMT_CONSTEXPR auto do_format(const tuple_join_view<Tuple, Char>&,
|
||||
FormatContext& ctx,
|
||||
std::integral_constant<size_t, 0>) const ->
|
||||
typename FormatContext::iterator {
|
||||
return ctx.out();
|
||||
}
|
||||
|
||||
template <typename FormatContext, size_t N>
|
||||
auto do_format(const tuple_join_view<Tuple, Char>& value, FormatContext& ctx,
|
||||
std::integral_constant<size_t, N>) const ->
|
||||
FMT_CONSTEXPR auto do_format(const tuple_join_view<Tuple, Char>& value,
|
||||
FormatContext& ctx,
|
||||
std::integral_constant<size_t, N>) const ->
|
||||
typename FormatContext::iterator {
|
||||
using std::get;
|
||||
auto out =
|
||||
@ -813,7 +827,7 @@ auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> {
|
||||
* // Output: 01, 02, 03
|
||||
*/
|
||||
template <typename Range, FMT_ENABLE_IF(!is_tuple_like<Range>::value)>
|
||||
auto join(Range&& r, string_view sep)
|
||||
FMT_CONSTEXPR auto join(Range&& r, string_view sep)
|
||||
-> join_view<decltype(detail::range_begin(r)),
|
||||
decltype(detail::range_end(r))> {
|
||||
return {detail::range_begin(r), detail::range_end(r), sep};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - formatters for standard library types
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -133,8 +133,8 @@ void write_escaped_path(basic_memory_buffer<Char>& quoted,
|
||||
#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT
|
||||
|
||||
template <typename Char, typename OutputIt, typename T, typename FormatContext>
|
||||
auto write_escaped_alternative(OutputIt out, const T& v, FormatContext& ctx)
|
||||
-> OutputIt {
|
||||
FMT_CONSTEXPR auto write_escaped_alternative(OutputIt out, const T& v,
|
||||
FormatContext& ctx) -> OutputIt {
|
||||
if constexpr (has_to_string_view<T>::value)
|
||||
return write_escaped_string<Char>(out, detail::to_string_view(v));
|
||||
if constexpr (std::is_same_v<T, Char>) return write_escaped_char(out, v);
|
||||
@ -508,7 +508,7 @@ template <typename Char> struct formatter<std::monostate, Char> {
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::monostate&, FormatContext& ctx) const
|
||||
FMT_CONSTEXPR auto format(const std::monostate&, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return detail::write<Char>(ctx.out(), "monostate");
|
||||
}
|
||||
@ -524,7 +524,7 @@ struct formatter<Variant, Char,
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const Variant& value, FormatContext& ctx) const
|
||||
FMT_CONSTEXPR20 auto format(const Variant& value, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
|
||||
@ -637,15 +637,52 @@ struct formatter<
|
||||
template <typename Context>
|
||||
auto format(const std::exception& ex, Context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
return write(ctx.out(), ex);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename OutputIt>
|
||||
auto write(OutputIt out, const std::exception& ex) const -> OutputIt {
|
||||
#if FMT_USE_RTTI
|
||||
if (with_typename_) {
|
||||
out = detail::write_demangled_name(out, typeid(ex));
|
||||
*out++ = ':';
|
||||
*out++ = ' ';
|
||||
}
|
||||
#endif
|
||||
return detail::write_bytes<char>(out, string_view(ex.what()));
|
||||
#endif // FMT_USE_RTTI
|
||||
out = detail::write_bytes<char>(out, string_view(ex.what()));
|
||||
#if FMT_USE_RTTI
|
||||
// If the exception carries a nested exception (e.g. via
|
||||
// std::throw_with_nested), format the whole chain.
|
||||
if (auto* nested = dynamic_cast<const std::nested_exception*>(&ex)) {
|
||||
if (auto ep = nested->nested_ptr()) {
|
||||
out = detail::write(out, string_view(": "));
|
||||
try {
|
||||
std::rethrow_exception(ep);
|
||||
} catch (const std::exception& nested_ex) {
|
||||
out = write(out, nested_ex);
|
||||
} catch (...) {
|
||||
out = detail::write(out, string_view("unknown exception"));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // FMT_USE_RTTI
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct formatter<std::exception_ptr> : formatter<std::exception> {
|
||||
template <typename FormatContext>
|
||||
auto format(const std::exception_ptr& ep, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
if (!ep) return detail::write(ctx.out(), string_view("none"));
|
||||
try {
|
||||
std::rethrow_exception(ep);
|
||||
} catch (const std::exception& e) {
|
||||
return formatter<std::exception>::format(e, ctx);
|
||||
} catch (...) {
|
||||
return detail::write(ctx.out(), string_view("unknown exception"));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -690,11 +727,12 @@ struct formatter<BitRef, Char,
|
||||
#ifdef __cpp_lib_byte
|
||||
template <typename Char>
|
||||
struct formatter<std::byte, Char> : formatter<unsigned, Char> {
|
||||
static auto format_as(std::byte b) -> unsigned char {
|
||||
FMT_CONSTEXPR static auto format_as(std::byte b) -> unsigned char {
|
||||
return static_cast<unsigned char>(b);
|
||||
}
|
||||
template <typename Context>
|
||||
auto format(std::byte b, Context& ctx) const -> decltype(ctx.out()) {
|
||||
FMT_CONSTEXPR auto format(std::byte b, Context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return formatter<unsigned, Char>::format(format_as(b), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - optional wchar_t and exotic character support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -279,10 +279,18 @@ inline auto vformat_to_n(OutputIt out, size_t n, basic_string_view<Char> fmt,
|
||||
return {buf.out(), buf.count()};
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename... T,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, wchar_t>::value)>
|
||||
FMT_INLINE auto format_to_n(OutputIt out, size_t n, wformat_string<T...> fmt,
|
||||
T&&... args) -> format_to_n_result<OutputIt> {
|
||||
return vformat_to_n(out, n, fmt.get(), fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... T,
|
||||
typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value &&
|
||||
!std::is_same<Char, char>::value &&
|
||||
!std::is_same<Char, wchar_t>::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, fmt::basic_string_view<Char>(fmt),
|
||||
|
||||
41
src/fmt-c.cc
41
src/fmt-c.cc
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - the C API
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -9,12 +9,13 @@
|
||||
|
||||
#include <fmt/base.h>
|
||||
|
||||
extern "C" int fmt_vformat(char* buffer, size_t size, const char* fmt,
|
||||
const fmt_arg* args, size_t num_args) {
|
||||
constexpr size_t max_args = 16;
|
||||
if (num_args > max_args) return fmt_error_invalid_arg;
|
||||
constexpr size_t max_c_format_args = 16;
|
||||
|
||||
static int convert_c_format_args(
|
||||
fmt::basic_format_arg<fmt::format_context>* format_args,
|
||||
const fmt_arg* args, size_t num_args) {
|
||||
if (num_args > max_c_format_args) return fmt_error_invalid_arg;
|
||||
|
||||
fmt::basic_format_arg<fmt::format_context> format_args[max_args];
|
||||
for (size_t i = 0; i < num_args; ++i) {
|
||||
switch (args[i].type) {
|
||||
case fmt_int: format_args[i] = args[i].value.int_value; break;
|
||||
@ -31,12 +32,36 @@ extern "C" int fmt_vformat(char* buffer, size_t size, const char* fmt,
|
||||
default: return fmt_error_invalid_arg;
|
||||
}
|
||||
}
|
||||
try {
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int fmt_vformat(char* buffer, size_t size, const char* fmt,
|
||||
const fmt_arg* args, size_t num_args) {
|
||||
fmt::basic_format_arg<fmt::format_context> format_args[max_c_format_args];
|
||||
int error = convert_c_format_args(format_args, args, num_args);
|
||||
if (error != 0) return error;
|
||||
|
||||
FMT_TRY {
|
||||
auto result = fmt::vformat_to_n(
|
||||
buffer, size, fmt,
|
||||
fmt::format_args(format_args, static_cast<int>(num_args)));
|
||||
return static_cast<int>(result.size);
|
||||
} catch (...) {
|
||||
}
|
||||
FMT_CATCH(...) {}
|
||||
return fmt_error;
|
||||
}
|
||||
|
||||
extern "C" int fmt_vprint(FILE* stream, const char* fmt, const fmt_arg* args,
|
||||
size_t num_args) {
|
||||
fmt::basic_format_arg<fmt::format_context> format_args[max_c_format_args];
|
||||
int error = convert_c_format_args(format_args, args, num_args);
|
||||
if (error != 0) return error;
|
||||
|
||||
FMT_TRY {
|
||||
fmt::vprint(stream, fmt,
|
||||
fmt::format_args(format_args, static_cast<int>(num_args)));
|
||||
return 0;
|
||||
}
|
||||
FMT_CATCH(...) {}
|
||||
return fmt_error;
|
||||
}
|
||||
|
||||
@ -1,3 +1,10 @@
|
||||
// Formatting library for C++ - C++20 module
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
module;
|
||||
|
||||
#define FMT_MODULE
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++
|
||||
//
|
||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - optional OS-specific functionality
|
||||
//
|
||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -13,7 +13,6 @@
|
||||
#include "fmt/os.h"
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <climits>
|
||||
|
||||
# if FMT_USE_FCNTL
|
||||
# include <sys/stat.h>
|
||||
@ -35,6 +34,8 @@
|
||||
|
||||
# ifdef _WIN32
|
||||
# include <windows.h>
|
||||
|
||||
# include <climits> // CHAR_BIT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
6
support/cmake-format-requirements.txt
Normal file
6
support/cmake-format-requirements.txt
Normal file
@ -0,0 +1,6 @@
|
||||
cmakelang==0.6.13 \
|
||||
--hash=sha256:764b9467195c7c36453d60a829f30229720d26c7dffd41cb516b99bd9c7daf4e \
|
||||
--hash=sha256:03982e87b00654d024d73ef972d9d9bb0e5726cdb6b8a424a15661fb6278e67f
|
||||
six==1.17.0 \
|
||||
--hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \
|
||||
--hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81
|
||||
4
support/doc-requirements.in
Normal file
4
support/doc-requirements.in
Normal file
@ -0,0 +1,4 @@
|
||||
mkdocs-material==9.7.0
|
||||
mkdocstrings==1.0.0
|
||||
mike==2.1.3
|
||||
typing_extensions==4.15.0
|
||||
502
support/doc-requirements.txt
Normal file
502
support/doc-requirements.txt
Normal file
@ -0,0 +1,502 @@
|
||||
# Pinned, hash-verified Python dependencies for building the docs.
|
||||
# To regenerate, run from the repository root:
|
||||
# uv pip compile support/doc-requirements.in --generate-hashes \
|
||||
# --python-version 3.10 --python-platform x86_64-unknown-linux-gnu \
|
||||
# --output-file support/doc-requirements.txt
|
||||
babel==2.18.0 \
|
||||
--hash=sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d \
|
||||
--hash=sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35
|
||||
# via mkdocs-material
|
||||
backrefs==7.0 \
|
||||
--hash=sha256:4989bb9e1e99eb23647c7160ed51fb21d0b41b5d200f2d3017da41e023097e82 \
|
||||
--hash=sha256:a0fa7360c63509e9e077e174ef4e6d3c21c8db94189b9d957289ae6d794b9475 \
|
||||
--hash=sha256:a6448b28180e3ca01134c9cf09dcebafad8531072e09903c5451748a05f24bc9 \
|
||||
--hash=sha256:b57cd227ea556b0aed3dc9b8da4628db4eabc0402c6d7fcfc69283a93955f7e9 \
|
||||
--hash=sha256:ca42ce6a49ace3d75684dfa9937f3373902a63284ecb385ce36d15e5dcb41c12 \
|
||||
--hash=sha256:f2c52955d631b9e1ac4cd56209f0a3a946d592b98e7790e77699339ae01c102a
|
||||
# via mkdocs-material
|
||||
certifi==2026.5.20 \
|
||||
--hash=sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897 \
|
||||
--hash=sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d
|
||||
# via requests
|
||||
charset-normalizer==3.4.7 \
|
||||
--hash=sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc \
|
||||
--hash=sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c \
|
||||
--hash=sha256:07d9e39b01743c3717745f4c530a6349eadbfa043c7577eef86c502c15df2c67 \
|
||||
--hash=sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4 \
|
||||
--hash=sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0 \
|
||||
--hash=sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c \
|
||||
--hash=sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5 \
|
||||
--hash=sha256:12a6fff75f6bc66711b73a2f0addfc4c8c15a20e805146a02d147a318962c444 \
|
||||
--hash=sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153 \
|
||||
--hash=sha256:14265bfe1f09498b9d8ec91e9ec9fa52775edf90fcbde092b25f4a33d444fea9 \
|
||||
--hash=sha256:16d971e29578a5e97d7117866d15889a4a07befe0e87e703ed63cd90cb348c01 \
|
||||
--hash=sha256:177a0ba5f0211d488e295aaf82707237e331c24788d8d76c96c5a41594723217 \
|
||||
--hash=sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b \
|
||||
--hash=sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c \
|
||||
--hash=sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a \
|
||||
--hash=sha256:1dc8b0ea451d6e69735094606991f32867807881400f808a106ee1d963c46a83 \
|
||||
--hash=sha256:1efde3cae86c8c273f1eb3b287be7d8499420cf2fe7585c41d370d3e790054a5 \
|
||||
--hash=sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7 \
|
||||
--hash=sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb \
|
||||
--hash=sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c \
|
||||
--hash=sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1 \
|
||||
--hash=sha256:2cd4a60d0e2fb04537162c62bbbb4182f53541fe0ede35cdf270a1c1e723cc42 \
|
||||
--hash=sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab \
|
||||
--hash=sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df \
|
||||
--hash=sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e \
|
||||
--hash=sha256:320ade88cfb846b8cd6b4ddf5ee9e80ee0c1f52401f2456b84ae1ae6a1a5f207 \
|
||||
--hash=sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18 \
|
||||
--hash=sha256:36836d6ff945a00b88ba1e4572d721e60b5b8c98c155d465f56ad19d68f23734 \
|
||||
--hash=sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38 \
|
||||
--hash=sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110 \
|
||||
--hash=sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18 \
|
||||
--hash=sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44 \
|
||||
--hash=sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d \
|
||||
--hash=sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48 \
|
||||
--hash=sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e \
|
||||
--hash=sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5 \
|
||||
--hash=sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d \
|
||||
--hash=sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53 \
|
||||
--hash=sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790 \
|
||||
--hash=sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c \
|
||||
--hash=sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b \
|
||||
--hash=sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116 \
|
||||
--hash=sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d \
|
||||
--hash=sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10 \
|
||||
--hash=sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6 \
|
||||
--hash=sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2 \
|
||||
--hash=sha256:6370e8686f662e6a3941ee48ed4742317cafbe5707e36406e9df792cdb535776 \
|
||||
--hash=sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a \
|
||||
--hash=sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265 \
|
||||
--hash=sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008 \
|
||||
--hash=sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943 \
|
||||
--hash=sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374 \
|
||||
--hash=sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246 \
|
||||
--hash=sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e \
|
||||
--hash=sha256:6e0d51f618228538a3e8f46bd246f87a6cd030565e015803691603f55e12afb5 \
|
||||
--hash=sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616 \
|
||||
--hash=sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15 \
|
||||
--hash=sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41 \
|
||||
--hash=sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960 \
|
||||
--hash=sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752 \
|
||||
--hash=sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e \
|
||||
--hash=sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72 \
|
||||
--hash=sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7 \
|
||||
--hash=sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8 \
|
||||
--hash=sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b \
|
||||
--hash=sha256:813c0e0132266c08eb87469a642cb30aaff57c5f426255419572aaeceeaa7bf4 \
|
||||
--hash=sha256:82b271f5137d07749f7bf32f70b17ab6eaabedd297e75dce75081a24f76eb545 \
|
||||
--hash=sha256:84c018e49c3bf790f9c2771c45e9313a08c2c2a6342b162cd650258b57817706 \
|
||||
--hash=sha256:8751d2787c9131302398b11e6c8068053dcb55d5a8964e114b6e196cf16cb366 \
|
||||
--hash=sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb \
|
||||
--hash=sha256:87fad7d9ba98c86bcb41b2dc8dbb326619be2562af1f8ff50776a39e55721c5a \
|
||||
--hash=sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e \
|
||||
--hash=sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00 \
|
||||
--hash=sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f \
|
||||
--hash=sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a \
|
||||
--hash=sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1 \
|
||||
--hash=sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66 \
|
||||
--hash=sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356 \
|
||||
--hash=sha256:a6c5863edfbe888d9eff9c8b8087354e27618d9da76425c119293f11712a6319 \
|
||||
--hash=sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4 \
|
||||
--hash=sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad \
|
||||
--hash=sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d \
|
||||
--hash=sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5 \
|
||||
--hash=sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7 \
|
||||
--hash=sha256:aef65cd602a6d0e0ff6f9930fcb1c8fec60dd2cfcb6facaf4bdb0e5873042db0 \
|
||||
--hash=sha256:af21eb4409a119e365397b2adbaca4c9ccab56543a65d5dbd9f920d6ac29f686 \
|
||||
--hash=sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34 \
|
||||
--hash=sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49 \
|
||||
--hash=sha256:bb8cc7534f51d9a017b93e3e85b260924f909601c3df002bcdb58ddb4dc41a5c \
|
||||
--hash=sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1 \
|
||||
--hash=sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e \
|
||||
--hash=sha256:bd9b23791fe793e4968dba0c447e12f78e425c59fc0e3b97f6450f4781f3ee60 \
|
||||
--hash=sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0 \
|
||||
--hash=sha256:c0f081d69a6e58272819b70288d3221a6ee64b98df852631c80f293514d3b274 \
|
||||
--hash=sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d \
|
||||
--hash=sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0 \
|
||||
--hash=sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae \
|
||||
--hash=sha256:c593052c465475e64bbfe5dbd81680f64a67fdc752c56d7a0ae205dc8aeefe0f \
|
||||
--hash=sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d \
|
||||
--hash=sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe \
|
||||
--hash=sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3 \
|
||||
--hash=sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393 \
|
||||
--hash=sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1 \
|
||||
--hash=sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af \
|
||||
--hash=sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44 \
|
||||
--hash=sha256:d61f00a0869d77422d9b2aba989e2d24afa6ffd552af442e0e58de4f35ea6d00 \
|
||||
--hash=sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c \
|
||||
--hash=sha256:dca4bbc466a95ba9c0234ef56d7dd9509f63da22274589ebd4ed7f1f4d4c54e3 \
|
||||
--hash=sha256:dd915403e231e6b1809fe9b6d9fc55cf8fb5e02765ac625d9cd623342a7905d7 \
|
||||
--hash=sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd \
|
||||
--hash=sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e \
|
||||
--hash=sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b \
|
||||
--hash=sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8 \
|
||||
--hash=sha256:e5f4d355f0a2b1a31bc3edec6795b46324349c9cb25eed068049e4f472fb4259 \
|
||||
--hash=sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859 \
|
||||
--hash=sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46 \
|
||||
--hash=sha256:e80c8378d8f3d83cd3164da1ad2df9e37a666cdde7b1cb2298ed0b558064be30 \
|
||||
--hash=sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b \
|
||||
--hash=sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46 \
|
||||
--hash=sha256:ed065083d0898c9d5b4bbec7b026fd755ff7454e6e8b73a67f8c744b13986e24 \
|
||||
--hash=sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a \
|
||||
--hash=sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24 \
|
||||
--hash=sha256:f22dec1690b584cea26fade98b2435c132c1b5f68e39f5a0b7627cd7ae31f1dc \
|
||||
--hash=sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215 \
|
||||
--hash=sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063 \
|
||||
--hash=sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832 \
|
||||
--hash=sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6 \
|
||||
--hash=sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79 \
|
||||
--hash=sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464
|
||||
# via requests
|
||||
click==8.4.1 \
|
||||
--hash=sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2 \
|
||||
--hash=sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96
|
||||
# via mkdocs
|
||||
colorama==0.4.6 \
|
||||
--hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
|
||||
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
|
||||
# via mkdocs-material
|
||||
ghp-import==2.1.0 \
|
||||
--hash=sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619 \
|
||||
--hash=sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343
|
||||
# via mkdocs
|
||||
idna==3.17 \
|
||||
--hash=sha256:466e48829084efe2548012b855df21540b96f2e20e51bd124c851536556a592c \
|
||||
--hash=sha256:5eb0cb53bc467c12eadcf6de83163ad8527cec9416f44b9b61b19caedad2b87f
|
||||
# via requests
|
||||
importlib-metadata==9.0.0 \
|
||||
--hash=sha256:2d21d1cc5a017bd0559e36150c21c830ab1dc304dedd1b7ea85d20f45ef3edd7 \
|
||||
--hash=sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc
|
||||
# via mike
|
||||
importlib-resources==7.1.0 \
|
||||
--hash=sha256:0722d4c6212489c530f2a145a34c0a7a3b4721bc96a15fada5930e2a0b760708 \
|
||||
--hash=sha256:1bd7b48b4088eddb2cd16382150bb515af0bd2c70128194392725f82ad2c96a1
|
||||
# via mike
|
||||
jinja2==3.1.6 \
|
||||
--hash=sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d \
|
||||
--hash=sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67
|
||||
# via
|
||||
# mike
|
||||
# mkdocs
|
||||
# mkdocs-material
|
||||
# mkdocstrings
|
||||
markdown==3.10.2 \
|
||||
--hash=sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950 \
|
||||
--hash=sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36
|
||||
# via
|
||||
# mkdocs
|
||||
# mkdocs-autorefs
|
||||
# mkdocs-material
|
||||
# mkdocstrings
|
||||
# pymdown-extensions
|
||||
markupsafe==3.0.3 \
|
||||
--hash=sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f \
|
||||
--hash=sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a \
|
||||
--hash=sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf \
|
||||
--hash=sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19 \
|
||||
--hash=sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf \
|
||||
--hash=sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c \
|
||||
--hash=sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175 \
|
||||
--hash=sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219 \
|
||||
--hash=sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb \
|
||||
--hash=sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6 \
|
||||
--hash=sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab \
|
||||
--hash=sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26 \
|
||||
--hash=sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1 \
|
||||
--hash=sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce \
|
||||
--hash=sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218 \
|
||||
--hash=sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634 \
|
||||
--hash=sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695 \
|
||||
--hash=sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad \
|
||||
--hash=sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73 \
|
||||
--hash=sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c \
|
||||
--hash=sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe \
|
||||
--hash=sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa \
|
||||
--hash=sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559 \
|
||||
--hash=sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa \
|
||||
--hash=sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37 \
|
||||
--hash=sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758 \
|
||||
--hash=sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f \
|
||||
--hash=sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8 \
|
||||
--hash=sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d \
|
||||
--hash=sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c \
|
||||
--hash=sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97 \
|
||||
--hash=sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a \
|
||||
--hash=sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19 \
|
||||
--hash=sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9 \
|
||||
--hash=sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9 \
|
||||
--hash=sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc \
|
||||
--hash=sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2 \
|
||||
--hash=sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4 \
|
||||
--hash=sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354 \
|
||||
--hash=sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50 \
|
||||
--hash=sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698 \
|
||||
--hash=sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9 \
|
||||
--hash=sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b \
|
||||
--hash=sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc \
|
||||
--hash=sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115 \
|
||||
--hash=sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e \
|
||||
--hash=sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485 \
|
||||
--hash=sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f \
|
||||
--hash=sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12 \
|
||||
--hash=sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025 \
|
||||
--hash=sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009 \
|
||||
--hash=sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d \
|
||||
--hash=sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b \
|
||||
--hash=sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a \
|
||||
--hash=sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5 \
|
||||
--hash=sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f \
|
||||
--hash=sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d \
|
||||
--hash=sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1 \
|
||||
--hash=sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287 \
|
||||
--hash=sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6 \
|
||||
--hash=sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f \
|
||||
--hash=sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581 \
|
||||
--hash=sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed \
|
||||
--hash=sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b \
|
||||
--hash=sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c \
|
||||
--hash=sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026 \
|
||||
--hash=sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8 \
|
||||
--hash=sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676 \
|
||||
--hash=sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6 \
|
||||
--hash=sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e \
|
||||
--hash=sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d \
|
||||
--hash=sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d \
|
||||
--hash=sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01 \
|
||||
--hash=sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7 \
|
||||
--hash=sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419 \
|
||||
--hash=sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795 \
|
||||
--hash=sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1 \
|
||||
--hash=sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5 \
|
||||
--hash=sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d \
|
||||
--hash=sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42 \
|
||||
--hash=sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe \
|
||||
--hash=sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda \
|
||||
--hash=sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e \
|
||||
--hash=sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737 \
|
||||
--hash=sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523 \
|
||||
--hash=sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591 \
|
||||
--hash=sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc \
|
||||
--hash=sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a \
|
||||
--hash=sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50
|
||||
# via
|
||||
# jinja2
|
||||
# mkdocs
|
||||
# mkdocs-autorefs
|
||||
# mkdocstrings
|
||||
mergedeep==1.3.4 \
|
||||
--hash=sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8 \
|
||||
--hash=sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307
|
||||
# via
|
||||
# mkdocs
|
||||
# mkdocs-get-deps
|
||||
mike==2.1.3 \
|
||||
--hash=sha256:abd79b8ea483fb0275b7972825d3082e5ae67a41820f8d8a0dc7a3f49944e810 \
|
||||
--hash=sha256:d90c64077e84f06272437b464735130d380703a76a5738b152932884c60c062a
|
||||
# via -r /tmp/doc-requirements.in
|
||||
mkdocs==1.6.1 \
|
||||
--hash=sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2 \
|
||||
--hash=sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e
|
||||
# via
|
||||
# mike
|
||||
# mkdocs-autorefs
|
||||
# mkdocs-material
|
||||
# mkdocstrings
|
||||
mkdocs-autorefs==1.4.4 \
|
||||
--hash=sha256:834ef5408d827071ad1bc69e0f39704fa34c7fc05bc8e1c72b227dfdc5c76089 \
|
||||
--hash=sha256:d54a284f27a7346b9c38f1f852177940c222da508e66edc816a0fa55fc6da197
|
||||
# via mkdocstrings
|
||||
mkdocs-get-deps==0.2.2 \
|
||||
--hash=sha256:8ee8d5f316cdbbb2834bc1df6e69c08fe769a83e040060de26d3c19fad3599a1 \
|
||||
--hash=sha256:e7878cbeac04860b8b5e0ca31d3abad3df9411a75a32cde82f8e44b6c16ff650
|
||||
# via mkdocs
|
||||
mkdocs-material==9.7.0 \
|
||||
--hash=sha256:602b359844e906ee402b7ed9640340cf8a474420d02d8891451733b6b02314ec \
|
||||
--hash=sha256:da2866ea53601125ff5baa8aa06404c6e07af3c5ce3d5de95e3b52b80b442887
|
||||
# via -r /tmp/doc-requirements.in
|
||||
mkdocs-material-extensions==1.3.1 \
|
||||
--hash=sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443 \
|
||||
--hash=sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31
|
||||
# via mkdocs-material
|
||||
mkdocstrings==1.0.0 \
|
||||
--hash=sha256:351a006dbb27aefce241ade110d3cd040c1145b7a3eb5fd5ac23f03ed67f401a \
|
||||
--hash=sha256:4c50eb960bff6e05dfc631f6bc00dfabffbcb29c5ff25f676d64daae05ed82fa
|
||||
# via -r /tmp/doc-requirements.in
|
||||
packaging==26.2 \
|
||||
--hash=sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e \
|
||||
--hash=sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661
|
||||
# via mkdocs
|
||||
paginate==0.5.7 \
|
||||
--hash=sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945 \
|
||||
--hash=sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591
|
||||
# via mkdocs-material
|
||||
pathspec==1.1.1 \
|
||||
--hash=sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a \
|
||||
--hash=sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189
|
||||
# via mkdocs
|
||||
platformdirs==4.10.0 \
|
||||
--hash=sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7 \
|
||||
--hash=sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a
|
||||
# via mkdocs-get-deps
|
||||
pygments==2.20.0 \
|
||||
--hash=sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f \
|
||||
--hash=sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176
|
||||
# via mkdocs-material
|
||||
pymdown-extensions==10.21.3 \
|
||||
--hash=sha256:72cfcf55f07aea0d4af2c4f11dd4e52466ddfb1bb819673146398e0bd3a77354 \
|
||||
--hash=sha256:d7a5d08014fc571e80ca21dd6f854e31f94c489800350564d55d15b3c41e76b6
|
||||
# via
|
||||
# mkdocs-material
|
||||
# mkdocstrings
|
||||
pyparsing==3.3.2 \
|
||||
--hash=sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d \
|
||||
--hash=sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc
|
||||
# via mike
|
||||
python-dateutil==2.9.0.post0 \
|
||||
--hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \
|
||||
--hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427
|
||||
# via ghp-import
|
||||
pyyaml==6.0.3 \
|
||||
--hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \
|
||||
--hash=sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a \
|
||||
--hash=sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3 \
|
||||
--hash=sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956 \
|
||||
--hash=sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6 \
|
||||
--hash=sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c \
|
||||
--hash=sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65 \
|
||||
--hash=sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a \
|
||||
--hash=sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0 \
|
||||
--hash=sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b \
|
||||
--hash=sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1 \
|
||||
--hash=sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6 \
|
||||
--hash=sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7 \
|
||||
--hash=sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e \
|
||||
--hash=sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007 \
|
||||
--hash=sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310 \
|
||||
--hash=sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4 \
|
||||
--hash=sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9 \
|
||||
--hash=sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295 \
|
||||
--hash=sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea \
|
||||
--hash=sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0 \
|
||||
--hash=sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e \
|
||||
--hash=sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac \
|
||||
--hash=sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9 \
|
||||
--hash=sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7 \
|
||||
--hash=sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35 \
|
||||
--hash=sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb \
|
||||
--hash=sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b \
|
||||
--hash=sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69 \
|
||||
--hash=sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5 \
|
||||
--hash=sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b \
|
||||
--hash=sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c \
|
||||
--hash=sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369 \
|
||||
--hash=sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd \
|
||||
--hash=sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824 \
|
||||
--hash=sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198 \
|
||||
--hash=sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065 \
|
||||
--hash=sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c \
|
||||
--hash=sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c \
|
||||
--hash=sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764 \
|
||||
--hash=sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196 \
|
||||
--hash=sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b \
|
||||
--hash=sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00 \
|
||||
--hash=sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac \
|
||||
--hash=sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8 \
|
||||
--hash=sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e \
|
||||
--hash=sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28 \
|
||||
--hash=sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3 \
|
||||
--hash=sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5 \
|
||||
--hash=sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4 \
|
||||
--hash=sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b \
|
||||
--hash=sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf \
|
||||
--hash=sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5 \
|
||||
--hash=sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702 \
|
||||
--hash=sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8 \
|
||||
--hash=sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788 \
|
||||
--hash=sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da \
|
||||
--hash=sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d \
|
||||
--hash=sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc \
|
||||
--hash=sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c \
|
||||
--hash=sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba \
|
||||
--hash=sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f \
|
||||
--hash=sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917 \
|
||||
--hash=sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5 \
|
||||
--hash=sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26 \
|
||||
--hash=sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f \
|
||||
--hash=sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b \
|
||||
--hash=sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be \
|
||||
--hash=sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c \
|
||||
--hash=sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3 \
|
||||
--hash=sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6 \
|
||||
--hash=sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926 \
|
||||
--hash=sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0
|
||||
# via
|
||||
# mike
|
||||
# mkdocs
|
||||
# mkdocs-get-deps
|
||||
# pymdown-extensions
|
||||
# pyyaml-env-tag
|
||||
pyyaml-env-tag==1.1 \
|
||||
--hash=sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04 \
|
||||
--hash=sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff
|
||||
# via
|
||||
# mike
|
||||
# mkdocs
|
||||
requests==2.34.2 \
|
||||
--hash=sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0 \
|
||||
--hash=sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed
|
||||
# via mkdocs-material
|
||||
six==1.17.0 \
|
||||
--hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \
|
||||
--hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81
|
||||
# via python-dateutil
|
||||
typing-extensions==4.15.0 \
|
||||
--hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \
|
||||
--hash=sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548
|
||||
# via -r /tmp/doc-requirements.in
|
||||
urllib3==2.7.0 \
|
||||
--hash=sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c \
|
||||
--hash=sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897
|
||||
# via requests
|
||||
verspec==0.1.0 \
|
||||
--hash=sha256:741877d5633cc9464c45a469ae2a31e801e6dbbaa85b9675d481cda100f11c31 \
|
||||
--hash=sha256:c4504ca697b2056cdb4bfa7121461f5a0e81809255b41c03dda4ba823637c01e
|
||||
# via mike
|
||||
watchdog==6.0.0 \
|
||||
--hash=sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a \
|
||||
--hash=sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2 \
|
||||
--hash=sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f \
|
||||
--hash=sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c \
|
||||
--hash=sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c \
|
||||
--hash=sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c \
|
||||
--hash=sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0 \
|
||||
--hash=sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13 \
|
||||
--hash=sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134 \
|
||||
--hash=sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa \
|
||||
--hash=sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e \
|
||||
--hash=sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379 \
|
||||
--hash=sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a \
|
||||
--hash=sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11 \
|
||||
--hash=sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282 \
|
||||
--hash=sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b \
|
||||
--hash=sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f \
|
||||
--hash=sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c \
|
||||
--hash=sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112 \
|
||||
--hash=sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948 \
|
||||
--hash=sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881 \
|
||||
--hash=sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860 \
|
||||
--hash=sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3 \
|
||||
--hash=sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680 \
|
||||
--hash=sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26 \
|
||||
--hash=sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26 \
|
||||
--hash=sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e \
|
||||
--hash=sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8 \
|
||||
--hash=sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c \
|
||||
--hash=sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2
|
||||
# via mkdocs
|
||||
zipp==4.1.0 \
|
||||
--hash=sha256:25ad4e16390cd314347dd8f1de67a2ac538ae658ed4ab9db16029c07c188e97f \
|
||||
--hash=sha256:4cb57381f544315db7688e976e922a2b18cdb513d21cc194eb42232ba2a3e602
|
||||
# via importlib-metadata
|
||||
52
support/llvm-snapshot.gpg.key
Normal file
52
support/llvm-snapshot.gpg.key
Normal file
@ -0,0 +1,52 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQINBFE9lCwBEADi0WUAApM/mgHJRU8lVkkw0CHsZNpqaQDNaHefD6Rw3S4LxNmM
|
||||
EZaOTkhP200XZM8lVdbfUW9xSjA3oPldc1HG26NjbqqCmWpdo2fb+r7VmU2dq3NM
|
||||
R18ZlKixiLDE6OUfaXWKamZsXb6ITTYmgTO6orQWYrnW6ckYHSeaAkW0wkDAryl2
|
||||
B5v8aoFnQ1rFiVEMo4NGzw4UX+MelF7rxaaregmKVTPiqCOSPJ1McC1dHFN533FY
|
||||
Wh/RVLKWo6npu+owtwYFQW+zyQhKzSIMvNujFRzhIxzxR9Gn87MoLAyfgKEzrbbT
|
||||
DhqqNXTxS4UMUKCQaO93TzetX/EBrRpJj+vP640yio80h4Dr5pAd7+LnKwgpTDk1
|
||||
G88bBXJAcPZnTSKu9I2c6KY4iRNbvRz4i+ZdwwZtdW4nSdl2792L7Sl7Nc44uLL/
|
||||
ZqkKDXEBF6lsX5XpABwyK89S/SbHOytXv9o4puv+65Ac5/UShspQTMSKGZgvDauU
|
||||
cs8kE1U9dPOqVNCYq9Nfwinkf6RxV1k1+gwtclxQuY7UpKXP0hNAXjAiA5KS5Crq
|
||||
7aaJg9q2F4bub0mNU6n7UI6vXguF2n4SEtzPRk6RP+4TiT3bZUsmr+1ktogyOJCc
|
||||
Ha8G5VdL+NBIYQthOcieYCBnTeIH7D3Sp6FYQTYtVbKFzmMK+36ERreL/wARAQAB
|
||||
tD1TeWx2ZXN0cmUgTGVkcnUgLSBEZWJpYW4gTExWTSBwYWNrYWdlcyA8c3lsdmVz
|
||||
dHJlQGRlYmlhbi5vcmc+iQJMBBMBCgA2AhsDAh4BAheABAsJCAcEFQoJCAUWAgMB
|
||||
ABYhBGCE88+BS1fBzxLv1RXPTRivT3QhBQJpl4k7AAoJEBXPTRivT3QhivEP/2Ix
|
||||
/Pi72KhD47zbxLecS0VLB/gURPC2h5AgWgW5P/GSQe0QXHAkqCWFd9y1Y5PI8e3v
|
||||
6RZFDCPJrfVKfHzIx4nciUHr0qlJqGaplvf6AZvgvF8Xrua9VZaHnZJO+GmK+WtH
|
||||
/bCgtzk91O08w8wcZ/4wmopQjcSu69OcpqpPBVClhIxaIIFFlATdUAKNVAzXDQDf
|
||||
WfWT2N3ghsbac1MRQKKzddzXgvVw5mRAw0NCKUJ2DPSohfRsS1LjVG4wThkLWZJb
|
||||
tPx6+meunBspvvROthh+HEEjiB5o4i7230AOhyYAOjgZj3wQq7A/2O0Ro1A2zl5L
|
||||
vB17a6WLnEdUzLgj0NYtE1x4W0fNAspEQpIXvVRkZzHA+GH31a2Fs/S2kqsuF/OY
|
||||
hsD35d/6lJtxbNY2sYsprDxT2tfdnUG9KCJSI3p/vjGIezFgrfBB7u6lUHx/GAQM
|
||||
nwpiXKeRRS4fT03aZ79FR3xVE7pLOHRq4tUVEH1lvHQB8aU07NHK61BR8NXS++cg
|
||||
LhveD+TwCKNQ9WaDdNNDl0jGbOBzcou+KguZD8wfoCj/Ko0CdCUFdO+H+TPsIH4F
|
||||
nRovkQ5bN7Y7iTHiV96mDOtnE2kd4ctbioEl8/4zroKCZTQEzJRQ/Zz+NdtRa/ev
|
||||
n2jUyoHWs2Vc5bYLyvwjk6CCurIumdT6JAdEUMF6uQINBFE9lCwBEADiPFiZtMfC
|
||||
YyOpKLOUwlg24Y6kiJ0R3H3NDmDM6vjfX9V9arhL5WEwOGzXmP2XKaXTLiiTbXlV
|
||||
EXCsBEQODpQ8yvtqMuYFAZq7QVxu9kn3SXg2NenmnQ0QT+o5v1QQdPsQaQSFpnV6
|
||||
SRYVNYKCzLutFd9kvEHqyTunMsIOyHJbfOMhqRYCelDmPmhuIPLvTylF4C4YH3g1
|
||||
LJvUehb/EawaC+8LDivTDfE9K3AXU+GZJwTo1MEh8uWJ5remXy+Eo+UKHngeTsjx
|
||||
AaOjUROVE/hCWXVnEcny7bl/+1pERLYDDweLuPQRVxnoxP0lZMjzfJRydSVk9lLY
|
||||
fJ5ZxSP7ydQLxbg3wCf5o2mz2X/bWKciXZNsajdifUlAucDVgKgbALfiDxBlMmES
|
||||
URAE3Rfb1rJZbo50XHwwO+WVsFXKaYqraUrVTnmZBN8OWLtLe98bP0an+hDBnxtC
|
||||
k55SRzmFtmzNjA/hFf7rzEM9+f4z252X6pb3C74vJ49tbodf3QuaSE2SRjZnNQ9E
|
||||
8MdkA1Tlu1o9dzYft51fjLiZpBrF6eoPSUaH0sbP+amzgcRm0IjkJjyjS4IwXeVP
|
||||
Rd9eG4uSyvs/G/nvK57wstMi04l30ebOn0b3tJFhh6pT7yXI1e1TY92ssurtAeTO
|
||||
uyWgbvyUKlBxqUcYAInOuVRZU/983ce3eQARAQABiQI2BBgBCgAgAhsMFiEEYITz
|
||||
z4FLV8HPEu/VFc9NGK9PdCEFAmmXid0ACgkQFc9NGK9PdCF/PxAAlMhoX2YtQ2vc
|
||||
aPt+6hZ3q/8y+xht/WK7YmPm76b7tmRvahZIIfr9Criu9HyL4nFXlVnYot63qIqa
|
||||
ebu4GUr7Dau+oimJ2olLXMbSjhg7R/Q9ESqG/6pvBl6gwgKqxQAh8lVgK4KevK++
|
||||
nxdPLLNe9F1kkwnLKCUvYElEYEUMrqI4GMHfgPw84vCCWmR8CSZ+AJ95tft5Xzxf
|
||||
7uENFADYkDkLiA4giHSasMOhiVxhZWSI+UVJ2vTGuscma509kqs+CjzXOzCKymQ4
|
||||
qVCjKLaSkQK4rUV125AU0WfRFpaKtiHWmLic5opBzCGhvJ7HI8iOxAFq3bHB1WN1
|
||||
Ba7VHOCbSKAFIw+7n+onEmKPpiZe55pc684wHy1RD3YnimdJWyHxMXSGuhggv3W1
|
||||
CWxE1U2fmnMzXbn3T1VXk5/q/5X4wtirzWobZIzVcg5WcoSx0w0LOqIgf6C1z0jq
|
||||
FLloorOrbdfYOg6GEhaoiiYiwnWwPiKHNqONpMqXitwh/lCK3SomtdsACy1FlVP7
|
||||
HvM41+jf7qZ9WqCvUZKc+11XAUdOaqAoxQU/T1I1gPGTTJ3uYvAsOqQc9SZAt3Io
|
||||
8QkYjS9LQvxtZqAdWUALaiQIYKf3uJE5eWP3sF6uEJA3LTyIZsMd7MO25UEPLKCw
|
||||
O9BuqGhXJW1iyMZ/Smhp993FdBBf4FA=
|
||||
=/NY6
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
@ -71,15 +71,18 @@ if len(args) > 0:
|
||||
# mike stages files added by deploy for deletion for unclear reason,
|
||||
# undo it.
|
||||
ret = call(['git', 'reset', '--hard'], cwd=site_dir)
|
||||
if False:
|
||||
os.makedirs(current_doc_path, exist_ok=True)
|
||||
redirect_page_path = os.path.join(current_doc_path, 'api.html')
|
||||
with open(redirect_page_path, "w") as file:
|
||||
file.write(redirect_page)
|
||||
ret = call(['git', 'add', redirect_page_path], cwd=site_dir)
|
||||
if ret != 0:
|
||||
sys.exit(ret)
|
||||
ret = call(['git', 'commit', '--amend', '--no-edit'], cwd=site_dir)
|
||||
if ret != 0:
|
||||
sys.exit(ret)
|
||||
# Generate a redirect page from the old Sphinx api.html to the new api/
|
||||
# page, preserving the URL hash so links such as api.html#udt keep working.
|
||||
os.makedirs(current_doc_path, exist_ok=True)
|
||||
redirect_page_path = os.path.join(current_doc_path, 'api.html')
|
||||
with open(redirect_page_path, "w") as file:
|
||||
file.write(redirect_page)
|
||||
ret = call(['git', 'add', redirect_page_path], cwd=site_dir)
|
||||
if ret != 0:
|
||||
sys.exit(ret)
|
||||
ret = call(['git', 'commit', '--amend', '--no-edit'], cwd=site_dir)
|
||||
sys.exit(ret)
|
||||
elif not command.startswith('-'):
|
||||
args += ['-f', config_path]
|
||||
|
||||
@ -35,6 +35,9 @@ class Git:
|
||||
def clone(self, *args):
|
||||
return self.call('clone', list(args) + [self.dir])
|
||||
|
||||
def fetch(self, *args):
|
||||
return self.call('fetch', args, cwd=self.dir)
|
||||
|
||||
def commit(self, *args):
|
||||
return self.call('commit', args, cwd=self.dir)
|
||||
|
||||
@ -56,16 +59,22 @@ class Git:
|
||||
|
||||
def clean_checkout(repo, branch):
|
||||
repo.clean('-f', '-d')
|
||||
repo.reset('--hard')
|
||||
repo.fetch('origin')
|
||||
repo.checkout(branch)
|
||||
# Hard-reset to the remote so a reused clone picks up new commits
|
||||
# instead of building from stale local state.
|
||||
repo.reset('--hard', 'origin/' + branch)
|
||||
|
||||
|
||||
class Runner:
|
||||
def __init__(self, cwd):
|
||||
def __init__(self, cwd, env=None):
|
||||
self.cwd = cwd
|
||||
self.env = env
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
kwargs['cwd'] = kwargs.get('cwd', self.cwd)
|
||||
if self.env is not None:
|
||||
kwargs['env'] = kwargs.get('env', self.env)
|
||||
check_call(args, **kwargs)
|
||||
|
||||
|
||||
@ -80,6 +89,28 @@ def create_build_env():
|
||||
return env
|
||||
|
||||
|
||||
def create_doc_env(env, fmt_repo):
|
||||
"""Create a virtualenv with the pinned documentation dependencies and
|
||||
return an environment dict with it prepended to PATH. This ensures the
|
||||
docs are built with the exact mkdocs/mkdocstrings versions required by the
|
||||
custom handler, regardless of what is installed system-wide."""
|
||||
# Use an absolute path so the venv resolves on PATH regardless of the
|
||||
# working directory the build steps run in.
|
||||
venv_dir = os.path.abspath(os.path.join(env.build_dir, 'venv'))
|
||||
shutil.rmtree(venv_dir, ignore_errors=True)
|
||||
check_call([sys.executable, '-m', 'venv', venv_dir])
|
||||
venv_bin = os.path.join(venv_dir, 'bin')
|
||||
pip = os.path.join(venv_bin, 'pip')
|
||||
check_call([pip, 'install', '--quiet', '--upgrade', 'pip'])
|
||||
requirements = os.path.join(
|
||||
fmt_repo.dir, 'support', 'doc-requirements.txt')
|
||||
check_call(
|
||||
[pip, 'install', '--quiet', '--require-hashes', '-r', requirements])
|
||||
doc_env = os.environ.copy()
|
||||
doc_env['PATH'] = venv_bin + os.pathsep + doc_env.get('PATH', '')
|
||||
return doc_env
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = docopt.docopt(__doc__)
|
||||
env = create_build_env()
|
||||
@ -87,7 +118,7 @@ if __name__ == '__main__':
|
||||
|
||||
branch = args.get('<branch>')
|
||||
if branch is None:
|
||||
branch = 'master'
|
||||
branch = 'main'
|
||||
if not fmt_repo.update('-b', branch, 'git@github.com:fmtlib/fmt'):
|
||||
clean_checkout(fmt_repo, branch)
|
||||
|
||||
@ -151,12 +182,21 @@ if __name__ == '__main__':
|
||||
fmt_repo.add(changelog)
|
||||
fmt_repo.commit('-m', 'Update version')
|
||||
|
||||
# Build the docs and package.
|
||||
run = Runner(fmt_repo.dir)
|
||||
# Build the docs locally in a virtualenv with the pinned doc dependencies;
|
||||
# the source zip is now built and attached to the release in CI by
|
||||
# .github/workflows/release.yml, which also generates a SLSA provenance
|
||||
# attestation for it. The venv is prepended to PATH so that CMake's
|
||||
# find_program(MKDOCS mkdocs) and the ./mkdocs deploy step below both pick
|
||||
# up the correct mkdocs/mkdocstrings versions.
|
||||
doc_env = create_doc_env(env, fmt_repo)
|
||||
run = Runner(fmt_repo.dir, env=doc_env)
|
||||
run('cmake', '.')
|
||||
run('make', 'doc', 'package_source')
|
||||
run('make', 'doc')
|
||||
|
||||
# Create a release on GitHub.
|
||||
# Create a draft release on GitHub, then trigger the release workflow to
|
||||
# build the source zip from the `release` branch and attach the zip plus
|
||||
# *.intoto.jsonl provenance to this draft. After reviewing the draft, the
|
||||
# maintainer clicks Publish to finalize.
|
||||
fmt_repo.push('origin', 'release')
|
||||
auth_headers = {'Authorization': 'token ' + os.getenv('FMT_TOKEN')}
|
||||
req = urllib.request.Request(
|
||||
@ -169,20 +209,21 @@ if __name__ == '__main__':
|
||||
if response.status != 201:
|
||||
raise Exception(f'Failed to create a release ' +
|
||||
'{response.status} {response.reason}')
|
||||
response_data = json.loads(response.read().decode('utf-8'))
|
||||
id = response_data['id']
|
||||
|
||||
# Upload the package.
|
||||
uploads_url = 'https://uploads.github.com/repos/fmtlib/fmt/releases'
|
||||
package = 'fmt-{}.zip'.format(version)
|
||||
req = urllib.request.Request(
|
||||
f'{uploads_url}/{id}/assets?name={package}',
|
||||
headers={'Content-Type': 'application/zip'} | auth_headers,
|
||||
data=open('build/fmt/' + package, 'rb').read(), method='POST')
|
||||
with urllib.request.urlopen(req) as response:
|
||||
if response.status != 201:
|
||||
raise Exception(f'Failed to upload an asset '
|
||||
'{response.status} {response.reason}')
|
||||
# Draft releases do not fire `release: created`, so explicitly dispatch the
|
||||
# release workflow. It runs from the default branch (`branch`) but builds
|
||||
# and uploads artifacts from the `release` branch for tag `version`.
|
||||
dispatch_req = urllib.request.Request(
|
||||
'https://api.github.com/repos/fmtlib/fmt/actions/workflows/'
|
||||
'release.yml/dispatches',
|
||||
data=json.dumps({'ref': branch,
|
||||
'inputs': {'tag_name': version,
|
||||
'ref': 'release'}}).encode('utf-8'),
|
||||
headers=auth_headers, method='POST')
|
||||
with urllib.request.urlopen(dispatch_req) as response:
|
||||
if response.status != 204:
|
||||
raise Exception('Failed to dispatch the release workflow ' +
|
||||
f'{response.status} {response.reason}')
|
||||
|
||||
short_version = '.'.join(version.split('.')[:-1])
|
||||
check_call(['./mkdocs', 'deploy', short_version])
|
||||
check_call(['./mkdocs', 'deploy', short_version], env=doc_env)
|
||||
|
||||
@ -19,7 +19,7 @@ function (add_fmt_test name)
|
||||
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wno-weak-vtables)
|
||||
endif ()
|
||||
elseif (ADD_FMT_TEST_MODULE)
|
||||
set(libs test-main)
|
||||
set(libs test-main fmt-module)
|
||||
else ()
|
||||
set(libs test-main fmt)
|
||||
endif ()
|
||||
@ -81,9 +81,7 @@ add_executable(perf-sanity perf-sanity.cc)
|
||||
target_link_libraries(perf-sanity fmt::fmt)
|
||||
|
||||
if (FMT_MODULE)
|
||||
# Module tests are currently disabled.
|
||||
# add_fmt_test(module-test MODULE test-main.cc)
|
||||
# target_link_libraries(module-test fmt-module)
|
||||
add_fmt_test(module-test MODULE)
|
||||
endif ()
|
||||
|
||||
if (NOT DEFINED MSVC_STATIC_RUNTIME AND MSVC)
|
||||
|
||||
@ -15,3 +15,12 @@ if (TARGET fmt::fmt-header-only)
|
||||
target_compile_options(header-only-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
|
||||
target_link_libraries(header-only-test fmt::fmt-header-only)
|
||||
endif ()
|
||||
|
||||
# Test that a target publicly depending on fmt can itself be exported even
|
||||
# though fmt is added via add_subdirectory and FMT_INSTALL is off (#4806).
|
||||
add_library(export-test STATIC export-lib.cc)
|
||||
target_link_libraries(export-test PUBLIC fmt::fmt)
|
||||
export(
|
||||
TARGETS export-test
|
||||
NAMESPACE test::
|
||||
FILE ${CMAKE_CURRENT_BINARY_DIR}/export-test-targets.cmake)
|
||||
|
||||
3
test/add-subdirectory-test/export-lib.cc
Normal file
3
test/add-subdirectory-test/export-lib.cc
Normal file
@ -0,0 +1,3 @@
|
||||
#include "fmt/base.h"
|
||||
|
||||
void greet(const char* name) { fmt::print("Hello, {}!\n", name); }
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - dynamic argument store tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
// 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
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - core tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -21,8 +21,10 @@
|
||||
#include <functional> // std::equal_to
|
||||
#include <iterator> // std::back_insert_iterator, std::distance
|
||||
#include <limits> // std::numeric_limits
|
||||
#include <list> // std::list
|
||||
#include <string> // std::string
|
||||
#include <type_traits> // std::is_same
|
||||
#include <vector> // std::vector
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
@ -811,10 +813,10 @@ TEST(base_test, throw_in_buffer_dtor) {
|
||||
constexpr int buffer_size = 256;
|
||||
|
||||
struct throwing_iterator {
|
||||
int& count;
|
||||
int* count;
|
||||
|
||||
auto operator=(char) -> throwing_iterator& {
|
||||
if (++count > buffer_size) throw std::exception();
|
||||
if (++*count > buffer_size) throw std::exception();
|
||||
return *this;
|
||||
}
|
||||
auto operator*() -> throwing_iterator& { return *this; }
|
||||
@ -824,7 +826,7 @@ TEST(base_test, throw_in_buffer_dtor) {
|
||||
|
||||
try {
|
||||
int count = 0;
|
||||
fmt::format_to(throwing_iterator{count}, fmt::runtime("{:{}}{"), "",
|
||||
fmt::format_to(throwing_iterator{&count}, fmt::runtime("{:{}}{"), "",
|
||||
buffer_size + 1);
|
||||
} catch (const std::exception&) {
|
||||
}
|
||||
@ -872,10 +874,32 @@ struct custom_container {
|
||||
auto operator[](size_t) -> char& { return data; }
|
||||
};
|
||||
|
||||
struct phantom_subscript_container {
|
||||
using value_type = char;
|
||||
|
||||
auto data() -> char*;
|
||||
auto size() const -> size_t;
|
||||
operator const char*() const;
|
||||
};
|
||||
|
||||
struct real_subscript_container : phantom_subscript_container {
|
||||
auto operator[](size_t) -> char&;
|
||||
};
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct is_contiguous<custom_container> : std::true_type {};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
TEST(base_test, is_contiguous) {
|
||||
EXPECT_TRUE((fmt::is_contiguous<custom_container>::value));
|
||||
EXPECT_TRUE((fmt::is_contiguous<std::string>::value));
|
||||
EXPECT_TRUE((fmt::is_contiguous<fmt::string_view>::value));
|
||||
EXPECT_TRUE((fmt::is_contiguous<std::vector<char>>::value));
|
||||
EXPECT_FALSE((fmt::is_contiguous<std::list<char>>::value));
|
||||
EXPECT_FALSE((fmt::is_contiguous<phantom_subscript_container>::value));
|
||||
EXPECT_TRUE((fmt::is_contiguous<real_subscript_container>::value));
|
||||
}
|
||||
|
||||
TEST(base_test, format_to_custom_container) {
|
||||
auto c = custom_container();
|
||||
fmt::format_to(std::back_inserter(c), "");
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - the C API tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -83,10 +83,30 @@ void test_buffer_size_query(void) {
|
||||
ASSERT_INT_EQ(size, 15);
|
||||
}
|
||||
|
||||
void test_print(void) {
|
||||
FILE* file = tmpfile();
|
||||
if (!file) {
|
||||
fprintf(stderr, "\nFailed to create temporary file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int ret = fmt_print(file, "{} and {}", 42, "foo");
|
||||
ASSERT_INT_EQ(ret, 0);
|
||||
|
||||
rewind(file);
|
||||
char buf[100];
|
||||
size_t n = fread(buf, 1, sizeof(buf) - 1, file);
|
||||
buf[n] = '\0';
|
||||
ASSERT_STR_EQ(buf, "42 and foo");
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
printf("Running C API tests\n");
|
||||
test_types();
|
||||
test_zero_arguments();
|
||||
test_buffer_size_query();
|
||||
test_print();
|
||||
printf("C API tests passed\n");
|
||||
}
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
// Formatting library for C++ - time formatting tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#include "fmt/chrono.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <ctime>
|
||||
#include <vector>
|
||||
|
||||
@ -359,6 +358,9 @@ TEST(chrono_test, tm) {
|
||||
char tz[] = "EET";
|
||||
if (fmt::detail::set_tm_zone(time, tz)) {
|
||||
EXPECT_EQ(fmt::format(fmt::runtime("{:%Z}"), time), "EET");
|
||||
fmt::detail::set_tm_zone(time, nullptr);
|
||||
EXPECT_THROW_MSG((void)fmt::format(fmt::runtime("{:%Z}"), time),
|
||||
fmt::format_error, "no timezone");
|
||||
} else {
|
||||
EXPECT_THROW_MSG((void)fmt::format(fmt::runtime("{:%Z}"), time),
|
||||
fmt::format_error, "no timezone");
|
||||
@ -987,6 +989,9 @@ TEST(chrono_test, glibc_extensions) {
|
||||
TEST(chrono_test, out_of_range) {
|
||||
auto d = std::chrono::duration<unsigned long, std::giga>(538976288);
|
||||
EXPECT_THROW((void)fmt::format("{:%j}", d), fmt::format_error);
|
||||
// A floating-point day count that doesn't fit in int.
|
||||
auto fd = std::chrono::duration<double>(1e300);
|
||||
EXPECT_THROW((void)fmt::format("{:%j}", fd), fmt::format_error);
|
||||
}
|
||||
|
||||
TEST(chrono_test, year_month_day) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - color tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -136,3 +136,15 @@ 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");
|
||||
}
|
||||
|
||||
TEST(color_test, println) {
|
||||
EXPECT_WRITE(stdout,
|
||||
fmt::println(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"),
|
||||
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m\n");
|
||||
EXPECT_WRITE(stdout, fmt::println(fmt::emphasis::bold, "bold"),
|
||||
"\x1b[1mbold\x1b[0m\n");
|
||||
EXPECT_WRITE(
|
||||
stdout,
|
||||
fmt::println(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"),
|
||||
"\x1b[1m\x1b[38;2;000;000;255mblue/bold\x1b[0m\n");
|
||||
}
|
||||
|
||||
@ -239,6 +239,16 @@ if (CMAKE_CXX_STANDARD GREATER_EQUAL 20)
|
||||
#endif
|
||||
"
|
||||
ERROR)
|
||||
expect_compile(
|
||||
format-string-embedded-nul-error
|
||||
"
|
||||
#if FMT_USE_CONSTEVAL
|
||||
fmt::format(\"a\\0{}\");
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
"
|
||||
ERROR)
|
||||
|
||||
# Compile-time argument name check
|
||||
expect_compile(
|
||||
|
||||
@ -1,19 +1,22 @@
|
||||
// Formatting library for C++ - formatting library tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#include "fmt/compile.h"
|
||||
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "fmt/chrono.h"
|
||||
#include "fmt/color.h"
|
||||
#include "fmt/ranges.h"
|
||||
#include "fmt/std.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest-extra.h"
|
||||
|
||||
@ -87,7 +90,6 @@ TEST(compile_test, format_escape) {
|
||||
EXPECT_EQ("\"abc\" ", fmt::format(FMT_COMPILE("{0:<7?}"), "abc"));
|
||||
}
|
||||
|
||||
|
||||
TEST(compile_test, format_specs) {
|
||||
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42));
|
||||
EXPECT_EQ("1.2 ms ",
|
||||
@ -224,6 +226,19 @@ TEST(compile_test, constexpr_formatted_size) {
|
||||
FMT_CONSTEXPR20 size_t str_size =
|
||||
fmt::formatted_size(FMT_COMPILE("{:s}"), "abc");
|
||||
EXPECT_EQ(str_size, 3);
|
||||
FMT_CONSTEXPR20 size_t tuple_size = fmt::formatted_size(
|
||||
FMT_COMPILE("{}"), fmt::join(std::tuple(1, 2, 3), ","));
|
||||
EXPECT_EQ(tuple_size, 5);
|
||||
FMT_CONSTEXPR20 size_t array_size = fmt::formatted_size(
|
||||
FMT_COMPILE("{}"), fmt::join(std::array<int, 3>{1, 2, 3}, ","));
|
||||
EXPECT_EQ(array_size, 5);
|
||||
FMT_CONSTEXPR20 size_t styled_size = fmt::formatted_size(
|
||||
FMT_COMPILE("{}"),
|
||||
fmt::styled(std::array{1, 2, 3}, fmt::bg(fmt::color::green)));
|
||||
EXPECT_EQ(styled_size, 32);
|
||||
FMT_CONSTEXPR20 size_t variant_size = fmt::formatted_size(
|
||||
FMT_COMPILE("{}"), std::variant<std::monostate, char>{});
|
||||
EXPECT_EQ(variant_size, 18);
|
||||
}
|
||||
|
||||
TEST(compile_test, static_format) {
|
||||
@ -464,3 +479,13 @@ TEST(compile_test, constexpr_string_format) {
|
||||
EXPECT_TRUE(big);
|
||||
}
|
||||
#endif // FMT_USE_CONSTEXPR_STRING
|
||||
|
||||
namespace {
|
||||
struct compile_format_as_type {
|
||||
int value;
|
||||
};
|
||||
int format_as(compile_format_as_type f) { return f.value; }
|
||||
}
|
||||
TEST(compile_test, format_as) {
|
||||
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), compile_format_as_type{42}));
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - tests of formatters for standard library types
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - formatting library tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
// Formatting library for C++ - formatting library implementation tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
// clang-format off
|
||||
@ -14,7 +13,6 @@
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "util.h"
|
||||
|
||||
using fmt::detail::bigint;
|
||||
using fmt::detail::fp;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - formatting library tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -15,17 +15,17 @@
|
||||
|
||||
#include <stdint.h> // uint32_t
|
||||
|
||||
#include <cfenv> // fegetexceptflag and FE_ALL_EXCEPT
|
||||
#include <climits> // INT_MAX
|
||||
#include <cmath> // std::signbit
|
||||
#include <condition_variable> // std::condition_variable
|
||||
#include <cstring> // std::strlen
|
||||
#include <iterator> // std::back_inserter
|
||||
#include <list> // std::list
|
||||
#include <mutex> // std::mutex
|
||||
#include <string> // std::string
|
||||
#include <thread> // std::thread
|
||||
#include <type_traits> // std::is_default_constructible
|
||||
#include <cfenv> // fegetexceptflag and FE_ALL_EXCEPT
|
||||
#include <climits> // INT_MAX
|
||||
#include <cmath> // std::signbit
|
||||
#include <csignal> // std::signal, SIGPIPE
|
||||
#include <cstring> // std::strlen
|
||||
#include <iterator> // std::back_inserter
|
||||
#include <list> // std::list
|
||||
#include <mutex> // std::mutex
|
||||
#include <string> // std::string
|
||||
#include <thread> // std::thread
|
||||
#include <type_traits> // std::is_default_constructible
|
||||
#if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE(<version>)
|
||||
# include <version>
|
||||
#endif
|
||||
@ -82,6 +82,11 @@ TEST(uint128_test, minus) {
|
||||
EXPECT_EQ(n - 2, 40);
|
||||
}
|
||||
|
||||
TEST(uint128_test, bitwise_not) {
|
||||
auto n = ~uint128(0x123456789abcdef0, 0x0fedcba987654321);
|
||||
EXPECT_EQ(n, uint128(0xedcba9876543210f, 0xf0123456789abcde));
|
||||
}
|
||||
|
||||
TEST(uint128_test, plus_assign) {
|
||||
auto n = uint128(32);
|
||||
n += uint128(10);
|
||||
@ -268,22 +273,6 @@ TEST(util_test, format_system_error) {
|
||||
fmt::format_system_error(message, EDOM, "test");
|
||||
auto ec = std::error_code(EDOM, std::generic_category());
|
||||
EXPECT_EQ(to_string(message), std::system_error(ec, "test").what());
|
||||
message = fmt::memory_buffer();
|
||||
|
||||
// Check if std::allocator throws on allocating max size_t / 2 chars.
|
||||
size_t max_size = max_value<size_t>() / 2;
|
||||
bool throws_on_alloc = false;
|
||||
try {
|
||||
auto alloc = std::allocator<char>();
|
||||
alloc.deallocate(alloc.allocate(max_size), max_size);
|
||||
} catch (const std::bad_alloc&) {
|
||||
throws_on_alloc = true;
|
||||
}
|
||||
if (!throws_on_alloc) {
|
||||
fmt::print(stderr, "warning: std::allocator allocates {} chars\n",
|
||||
max_size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(util_test, system_error) {
|
||||
@ -1345,6 +1334,16 @@ TEST(format_test, format_int) {
|
||||
"invalid format specifier");
|
||||
check_unknown_types(42, "bBdoxXnLc", "integer");
|
||||
EXPECT_EQ(fmt::format("{:c}", static_cast<int>('x')), "x");
|
||||
// The 'c' type treats all character types as unsigned for portability, so the
|
||||
// representable range for char is [0, 255] and out-of-range values are
|
||||
// reported as an error.
|
||||
EXPECT_EQ(fmt::format("{:c}", 200), std::string(1, static_cast<char>(200)));
|
||||
EXPECT_EQ(fmt::format("{:c}", 255), std::string(1, static_cast<char>(255)));
|
||||
const char* msg = "character value out of range";
|
||||
EXPECT_THROW_MSG((void)fmt::format("{:c}", -1), format_error, msg);
|
||||
EXPECT_THROW_MSG((void)fmt::format("{:c}", -104), format_error, msg);
|
||||
EXPECT_THROW_MSG((void)fmt::format("{:c}", 256), format_error, msg);
|
||||
EXPECT_THROW_MSG((void)fmt::format("{:c}", 400u), format_error, msg);
|
||||
}
|
||||
|
||||
TEST(format_test, format_bin) {
|
||||
@ -2609,6 +2608,24 @@ TEST(format_test, invalid_glibc_buffer) {
|
||||
|
||||
fmt::print(file, "------\n");
|
||||
}
|
||||
|
||||
TEST(format_test, print_to_broken_pipe) {
|
||||
// Ignore SIGPIPE so that a failing write reports EPIPE instead of
|
||||
// terminating the test process. It must stay ignored until the file is
|
||||
// closed below because closing also flushes the remaining buffered data.
|
||||
auto old_handler = std::signal(SIGPIPE, SIG_IGN);
|
||||
{
|
||||
auto pipe = fmt::pipe();
|
||||
pipe.read_end.close();
|
||||
auto write_end = pipe.write_end.fdopen("w");
|
||||
|
||||
// The data must exceed the file's buffer to force a flush during
|
||||
// formatting, whose underlying write() then fails with EPIPE.
|
||||
auto data = std::string(1024 * 1024, 'x');
|
||||
EXPECT_THROW(fmt::print(write_end.get(), "{}", data), std::system_error);
|
||||
}
|
||||
std::signal(SIGPIPE, old_handler);
|
||||
}
|
||||
#endif // FMT_USE_FCNTL
|
||||
|
||||
// Only defined after the test case.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - tests of custom Google Test assertions
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -9,7 +9,6 @@
|
||||
|
||||
#include <gtest/gtest-spi.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - custom Google Test assertions
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - custom Google Test assertions
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - mock allocator
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,19 +1,9 @@
|
||||
// Formatting library for C++ - module tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
//
|
||||
// Copyright (c) 2021 - present, Daniela Engert
|
||||
// All Rights Reserved
|
||||
// {fmt} module.
|
||||
|
||||
#ifdef _MSC_FULL_VER
|
||||
// hide some implementation bugs in msvc
|
||||
// that are not essential to users of the module.
|
||||
# define FMT_HIDE_MODULE_BUGS
|
||||
#endif
|
||||
|
||||
#include <bit>
|
||||
#include <chrono>
|
||||
@ -25,6 +15,7 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#if (__has_include(<fcntl.h>) || defined(__APPLE__) || \
|
||||
defined(__linux__)) && \
|
||||
@ -42,14 +33,6 @@
|
||||
|
||||
import fmt;
|
||||
|
||||
// check for macros leaking from BMI
|
||||
static bool macro_leaked =
|
||||
#if defined(FMT_CORE_H_) || defined(FMT_FORMAT_H_)
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
|
||||
#define FMT_OS_H_ // don't pull in os.h, neither directly nor indirectly
|
||||
#include "gtest-extra.h"
|
||||
|
||||
@ -60,42 +43,11 @@ TEST(module_test, namespace) {
|
||||
ASSERT_TRUE(true);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
bool oops_detail_namespace_is_visible;
|
||||
}
|
||||
|
||||
namespace fmt {
|
||||
bool namespace_detail_invisible() {
|
||||
#if defined(FMT_HIDE_MODULE_BUGS) && defined(_MSC_FULL_VER) && \
|
||||
_MSC_FULL_VER <= 193700000
|
||||
// bug in msvc up to at least 17.7:
|
||||
|
||||
// the namespace is visible even when it is neither
|
||||
// implicitly nor explicitly exported
|
||||
return true;
|
||||
#else
|
||||
using namespace detail;
|
||||
// this fails to compile if fmt::detail is visible
|
||||
return !oops_detail_namespace_is_visible;
|
||||
#endif
|
||||
}
|
||||
} // namespace fmt
|
||||
|
||||
// the non-exported namespace 'detail' must be invisible [module.interface]/2
|
||||
TEST(module_test, detail_namespace) {
|
||||
EXPECT_TRUE(fmt::namespace_detail_invisible());
|
||||
}
|
||||
|
||||
// macros must not be imported from a *named* module [cpp.import]/5.1
|
||||
// Macros must not be imported from a named module [cpp.import]/5.1.
|
||||
TEST(module_test, macros) {
|
||||
#if defined(FMT_HIDE_MODULE_BUGS) && defined(_MSC_FULL_VER) && \
|
||||
_MSC_FULL_VER <= 192930130
|
||||
// bug in msvc up to 16.11-pre2:
|
||||
// include-guard macros leak from BMI
|
||||
// and even worse: they cannot be #undef-ined
|
||||
macro_leaked = false;
|
||||
#if defined(FMT_BASE_H_) || defined(FMT_FORMAT_H_)
|
||||
FAIL() << "Macros are leaking from a named module";
|
||||
#endif
|
||||
EXPECT_FALSE(macro_leaked);
|
||||
}
|
||||
|
||||
// The following is less about functional testing (that's done elsewhere)
|
||||
@ -167,78 +119,33 @@ TEST(module_test, format_to_n) {
|
||||
}
|
||||
|
||||
TEST(module_test, format_args) {
|
||||
auto no_args = fmt::format_args();
|
||||
EXPECT_FALSE(no_args.get(1));
|
||||
|
||||
fmt::basic_format_args args = fmt::make_format_args(42);
|
||||
EXPECT_TRUE(args.max_size() > 0);
|
||||
auto arg0 = args.get(0);
|
||||
EXPECT_TRUE(arg0);
|
||||
decltype(arg0) arg_none;
|
||||
EXPECT_FALSE(arg_none);
|
||||
EXPECT_TRUE(arg0.type() != arg_none.type());
|
||||
}
|
||||
|
||||
TEST(module_test, wformat_args) {
|
||||
auto no_args = fmt::wformat_args();
|
||||
EXPECT_FALSE(no_args.get(1));
|
||||
fmt::basic_format_args args = fmt::make_wformat_args(42);
|
||||
int n = 42;
|
||||
auto store = fmt::make_format_args(n);
|
||||
fmt::format_args args = store;
|
||||
EXPECT_TRUE(args.get(0));
|
||||
}
|
||||
|
||||
TEST(module_test, dynamic_format_args) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> dyn_store;
|
||||
dyn_store.push_back(fmt::arg("a42", 42));
|
||||
fmt::basic_format_args args = dyn_store;
|
||||
EXPECT_FALSE(args.get(3));
|
||||
EXPECT_TRUE(args.get(fmt::string_view("a42")));
|
||||
|
||||
fmt::dynamic_format_arg_store<fmt::wformat_context> wdyn_store;
|
||||
wdyn_store.push_back(fmt::arg(L"a42", 42));
|
||||
fmt::basic_format_args wargs = wdyn_store;
|
||||
EXPECT_FALSE(wargs.get(3));
|
||||
EXPECT_TRUE(wargs.get(fmt::wstring_view(L"a42")));
|
||||
EXPECT_FALSE(args.get(1));
|
||||
}
|
||||
|
||||
TEST(module_test, vformat) {
|
||||
EXPECT_EQ("42", fmt::vformat("{}", fmt::make_format_args(42)));
|
||||
EXPECT_EQ(L"42",
|
||||
fmt::vformat(fmt::wstring_view(L"{}"), fmt::make_wformat_args(42)));
|
||||
int n = 42;
|
||||
EXPECT_EQ("42", fmt::vformat("{}", fmt::make_format_args(n)));
|
||||
}
|
||||
|
||||
TEST(module_test, vformat_to) {
|
||||
auto store = fmt::make_format_args(42);
|
||||
int n = 42;
|
||||
auto store = fmt::make_format_args(n);
|
||||
std::string s;
|
||||
fmt::vformat_to(std::back_inserter(s), "{}", store);
|
||||
EXPECT_EQ("42", s);
|
||||
|
||||
char buffer[4] = {0};
|
||||
fmt::vformat_to(buffer, "{:}", store);
|
||||
EXPECT_EQ("42", std::string_view(buffer));
|
||||
|
||||
auto wstore = fmt::make_wformat_args(42);
|
||||
std::wstring w;
|
||||
fmt::vformat_to(std::back_inserter(w), L"{}", wstore);
|
||||
EXPECT_EQ(L"42", w);
|
||||
|
||||
wchar_t wbuffer[4] = {0};
|
||||
fmt::vformat_to(wbuffer, L"{:}", wstore);
|
||||
EXPECT_EQ(L"42", std::wstring_view(wbuffer));
|
||||
}
|
||||
|
||||
TEST(module_test, vformat_to_n) {
|
||||
auto store = fmt::make_format_args(12345);
|
||||
int n = 12345;
|
||||
auto store = fmt::make_format_args(n);
|
||||
std::string s;
|
||||
auto result = fmt::vformat_to_n(std::back_inserter(s), 1, "{}", store);
|
||||
fmt::vformat_to_n(std::back_inserter(s), 1, "{}", store);
|
||||
char buffer[4] = {0};
|
||||
fmt::vformat_to_n(buffer, 3, "{:}", store);
|
||||
|
||||
auto wstore = fmt::make_wformat_args(12345);
|
||||
std::wstring w;
|
||||
auto wresult = fmt::vformat_to_n(std::back_inserter(w), 1,
|
||||
fmt::wstring_view(L"{}"), wstore);
|
||||
wchar_t wbuffer[4] = {0};
|
||||
fmt::vformat_to_n(wbuffer, 3, fmt::wstring_view(L"{:}"), wstore);
|
||||
}
|
||||
|
||||
std::string as_string(std::wstring_view text) {
|
||||
@ -249,18 +156,14 @@ std::string as_string(std::wstring_view text) {
|
||||
TEST(module_test, print) {
|
||||
EXPECT_WRITE(stdout, fmt::print("{}µ", 42), "42µ");
|
||||
EXPECT_WRITE(stderr, fmt::print(stderr, "{}µ", 4.2), "4.2µ");
|
||||
EXPECT_WRITE(stdout, fmt::print(L"{}µ", 42), as_string(L"42µ"));
|
||||
EXPECT_WRITE(stderr, fmt::print(stderr, L"{}µ", 4.2), as_string(L"4.2µ"));
|
||||
}
|
||||
|
||||
TEST(module_test, vprint) {
|
||||
EXPECT_WRITE(stdout, fmt::vprint("{:}µ", fmt::make_format_args(42)), "42µ");
|
||||
EXPECT_WRITE(stderr, fmt::vprint(stderr, "{}", fmt::make_format_args(4.2)),
|
||||
int n = 42;
|
||||
double m = 4.2;
|
||||
EXPECT_WRITE(stdout, fmt::vprint("{:}µ", fmt::make_format_args(n)), "42µ");
|
||||
EXPECT_WRITE(stderr, fmt::vprint(stderr, "{}", fmt::make_format_args(m)),
|
||||
"4.2");
|
||||
EXPECT_WRITE(stdout, fmt::vprint(L"{:}µ", fmt::make_wformat_args(42)),
|
||||
as_string(L"42µ"));
|
||||
EXPECT_WRITE(stderr, fmt::vprint(stderr, L"{}", fmt::make_wformat_args(42)),
|
||||
as_string(L"42"));
|
||||
}
|
||||
|
||||
TEST(module_test, named_args) {
|
||||
@ -275,7 +178,8 @@ TEST(module_test, literals) {
|
||||
}
|
||||
|
||||
TEST(module_test, locale) {
|
||||
auto store = fmt::make_format_args(4.2);
|
||||
const double m = 4.2;
|
||||
auto store = fmt::make_format_args(m);
|
||||
const auto classic = std::locale::classic();
|
||||
EXPECT_EQ("4.2", fmt::format(classic, "{:L}", 4.2));
|
||||
EXPECT_EQ("4.2", fmt::vformat(classic, "{:L}", store));
|
||||
@ -283,14 +187,6 @@ TEST(module_test, locale) {
|
||||
fmt::vformat_to(std::back_inserter(s), classic, "{:L}", store);
|
||||
EXPECT_EQ("4.2", s);
|
||||
EXPECT_EQ("4.2", fmt::format("{:L}", 4.2));
|
||||
|
||||
auto wstore = fmt::make_wformat_args(4.2);
|
||||
EXPECT_EQ(L"4.2", fmt::format(classic, L"{:L}", 4.2));
|
||||
EXPECT_EQ(L"4.2", fmt::vformat(classic, L"{:L}", wstore));
|
||||
std::wstring w;
|
||||
fmt::vformat_to(std::back_inserter(w), classic, L"{:L}", wstore);
|
||||
EXPECT_EQ(L"4.2", w);
|
||||
EXPECT_EQ(L"4.2", fmt::format(L"{:L}", 4.2));
|
||||
}
|
||||
|
||||
TEST(module_test, string_view) {
|
||||
@ -313,34 +209,17 @@ TEST(module_test, memory_buffer) {
|
||||
EXPECT_EQ("42", to_string(buffer));
|
||||
nbuffer.clear();
|
||||
EXPECT_EQ(0u, to_string(nbuffer).size());
|
||||
|
||||
fmt::wmemory_buffer wbuffer;
|
||||
EXPECT_EQ(0u, to_string(wbuffer).size());
|
||||
}
|
||||
|
||||
TEST(module_test, is_char) {
|
||||
EXPECT_TRUE(fmt::is_char<char>());
|
||||
EXPECT_TRUE(fmt::is_char<wchar_t>());
|
||||
EXPECT_TRUE(fmt::is_char<char8_t>());
|
||||
EXPECT_TRUE(fmt::is_char<char16_t>());
|
||||
EXPECT_TRUE(fmt::is_char<char32_t>());
|
||||
EXPECT_FALSE(fmt::is_char<signed char>());
|
||||
}
|
||||
|
||||
TEST(module_test, ptr) {
|
||||
uintptr_t answer = 42;
|
||||
auto p = std::bit_cast<int*>(answer);
|
||||
EXPECT_EQ("0x2a", fmt::to_string(fmt::ptr(p)));
|
||||
std::unique_ptr<int> up(p);
|
||||
EXPECT_EQ("0x2a", fmt::to_string(fmt::ptr(up)));
|
||||
up.release();
|
||||
auto sp = std::make_shared<int>(0);
|
||||
p = sp.get();
|
||||
EXPECT_EQ(fmt::to_string(fmt::ptr(p)), fmt::to_string(fmt::ptr(sp)));
|
||||
}
|
||||
|
||||
TEST(module_test, errors) {
|
||||
auto store = fmt::make_format_args(42);
|
||||
int n = 42;
|
||||
auto store = fmt::make_format_args(n);
|
||||
EXPECT_THROW(throw fmt::format_error("oops"), std::exception);
|
||||
EXPECT_THROW(throw fmt::vsystem_error(0, "{}", store), std::system_error);
|
||||
EXPECT_THROW(throw fmt::system_error(0, "{}", 42), std::system_error);
|
||||
@ -365,8 +244,6 @@ TEST(module_test, error_code) {
|
||||
fmt::format("{0}", std::error_code(42, std::generic_category())));
|
||||
EXPECT_EQ("system:42",
|
||||
fmt::format("{0}", std::error_code(42, fmt::system_category())));
|
||||
EXPECT_EQ(L"generic:42",
|
||||
fmt::format(L"{0}", std::error_code(42, std::generic_category())));
|
||||
}
|
||||
|
||||
TEST(module_test, format_int) {
|
||||
@ -385,23 +262,19 @@ TEST(module_test, formatter) { EXPECT_TRUE(test_formatter{}.check()); }
|
||||
TEST(module_test, join) {
|
||||
int arr[3] = {1, 2, 3};
|
||||
std::vector<double> vec{1.0, 2.0, 3.0};
|
||||
std::initializer_list<int> il{1, 2, 3};
|
||||
auto sep = fmt::string_view(", ");
|
||||
EXPECT_EQ("1, 2, 3", to_string(fmt::join(arr + 0, arr + 3, sep)));
|
||||
EXPECT_EQ("1, 2, 3", to_string(fmt::join(arr, sep)));
|
||||
EXPECT_EQ("1, 2, 3", to_string(fmt::join(vec.begin(), vec.end(), sep)));
|
||||
EXPECT_EQ("1, 2, 3", to_string(fmt::join(vec, sep)));
|
||||
EXPECT_EQ("1, 2, 3", to_string(fmt::join(il, sep)));
|
||||
|
||||
auto wsep = fmt::wstring_view(L", ");
|
||||
EXPECT_EQ(L"1, 2, 3", fmt::format(L"{}", fmt::join(arr + 0, arr + 3, wsep)));
|
||||
EXPECT_EQ(L"1, 2, 3", fmt::format(L"{}", fmt::join(arr, wsep)));
|
||||
EXPECT_EQ(L"1, 2, 3", fmt::format(L"{}", fmt::join(il, wsep)));
|
||||
}
|
||||
|
||||
TEST(module_test, time) {
|
||||
auto time_now = std::time(nullptr);
|
||||
EXPECT_TRUE(fmt::localtime(time_now).tm_year > 120);
|
||||
EXPECT_TRUE(fmt::gmtime(time_now).tm_year > 120);
|
||||
auto chrono_now = std::chrono::system_clock::now();
|
||||
EXPECT_TRUE(fmt::gmtime(chrono_now).tm_year > 120);
|
||||
@ -433,42 +306,17 @@ TEST(module_test, weekday) {
|
||||
TEST(module_test, printf) {
|
||||
EXPECT_WRITE(stdout, fmt::printf("%f", 42.123456), "42.123456");
|
||||
EXPECT_WRITE(stdout, fmt::printf("%d", 42), "42");
|
||||
EXPECT_WRITE(stdout, fmt::printf(L"%f", 42.123456), as_string(L"42.123456"));
|
||||
EXPECT_WRITE(stdout, fmt::printf(L"%d", 42), as_string(L"42"));
|
||||
}
|
||||
|
||||
TEST(module_test, fprintf) {
|
||||
EXPECT_WRITE(stderr, fmt::fprintf(stderr, "%d", 42), "42");
|
||||
EXPECT_WRITE(stderr, fmt::fprintf(stderr, L"%d", 42), as_string(L"42"));
|
||||
}
|
||||
|
||||
TEST(module_test, sprintf) {
|
||||
EXPECT_EQ("42", fmt::sprintf("%d", 42));
|
||||
EXPECT_EQ(L"42", fmt::sprintf(L"%d", 42));
|
||||
}
|
||||
|
||||
TEST(module_test, vprintf) {
|
||||
EXPECT_WRITE(stdout, fmt::vprintf("%d", fmt::make_printf_args(42)), "42");
|
||||
EXPECT_WRITE(stdout, fmt::vprintf(L"%d", fmt::make_wprintf_args(42)),
|
||||
as_string(L"42"));
|
||||
}
|
||||
|
||||
TEST(module_test, vfprintf) {
|
||||
auto args = fmt::make_printf_args(42);
|
||||
EXPECT_WRITE(stderr, fmt::vfprintf(stderr, "%d", args), "42");
|
||||
auto wargs = fmt::make_wprintf_args(42);
|
||||
EXPECT_WRITE(stderr, fmt::vfprintf(stderr, L"%d", wargs), as_string(L"42"));
|
||||
}
|
||||
|
||||
TEST(module_test, vsprintf) {
|
||||
EXPECT_EQ("42", fmt::vsprintf("%d", fmt::make_printf_args(42)));
|
||||
EXPECT_EQ(L"42", fmt::vsprintf(L"%d", fmt::make_wprintf_args(42)));
|
||||
}
|
||||
|
||||
TEST(module_test, color) {
|
||||
auto fg_check = fg(fmt::rgb(255, 200, 30));
|
||||
auto bg_check = bg(fmt::color::dark_slate_gray) | fmt::emphasis::italic;
|
||||
auto emphasis_check = fmt::emphasis::underline | fmt::emphasis::bold;
|
||||
EXPECT_EQ("\x1B[30m42\x1B[0m",
|
||||
fmt::format(fg(fmt::terminal_color::black), "{}", 42));
|
||||
EXPECT_EQ(L"\x1B[30m42\x1B[0m",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - formatting library tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - Noexception tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
// Formatting library for C++ - tests of the OS-specific functionality
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#include "fmt/os.h"
|
||||
|
||||
#include <cstdlib> // std::exit
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - std::ostream support tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Tests of the C++ interface to POSIX functions that require mocks
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -15,19 +15,19 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <climits>
|
||||
#include <memory>
|
||||
|
||||
#include "../src/os.cc"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <io.h>
|
||||
|
||||
# include <climits> // UINT_MAX
|
||||
# undef max
|
||||
#endif
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest-extra.h"
|
||||
#include "util.h"
|
||||
|
||||
using fmt::buffered_file;
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - mocks of POSIX functions
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - printf tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -9,7 +9,6 @@
|
||||
|
||||
#include <cctype>
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
|
||||
#include "fmt/xchar.h" // DEPRECATED!
|
||||
#include "gtest-extra.h"
|
||||
@ -47,6 +46,14 @@ auto test_sprintf(fmt::basic_string_view<wchar_t> format, const Args&... args)
|
||||
|
||||
TEST(printf_test, no_args) { EXPECT_EQ("test", test_sprintf("test")); }
|
||||
|
||||
TEST(printf_test, trailing_percent) {
|
||||
EXPECT_THROW_MSG(test_sprintf("%"), format_error, "invalid format string");
|
||||
EXPECT_THROW_MSG(test_sprintf("hello%"), format_error,
|
||||
"invalid format string");
|
||||
EXPECT_THROW_MSG(test_sprintf("%1$d%", 1, 2), format_error,
|
||||
"invalid format string");
|
||||
}
|
||||
|
||||
TEST(printf_test, escape) {
|
||||
EXPECT_EQ("%", test_sprintf("%%"));
|
||||
EXPECT_EQ("before %", test_sprintf("before %%"));
|
||||
@ -77,8 +84,6 @@ TEST(printf_test, number_is_too_big_in_arg_index) {
|
||||
}
|
||||
|
||||
TEST(printf_test, switch_arg_indexing) {
|
||||
EXPECT_THROW_MSG(test_sprintf("%1$d%", 1, 2), format_error,
|
||||
"cannot switch from manual to automatic argument indexing");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", big_num), 1, 2),
|
||||
format_error, "number is too big");
|
||||
EXPECT_THROW_MSG(test_sprintf("%1$d%d", 1, 2), format_error,
|
||||
@ -111,6 +116,17 @@ TEST(printf_test, invalid_arg_index) {
|
||||
"argument not found");
|
||||
}
|
||||
|
||||
TEST(printf_test, zero_positional_width_precision) {
|
||||
// A '0' positional index for a '*' width or precision must be rejected. Use
|
||||
// enough arguments to exercise the unpacked argument storage path.
|
||||
EXPECT_THROW_MSG(test_sprintf("%*0$d", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
|
||||
13, 14, 15, 16),
|
||||
format_error, "argument not found");
|
||||
EXPECT_THROW_MSG(test_sprintf("%.*0$d", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
|
||||
13, 14, 15, 16),
|
||||
format_error, "argument not found");
|
||||
}
|
||||
|
||||
TEST(printf_test, default_align_right) {
|
||||
EXPECT_PRINTF(" 42", "%5d", 42);
|
||||
EXPECT_PRINTF(" abc", "%5s", "abc");
|
||||
@ -313,7 +329,8 @@ TEST(printf_test, positional_precision) {
|
||||
EXPECT_EQ("Hell", test_sprintf("%2$.*1$s", 4, "Hello"));
|
||||
EXPECT_THROW_MSG(test_sprintf("%2$.*1$d", 5.0, 42), format_error,
|
||||
"precision is not integer");
|
||||
EXPECT_THROW_MSG(test_sprintf("%2$.*1$d"), format_error, "argument not found");
|
||||
EXPECT_THROW_MSG(test_sprintf("%2$.*1$d"), format_error,
|
||||
"argument not found");
|
||||
EXPECT_THROW_MSG(test_sprintf("%2$.*1$d", big_num, 42), format_error,
|
||||
"number is too big");
|
||||
}
|
||||
@ -322,7 +339,8 @@ TEST(printf_test, positional_width_and_precision) {
|
||||
EXPECT_EQ(" 00042", test_sprintf("%3$*1$.*2$d", 7, 5, 42));
|
||||
EXPECT_EQ(" ab", test_sprintf("%3$*1$.*2$s", 7, 2, "abcdef"));
|
||||
EXPECT_EQ(" 00042", test_sprintf("%3$*1$.*2$x", 7, 5, 0x42));
|
||||
EXPECT_EQ("100.4400000", test_sprintf("%6$-*5$.*4$f%3$s%2$s%1$s", "", "", "", 7, 4, 100.44));
|
||||
EXPECT_EQ("100.4400000",
|
||||
test_sprintf("%6$-*5$.*4$f%3$s%2$s%1$s", "", "", "", 7, 4, 100.44));
|
||||
}
|
||||
|
||||
template <typename T> struct make_signed {
|
||||
@ -555,3 +573,8 @@ TEST(printf_test, make_printf_args) {
|
||||
fmt::vsprintf(fmt::basic_string_view<wchar_t>(L"[%d] %s happened"),
|
||||
{fmt::make_printf_args<wchar_t>(n, L"something")}));
|
||||
}
|
||||
|
||||
TEST(printf_test, trailing_percent_non_nul_terminated) {
|
||||
auto p = std::unique_ptr<char>(new char('%'));
|
||||
EXPECT_THROW(fmt::sprintf(fmt::string_view(p.get(), 1)), format_error);
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - the core API
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -10,7 +10,6 @@
|
||||
#include <array>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <numeric>
|
||||
#include <queue>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
@ -272,6 +271,23 @@ TEST(ranges_test, disabled_range_formatting_of_path) {
|
||||
fmt::range_format::disabled);
|
||||
}
|
||||
|
||||
template <typename T> struct optional_like {
|
||||
auto begin() const -> const T*;
|
||||
auto end() const -> const T*;
|
||||
|
||||
bool has_value() const noexcept;
|
||||
T& value() &;
|
||||
const T& value() const&;
|
||||
T&& value() &&;
|
||||
const T&& value() const&&;
|
||||
};
|
||||
|
||||
TEST(ranges_test, disabled_range_formatting_of_optional) {
|
||||
// (C++26) Has a range support for std::optional.
|
||||
EXPECT_EQ((fmt::range_format_kind<optional_like<int>, char>::value),
|
||||
fmt::range_format::disabled);
|
||||
}
|
||||
|
||||
struct vector_string : std::vector<char> {
|
||||
using base = std::vector<char>;
|
||||
using base::base;
|
||||
@ -710,10 +726,17 @@ struct codec_mask {
|
||||
int except = 0;
|
||||
};
|
||||
|
||||
// A named functor instead of a lambda to avoid -Wsubobject-linkage: a lambda
|
||||
// gives the filter_view type internal linkage, which propagates to the
|
||||
// formatter base class via format_as.
|
||||
struct not_equal {
|
||||
int value;
|
||||
bool operator()(int c) const { return c != value; }
|
||||
};
|
||||
|
||||
auto format_as(codec_mask mask) {
|
||||
// Careful not to capture param by reference here, it will dangle.
|
||||
return codec_mask::codecs |
|
||||
std::views::filter([mask](auto c) { return c != mask.except; });
|
||||
std::views::filter(not_equal{mask.except});
|
||||
}
|
||||
} // namespace views_filter_view_test
|
||||
|
||||
|
||||
@ -1,14 +1,12 @@
|
||||
// Formatting library for C++ - scanning API test
|
||||
//
|
||||
// Copyright (c) 2019 - present, Victor Zverovich
|
||||
// Copyright (c) 2019 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#include "scan.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <climits>
|
||||
#include <thread>
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - scanning API proof of concept
|
||||
//
|
||||
// Copyright (c) 2019 - present, Victor Zverovich
|
||||
// Copyright (c) 2019 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - tests of formatters for standard library types
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
@ -402,6 +402,67 @@ TEST(std_test, exception) {
|
||||
StartsWith("std::filesystem::filesystem_error: "));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FMT_USE_RTTI
|
||||
// Nested exceptions (e.g. from std::throw_with_nested) are unwound.
|
||||
try {
|
||||
try {
|
||||
throw std::runtime_error("inner");
|
||||
} catch (...) {
|
||||
std::throw_with_nested(std::runtime_error("outer"));
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
EXPECT_EQ("outer: inner", fmt::format("{}", ex));
|
||||
}
|
||||
|
||||
// Multiple levels of nesting.
|
||||
try {
|
||||
try {
|
||||
try {
|
||||
throw std::runtime_error("level 3");
|
||||
} catch (...) {
|
||||
std::throw_with_nested(std::runtime_error("level 2"));
|
||||
}
|
||||
} catch (...) {
|
||||
std::throw_with_nested(std::runtime_error("level 1"));
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
EXPECT_EQ("level 1: level 2: level 3", fmt::format("{}", ex));
|
||||
}
|
||||
#endif // FMT_USE_RTTI
|
||||
}
|
||||
|
||||
TEST(std_test, exception_ptr) {
|
||||
std::exception_ptr p1 = nullptr;
|
||||
std::exception_ptr p2;
|
||||
|
||||
try {
|
||||
using namespace my_ns1::my_ns2;
|
||||
throw my_exception("My Exception");
|
||||
} catch (...) {
|
||||
p2 = std::current_exception();
|
||||
}
|
||||
|
||||
EXPECT_EQ(fmt::format("{}", p1), "none");
|
||||
EXPECT_EQ(fmt::format("{}", p2), "My Exception");
|
||||
|
||||
#if FMT_USE_RTTI
|
||||
EXPECT_EQ(fmt::format("{:t}", p2),
|
||||
"my_ns1::my_ns2::my_exception: My Exception");
|
||||
|
||||
// Nested exceptions are unwound through an exception_ptr too.
|
||||
std::exception_ptr p3;
|
||||
try {
|
||||
try {
|
||||
throw std::runtime_error("inner");
|
||||
} catch (...) {
|
||||
std::throw_with_nested(std::runtime_error("outer"));
|
||||
}
|
||||
} catch (...) {
|
||||
p3 = std::current_exception();
|
||||
}
|
||||
EXPECT_EQ(fmt::format("{}", p3), "outer: inner");
|
||||
#endif // FMT_USE_RTTI
|
||||
}
|
||||
|
||||
#if FMT_USE_RTTI
|
||||
@ -409,7 +470,7 @@ TEST(std_test, type_info) {
|
||||
EXPECT_EQ(fmt::format("{}", typeid(std::runtime_error)),
|
||||
"std::runtime_error");
|
||||
}
|
||||
#endif
|
||||
#endif // FMT_USE_RTTI
|
||||
|
||||
#if FMT_USE_BITINT
|
||||
FMT_PRAGMA_CLANG(diagnostic ignored "-Wbit-int-extension")
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - test version of FMT_ASSERT
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - test main function.
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - Unicode tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - test utilities
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Formatting library for C++ - test utilities
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
@ -1,15 +1,13 @@
|
||||
// Formatting library for C++ - formatting library tests
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#include "fmt/xchar.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <complex>
|
||||
#include <cwchar>
|
||||
#include <vector>
|
||||
|
||||
#include "fmt/chrono.h"
|
||||
@ -146,6 +144,26 @@ TEST(format_test, wide_format_to_n) {
|
||||
EXPECT_EQ(L"BC x", fmt::wstring_view(buffer, 4));
|
||||
}
|
||||
|
||||
TEST(format_test, wide_format_to_n_runtime) {
|
||||
wchar_t buffer[4];
|
||||
buffer[3] = L'x';
|
||||
auto result = fmt::format_to_n(buffer, 3, fmt::runtime(L"{}"), 12345);
|
||||
EXPECT_EQ(5u, result.size);
|
||||
EXPECT_EQ(buffer + 3, result.out);
|
||||
EXPECT_EQ(L"123x", fmt::wstring_view(buffer, 4));
|
||||
buffer[0] = L'x';
|
||||
buffer[1] = L'x';
|
||||
buffer[2] = L'x';
|
||||
result = fmt::format_to_n(buffer, 3, fmt::runtime(L"{}"), L'A');
|
||||
EXPECT_EQ(1u, result.size);
|
||||
EXPECT_EQ(buffer + 1, result.out);
|
||||
EXPECT_EQ(L"Axxx", fmt::wstring_view(buffer, 4));
|
||||
result = fmt::format_to_n(buffer, 3, fmt::runtime(L"{}{} "), L'B', L'C');
|
||||
EXPECT_EQ(3u, result.size);
|
||||
EXPECT_EQ(buffer + 3, result.out);
|
||||
EXPECT_EQ(L"BC x", fmt::wstring_view(buffer, 4));
|
||||
}
|
||||
|
||||
TEST(xchar_test, named_arg_udl) {
|
||||
using namespace fmt::literals;
|
||||
auto udl_a =
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user