diff --git a/external/fmt/.clang-format b/external/fmt/.clang-format
index 31f8c343..08fa7ba8 100644
--- a/external/fmt/.clang-format
+++ b/external/fmt/.clang-format
@@ -7,6 +7,7 @@ IndentCaseLabels: false
AlwaysBreakTemplateDeclarations: false
DerivePointerAlignment: false
AllowShortCaseLabelsOnASingleLine: true
+QualifierAlignment: Left
AlignConsecutiveShortCaseStatements:
Enabled: true
AcrossEmptyLines: true
diff --git a/external/fmt/.github/workflows/cifuzz.yml b/external/fmt/.github/workflows/cifuzz.yml
index 50182ee9..3769e2a8 100644
--- a/external/fmt/.github/workflows/cifuzz.yml
+++ b/external/fmt/.github/workflows/cifuzz.yml
@@ -25,7 +25,7 @@ jobs:
language: c++
- name: Upload crash
- uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
+ uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
diff --git a/external/fmt/.github/workflows/doc.yml b/external/fmt/.github/workflows/doc.yml
index 019a85f1..d76eb47e 100644
--- a/external/fmt/.github/workflows/doc.yml
+++ b/external/fmt/.github/workflows/doc.yml
@@ -7,8 +7,7 @@ permissions:
jobs:
build:
- # Use Ubuntu 20.04 because doxygen 1.8.13 from Ubuntu 18.04 is broken.
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
@@ -25,7 +24,7 @@ jobs:
run: |
sudo apt update
sudo apt install doxygen
- pip install mkdocs-material==9.5.25 mkdocstrings==0.25.1 mike==2.1.1
+ pip install mkdocs-material==9.5.25 mkdocstrings==0.26.1 mike==2.1.1
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)"
diff --git a/external/fmt/.github/workflows/linux.yml b/external/fmt/.github/workflows/linux.yml
index 97150467..42a2d2ce 100644
--- a/external/fmt/.github/workflows/linux.yml
+++ b/external/fmt/.github/workflows/linux.yml
@@ -7,87 +7,143 @@ permissions:
jobs:
build:
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-22.04
strategy:
matrix:
- cxx: [g++-4.9, g++-10, clang++-9]
+ cxx: [g++-4.9, g++-11, clang++-3.6, clang++-11]
build_type: [Debug, Release]
std: [11]
shared: [""]
include:
- cxx: g++-4.9
- install: sudo apt install g++-4.9
- - cxx: g++-8
+ - cxx: clang++-3.6
+ - cxx: g++-11
build_type: Debug
std: 14
- install: sudo apt install g++-8
- - cxx: g++-8
- build_type: Debug
- std: 17
- install: sudo apt install g++-8
- - cxx: g++-9
- build_type: Debug
- std: 17
- - cxx: g++-10
+ install: sudo apt install g++-11
+ - cxx: g++-11
build_type: Debug
std: 17
- cxx: g++-11
build_type: Debug
std: 20
install: sudo apt install g++-11
- - cxx: clang++-8
- build_type: Debug
- std: 17
- cxxflags: -stdlib=libc++
- install: sudo apt install clang-8 libc++-8-dev libc++abi-8-dev
- - cxx: clang++-9
- install: sudo apt install clang-9
- - cxx: clang++-9
- build_type: Debug
- fuzz: -DFMT_FUZZ=ON -DFMT_FUZZ_LINKMAIN=ON
- std: 17
- install: sudo apt install clang-9
- - cxx: clang++-11
- build_type: Debug
- std: 20
- - cxx: clang++-11
- build_type: Debug
- std: 20
- cxxflags: -stdlib=libc++
- install: sudo apt install libc++-11-dev libc++abi-11-dev
- cxx: g++-13
build_type: Release
std: 23
install: sudo apt install g++-13
shared: -DBUILD_SHARED_LIBS=ON
+ - cxx: clang++-11
+ build_type: Debug
+ std: 17
+ cxxflags: -stdlib=libc++
+ install: sudo apt install clang-11 libc++-11-dev libc++abi-11-dev
+ - cxx: clang++-11
+ install: sudo apt install clang-11
+ - cxx: clang++-11
+ build_type: Debug
+ fuzz: -DFMT_FUZZ=ON -DFMT_FUZZ_LINKMAIN=ON
+ std: 17
+ install: sudo apt install clang-11
+ - cxx: clang++-14
+ build_type: Debug
+ std: 20
+ - cxx: clang++-14
+ build_type: Debug
+ std: 20
+ cxxflags: -stdlib=libc++
+ install: sudo apt install libc++-14-dev libc++abi-14-dev
steps:
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- name: Set timezone
- run: sudo timedatectl set-timezone 'Asia/Yekaterinburg'
+ run: sudo timedatectl set-timezone 'Europe/Kyiv'
- - name: Add repositories for older GCC
+ - name: Install GCC 4.9
run: |
- # Below repo provides GCC 4.9.
- sudo apt-add-repository 'deb http://dk.archive.ubuntu.com/ubuntu/ xenial main'
- sudo apt-add-repository 'deb http://dk.archive.ubuntu.com/ubuntu/ xenial universe'
+ sudo apt update
+ sudo apt install libatomic1 libc6-dev libgomp1 libitm1 libmpc3
+ # https://launchpad.net/ubuntu/xenial/amd64/g++-4.9/4.9.3-13ubuntu2
+ wget --no-verbose \
+ http://launchpadlibrarian.net/230069137/libmpfr4_3.1.3-2_amd64.deb \
+ http://launchpadlibrarian.net/253728424/libasan1_4.9.3-13ubuntu2_amd64.deb \
+ http://launchpadlibrarian.net/445346135/libubsan0_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ http://launchpadlibrarian.net/445346112/libcilkrts5_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ http://launchpadlibrarian.net/253728426/libgcc-4.9-dev_4.9.3-13ubuntu2_amd64.deb \
+ http://launchpadlibrarian.net/253728432/libstdc++-4.9-dev_4.9.3-13ubuntu2_amd64.deb \
+ http://launchpadlibrarian.net/253728314/gcc-4.9-base_4.9.3-13ubuntu2_amd64.deb \
+ http://launchpadlibrarian.net/445345919/gcc-5-base_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ http://launchpadlibrarian.net/253728399/cpp-4.9_4.9.3-13ubuntu2_amd64.deb \
+ http://launchpadlibrarian.net/253728404/gcc-4.9_4.9.3-13ubuntu2_amd64.deb \
+ http://launchpadlibrarian.net/253728401/g++-4.9_4.9.3-13ubuntu2_amd64.deb
+ sudo dpkg -i \
+ libmpfr4_3.1.3-2_amd64.deb \
+ libasan1_4.9.3-13ubuntu2_amd64.deb \
+ libubsan0_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ libcilkrts5_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ libgcc-4.9-dev_4.9.3-13ubuntu2_amd64.deb \
+ libstdc++-4.9-dev_4.9.3-13ubuntu2_amd64.deb \
+ gcc-4.9-base_4.9.3-13ubuntu2_amd64.deb \
+ gcc-5-base_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ cpp-4.9_4.9.3-13ubuntu2_amd64.deb \
+ gcc-4.9_4.9.3-13ubuntu2_amd64.deb \
+ g++-4.9_4.9.3-13ubuntu2_amd64.deb
if: ${{ matrix.cxx == 'g++-4.9' }}
+ - name: Install Clang 3.6
+ run: |
+ sudo apt update
+ sudo apt install libtinfo5
+ # https://code.launchpad.net/ubuntu/xenial/amd64/clang-3.6/1:3.6.2-3ubuntu2
+ wget --no-verbose \
+ http://launchpadlibrarian.net/230019046/libffi6_3.2.1-4_amd64.deb \
+ http://launchpadlibrarian.net/445346109/libasan2_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ http://launchpadlibrarian.net/445346135/libubsan0_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ http://launchpadlibrarian.net/445346112/libcilkrts5_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ http://launchpadlibrarian.net/445346128/libmpx0_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ http://launchpadlibrarian.net/445346113/libgcc-5-dev_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ http://launchpadlibrarian.net/445346131/libstdc++-5-dev_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ http://launchpadlibrarian.net/445346022/libobjc-5-dev_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ http://launchpadlibrarian.net/254405108/libllvm3.6v5_3.6.2-3ubuntu2_amd64.deb \
+ http://launchpadlibrarian.net/254405097/libclang-common-3.6-dev_3.6.2-3ubuntu2_amd64.deb \
+ http://launchpadlibrarian.net/254405101/libclang1-3.6_3.6.2-3ubuntu2_amd64.deb \
+ http://launchpadlibrarian.net/445345919/gcc-5-base_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ http://launchpadlibrarian.net/254405091/clang-3.6_3.6.2-3ubuntu2_amd64.deb
+ sudo dpkg -i \
+ libffi6_3.2.1-4_amd64.deb \
+ libasan2_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ libubsan0_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ libcilkrts5_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ libmpx0_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ libgcc-5-dev_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ libstdc++-5-dev_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ libobjc-5-dev_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ libllvm3.6v5_3.6.2-3ubuntu2_amd64.deb \
+ libclang-common-3.6-dev_3.6.2-3ubuntu2_amd64.deb \
+ libclang1-3.6_3.6.2-3ubuntu2_amd64.deb \
+ gcc-5-base_5.4.0-6ubuntu1~16.04.12_amd64.deb \
+ clang-3.6_3.6.2-3ubuntu2_amd64.deb
+ if: ${{ matrix.cxx == 'clang++-3.6' }}
+
- name: Add repositories for newer GCC
run: |
sudo apt-add-repository ppa:ubuntu-toolchain-r/test
- if: ${{ matrix.cxx == 'g++-11' || matrix.cxx == 'g++-13' }}
+ if: ${{ matrix.cxx == 'g++-13' }}
- name: Add Ubuntu mirrors
run: |
- # Github Actions caching proxy is at times unreliable
- # see https://github.com/actions/runner-images/issues/7048
- printf 'http://azure.archive.ubuntu.com/ubuntu\tpriority:1\n' | sudo tee /etc/apt/mirrors.txt
- curl http://mirrors.ubuntu.com/mirrors.txt | sudo tee --append /etc/apt/mirrors.txt
- sudo sed -i 's~http://azure.archive.ubuntu.com/ubuntu/~mirror+file:/etc/apt/mirrors.txt~' /etc/apt/sources.list
+ # GitHub Actions caching proxy is at times unreliable
+ # see https://github.com/actions/runner-images/issues/7048.
+ mirrors=/etc/apt/mirrors.txt
+ printf 'http://azure.archive.ubuntu.com/ubuntu\tpriority:1\n' | \
+ sudo tee $mirrors
+ curl http://mirrors.ubuntu.com/mirrors.txt | sudo tee --append $mirrors
+ sudo sed -i \
+ "s~http://azure.archive.ubuntu.com/ubuntu/~mirror+file:$mirrors~" \
+ /etc/apt/sources.list
- - name: Create Build Environment
+ - name: Create build environment
run: |
sudo apt update
${{matrix.install}}
@@ -100,10 +156,12 @@ jobs:
CXX: ${{matrix.cxx}}
CXXFLAGS: ${{matrix.cxxflags}}
run: |
- cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ${{matrix.fuzz}} ${{matrix.shared}} \
- -DCMAKE_CXX_STANDARD=${{matrix.std}} -DFMT_DOC=OFF \
- -DCMAKE_CXX_VISIBILITY_PRESET=hidden -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON \
- -DFMT_PEDANTIC=ON -DFMT_WERROR=ON $GITHUB_WORKSPACE
+ cmake -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
- name: Build
working-directory: ${{runner.workspace}}/build
diff --git a/external/fmt/.github/workflows/macos.yml b/external/fmt/.github/workflows/macos.yml
index 3543ef57..1a297e6d 100644
--- a/external/fmt/.github/workflows/macos.yml
+++ b/external/fmt/.github/workflows/macos.yml
@@ -28,7 +28,7 @@ jobs:
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- name: Set timezone
- run: sudo systemsetup -settimezone 'Asia/Yekaterinburg'
+ run: sudo systemsetup -settimezone 'Europe/Minsk'
- name: Select Xcode 14.3 (macOS 13)
run: sudo xcode-select -s "/Applications/Xcode_14.3.app"
diff --git a/external/fmt/.github/workflows/scorecard.yml b/external/fmt/.github/workflows/scorecard.yml
index b363a6f8..cb435568 100644
--- a/external/fmt/.github/workflows/scorecard.yml
+++ b/external/fmt/.github/workflows/scorecard.yml
@@ -34,7 +34,7 @@ jobs:
persist-credentials: false
- name: "Run analysis"
- uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
+ uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
with:
results_file: results.sarif
results_format: sarif
@@ -52,7 +52,7 @@ jobs:
# 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@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
+ uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: SARIF file
path: results.sarif
@@ -60,6 +60,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
- uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0
+ uses: github/codeql-action/upload-sarif@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
with:
sarif_file: results.sarif
diff --git a/external/fmt/.github/workflows/windows.yml b/external/fmt/.github/workflows/windows.yml
index 5403e652..931e7589 100644
--- a/external/fmt/.github/workflows/windows.yml
+++ b/external/fmt/.github/workflows/windows.yml
@@ -39,7 +39,7 @@ jobs:
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- name: Set timezone
- run: tzutil /s "Ekaterinburg Standard Time"
+ run: tzutil /s "FLE Standard Time"
- name: Create Build Environment
run: cmake -E make_directory ${{runner.workspace}}/build
@@ -78,7 +78,7 @@ jobs:
- name: Set timezone
run: tzutil /s "Ekaterinburg Standard Time"
shell: cmd
- - uses: msys2/setup-msys2@c52d1fa9c7492275e60fe763540fb601f5f232a1 # v2.25.0
+ - uses: msys2/setup-msys2@61f9e5e925871ba6c9e3e8da24ede83ea27fa91f # v2.27.0
with:
release: false
msystem: ${{matrix.sys}}
diff --git a/external/fmt/.gitignore b/external/fmt/.gitignore
index 2635026a..edd4b086 100644
--- a/external/fmt/.gitignore
+++ b/external/fmt/.gitignore
@@ -3,6 +3,7 @@
*.xcodeproj
*~
.vscode/
+.vs/
/CMakeScripts
/Testing
/_CPack_Packages
diff --git a/external/fmt/CMakeLists.txt b/external/fmt/CMakeLists.txt
index 586ead51..dd0e0743 100644
--- a/external/fmt/CMakeLists.txt
+++ b/external/fmt/CMakeLists.txt
@@ -27,7 +27,13 @@ endfunction()
# DEPRECATED! Should be merged into add_module_library.
function(enable_module target)
if (MSVC)
- set(BMI ${CMAKE_CURRENT_BINARY_DIR}/${target}.ifc)
+ if(CMAKE_GENERATOR STREQUAL "Ninja")
+ # Ninja dyndep expects the .ifc output to be located in a specific relative path
+ file(RELATIVE_PATH BMI_DIR "${CMAKE_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${target}.dir")
+ else()
+ set(BMI_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+ file(TO_NATIVE_PATH "${BMI_DIR}/${target}.ifc" BMI)
target_compile_options(${target}
PRIVATE /interface /ifcOutput ${BMI}
INTERFACE /reference fmt=${BMI})
@@ -69,8 +75,6 @@ function(add_module_library name)
target_compile_options(${name} PUBLIC -fmodules-ts)
endif ()
- target_compile_definitions(${name} PRIVATE FMT_MODULE)
-
if (FMT_USE_CMAKE_MODULES)
target_sources(${name} PUBLIC FILE_SET fmt TYPE CXX_MODULES
FILES ${sources})
@@ -201,8 +205,7 @@ if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
endif ()
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
- "${CMAKE_CURRENT_SOURCE_DIR}/support/cmake")
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/support/cmake")
include(CheckCXXCompilerFlag)
include(JoinPaths)
@@ -295,6 +298,7 @@ function(add_headers VAR)
endfunction()
# Define the fmt library, its includes and the needed defines.
+set(FMT_HEADERS)
add_headers(FMT_HEADERS args.h base.h chrono.h color.h compile.h core.h format.h
format-inl.h os.h ostream.h printf.h ranges.h std.h
xchar.h)
@@ -427,7 +431,7 @@ if (FMT_INSTALL)
# Install the library and headers.
install(TARGETS ${INSTALL_TARGETS}
- COMPONENT core
+ COMPONENT fmt_core
EXPORT ${targets_export_name}
LIBRARY DESTINATION ${FMT_LIB_DIR}
ARCHIVE DESTINATION ${FMT_LIB_DIR}
@@ -443,13 +447,13 @@ if (FMT_INSTALL)
# Install version, config and target files.
install(FILES ${project_config} ${version_config}
DESTINATION ${FMT_CMAKE_DIR}
- COMPONENT core)
+ COMPONENT fmt_core)
install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR}
NAMESPACE fmt::
- COMPONENT core)
+ COMPONENT fmt_core)
install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}"
- COMPONENT core)
+ COMPONENT fmt_core)
endif ()
function(add_doc_target)
@@ -486,7 +490,7 @@ function(add_doc_target)
include(GNUInstallDirs)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc-html/
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/doc/fmt
- COMPONENT doc OPTIONAL)
+ COMPONENT fmt_doc OPTIONAL)
endfunction()
if (FMT_DOC)
diff --git a/external/fmt/ChangeLog.md b/external/fmt/ChangeLog.md
index 09ebaed6..56baba39 100644
--- a/external/fmt/ChangeLog.md
+++ b/external/fmt/ChangeLog.md
@@ -1,3 +1,187 @@
+# 11.2.0 - 2025-05-03
+
+- Added the `s` specifier for `std::error_code`. It allows formatting an error
+ message as a string. For example:
+
+ ```c++
+ #include
+
+ int main() {
+ auto ec = std::make_error_code(std::errc::no_such_file_or_directory);
+ fmt::print("{:s}\n", ec);
+ }
+ ```
+
+ prints
+
+ ```
+ No such file or directory
+ ```
+ (The actual message is platform-specific.)
+
+- Fixed formatting of `std::chrono::local_time` and `tm`
+ (https://github.com/fmtlib/fmt/issues/3815,
+ https://github.com/fmtlib/fmt/issues/4350).
+ For example ([godbolt](https://www.godbolt.org/z/8o4b1PPn5)):
+
+ ```c++
+ #include
+
+ int main() {
+ std::chrono::zoned_time zt(
+ std::chrono::current_zone(),
+ std::chrono::system_clock::now());
+ fmt::print("{}", zt.get_local_time());
+ }
+ ```
+
+ is now formatted consistenly across platforms.
+
+- Added diagnostics for cases when timezone information is not available.
+ For example:
+
+ ```c++
+ fmt::print("{:Z}", std::chrono::local_seconds());
+ ```
+
+ now gives a compile-time error.
+
+- Deprecated `fmt::localtime` in favor of `std::localtime`.
+
+- Fixed compilation with GCC 15 and C++20 modules enabled
+ (https://github.com/fmtlib/fmt/pull/4347). Thanks @tkhyn.
+
+- Fixed handling of named arguments in format specs
+ (https://github.com/fmtlib/fmt/issues/4360,
+ https://github.com/fmtlib/fmt/pull/4361). Thanks @dinomight.
+
+- Added error reporting for duplicate named arguments
+ (https://github.com/fmtlib/fmt/pull/4367). Thanks @dinomight.
+
+- Fixed formatting of `long` with `FMT_BUILTIN_TYPES=0`
+ (https://github.com/fmtlib/fmt/issues/4375,
+ https://github.com/fmtlib/fmt/issues/4394).
+
+- Optimized `text_style` using bit packing
+ (https://github.com/fmtlib/fmt/pull/4363). Thanks @LocalSpook.
+
+- Added support for incomplete types (https://github.com/fmtlib/fmt/issues/3180,
+ https://github.com/fmtlib/fmt/pull/4383). Thanks @LocalSpook.
+
+- Fixed a flush issue in `fmt::print` when using libstdc++
+ (https://github.com/fmtlib/fmt/issues/4398).
+
+- Fixed `fmt::println` usage with `FMT_ENFORCE_COMPILE_STRING` and legacy
+ compile-time checks (https://github.com/fmtlib/fmt/pull/4407).
+ Thanks @madmaxoft.
+
+- Removed legacy header `fmt/core.h` from docs
+ (https://github.com/fmtlib/fmt/pull/4421,
+ https://github.com/fmtlib/fmt/pull/4422). Thanks @krzysztofkortas.
+
+- Worked around limitations of `__builtin_strlen` during constant evaluation
+ (https://github.com/fmtlib/fmt/issues/4423,
+ https://github.com/fmtlib/fmt/pull/4429). Thanks @BRevzin.
+
+- Worked around a bug in MSVC v141 (https://github.com/fmtlib/fmt/issues/4412,
+ https://github.com/fmtlib/fmt/pull/4413). Thanks @hirohira9119.
+
+- Removed the `fmt_detail` namespace
+ (https://github.com/fmtlib/fmt/issues/4324).
+
+- Removed specializations of `std::is_floating_point` in tests
+ (https://github.com/fmtlib/fmt/issues/4417).
+
+- Fixed a CMake error when setting `CMAKE_MODULE_PATH` in the pedantic mode
+ (https://github.com/fmtlib/fmt/pull/4426). Thanks @rlalik.
+
+- Updated the Bazel config (https://github.com/fmtlib/fmt/pull/4400).
+ Thanks @Vertexwahn.
+
+# 11.1.4 - 2025-02-26
+
+- Fixed ABI compatibility with earlier 11.x versions on Windows
+ (https://github.com/fmtlib/fmt/issues/4359).
+
+- Improved the logic of switching between fixed and exponential format for
+ `float` (https://github.com/fmtlib/fmt/issues/3649).
+
+- Moved `is_compiled_string` to the public API
+ (https://github.com/fmtlib/fmt/issues/4342). Thanks @SwooshyCueb.
+
+- Simplified implementation of `operator""_cf`
+ (https://github.com/fmtlib/fmt/pull/4349). Thanks @LocalSpook.
+
+- Fixed `__builtin_strlen` detection (https://github.com/fmtlib/fmt/pull/4329).
+ Thanks @LocalSpook.
+
+- Fixed handling of BMI paths with the Ninja generator
+ (https://github.com/fmtlib/fmt/pull/4344). Thanks @tkhyn.
+
+- Fixed gcc 8.3 compile errors (https://github.com/fmtlib/fmt/issues/4331,
+ https://github.com/fmtlib/fmt/pull/4336). Thanks @sergiud.
+
+- Fixed a bogus MSVC warning (https://github.com/fmtlib/fmt/pull/4356).
+ Thanks @dinomight.
+
+# 11.1.3 - 2025-01-25
+
+- Fixed compilation on GCC 9.4 (https://github.com/fmtlib/fmt/issues/4313).
+
+- Worked around an internal compiler error when using C++20 modules with GCC
+ 14.2 and earlier (https://github.com/fmtlib/fmt/issues/4295).
+
+- Worked around a bug in GCC 6 (https://github.com/fmtlib/fmt/issues/4318).
+
+- Fixed an issue caused by instantiating `formatter`
+ (https://github.com/fmtlib/fmt/issues/4303,
+ https://github.com/fmtlib/fmt/pull/4325). Thanks @timsong-cpp.
+
+- Fixed formatting into `std::ostreambuf_iterator` when using format string
+ compilation (https://github.com/fmtlib/fmt/issues/4309,
+ https://github.com/fmtlib/fmt/pull/4312). Thanks @phprus.
+
+- Restored a constraint on the map formatter so that it correctly reports as
+ unformattable when the element is (https://github.com/fmtlib/fmt/pull/4326).
+ Thanks @timsong-cpp.
+
+- Reduced the size of format specs (https://github.com/fmtlib/fmt/issues/4298).
+
+- Readded `args()` to `fmt::format_context`
+ (https://github.com/fmtlib/fmt/issues/4307,
+ https://github.com/fmtlib/fmt/pull/4310). Thanks @Erroneous1.
+
+- Fixed a bogus MSVC warning (https://github.com/fmtlib/fmt/issues/4314,
+ https://github.com/fmtlib/fmt/pull/4322). Thanks @ZehMatt.
+
+- Fixed a pedantic mode error in the CMake config
+ (https://github.com/fmtlib/fmt/pull/4327). Thanks @rlalik.
+
+# 11.1.2 - 2025-01-12
+
+- Fixed ABI compatibility with earlier 11.x versions
+ (https://github.com/fmtlib/fmt/issues/4292).
+
+- Added `wchar_t` support to the `std::bitset` formatter
+ (https://github.com/fmtlib/fmt/issues/4285,
+ https://github.com/fmtlib/fmt/pull/4286,
+ https://github.com/fmtlib/fmt/issues/4289,
+ https://github.com/fmtlib/fmt/pull/4290). Thanks @phprus.
+
+- Prefixed CMake components with `fmt-` to simplify usage of {fmt} via
+ `add_subdirectory` (https://github.com/fmtlib/fmt/issues/4283).
+
+- Updated docs for meson (https://github.com/fmtlib/fmt/pull/4291).
+ Thanks @trim21.
+
+- Fixed a compilation error in chrono on nvcc
+ (https://github.com/fmtlib/fmt/issues/4297,
+ https://github.com/fmtlib/fmt/pull/4301). Thanks @breyerml.
+
+- Fixed various warnings
+ (https://github.com/fmtlib/fmt/pull/4288,
+ https://github.com/fmtlib/fmt/pull/4299). Thanks @GamesTrap and @edo9300.
+
# 11.1.1 - 2024-12-27
- Fixed ABI compatibility with earlier 11.x versions
diff --git a/external/fmt/README.md b/external/fmt/README.md
index fd845db2..638ec522 100644
--- a/external/fmt/README.md
+++ b/external/fmt/README.md
@@ -47,7 +47,7 @@ Try {fmt} in [Compiler Explorer](https://godbolt.org/z/8Mx1EW73v).
hundred million integers to strings per
second](http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html)
- Small code size both in terms of source code with the minimum
- configuration consisting of just three files, `core.h`, `format.h`
+ configuration consisting of just three files, `base.h`, `format.h`
and `format-inl.h`, and compiled code; see [Compile time and code
bloat](#compile-time-and-code-bloat)
- Reliability: the library has an extensive set of
@@ -74,7 +74,7 @@ See the [documentation](https://fmt.dev) for more details.
**Print to stdout** ([run](https://godbolt.org/z/Tevcjh))
``` c++
-#include
+#include
int main() {
fmt::print("Hello, world!\n");
diff --git a/external/fmt/doc/ChangeLog-old.md b/external/fmt/doc/ChangeLog-old.md
index 3f31d1e9..e8f993c4 100644
--- a/external/fmt/doc/ChangeLog-old.md
+++ b/external/fmt/doc/ChangeLog-old.md
@@ -674,7 +674,7 @@
https://github.com/fmtlib/fmt/issues/1747,
https://github.com/fmtlib/fmt/pull/1750).
Thanks @gsjaardema, @gabime, @johnor, @Kurkin, @invexed, @peterbell10,
- @daixtrose, @petrutlucian94, @Neargye, @ambitslix, @gabime, @erthink,
+ @daixtrose, @petrutlucian94, @Neargye, @ambitslix, @gabime,
@tohammer and @0x8000-0000.
# 6.2.1 - 2020-05-09
diff --git a/external/fmt/doc/api.md b/external/fmt/doc/api.md
index e86f0b06..61e5c3de 100644
--- a/external/fmt/doc/api.md
+++ b/external/fmt/doc/api.md
@@ -79,6 +79,8 @@ time formatting and [`fmt/std.h`](#std-api) for other standard library types.
There are two ways to make a user-defined type formattable: providing a
`format_as` function or specializing the `formatter` struct template.
+Formatting of non-void pointer types is intentionally disallowed and they
+cannot be made formattable via either extension API.
Use `format_as` if you want to make your type formattable as some other
type with the same format specifiers. The `format_as` function should
@@ -220,7 +222,7 @@ You can also write a formatter for a hierarchy of classes:
```c++
// demo.h:
#include
-#include
+#include
struct A {
virtual ~A() {}
@@ -403,7 +405,7 @@ All formatting is locale-independent by default. Use the `'L'` format
specifier to insert the appropriate number separator characters from the
locale:
- #include
+ #include
#include
std::locale::global(std::locale("en_US.UTF-8"));
@@ -413,11 +415,11 @@ locale:
that take `std::locale` as a parameter. The locale type is a template
parameter to avoid the expensive `` include.
-::: format(detail::locale_ref, format_string, T&&...)
+::: format(const Locale&, format_string, T&&...)
-::: format_to(OutputIt, detail::locale_ref, format_string, T&&...)
+::: format_to(OutputIt, const Locale&, format_string, T&&...)
-::: formatted_size(detail::locale_ref, format_string, T&&...)
+::: formatted_size(const Locale&, format_string, T&&...)
### Legacy Compile-Time Checks
@@ -473,9 +475,9 @@ chrono-format-specifications).
#include
int main() {
- std::time_t t = std::time(nullptr);
+ auto now = std::chrono::system_clock::now();
- fmt::print("The date is {:%Y-%m-%d}.", fmt::localtime(t));
+ fmt::print("The date is {:%Y-%m-%d}.\n", now);
// Output: The date is 2020-11-07.
// (with 2020-11-07 replaced by the current date)
@@ -488,8 +490,6 @@ chrono-format-specifications).
// Output: strftime-like format: 03:15:30
}
-::: localtime(std::time_t)
-
::: gmtime(std::time_t)
@@ -580,7 +580,7 @@ performance bottleneck.
`fmt/color.h` provides support for terminal color and text style output.
-::: print(const text_style&, format_string, T&&...)
+::: print(text_style, format_string, T&&...)
::: fg(detail::color_type)
@@ -669,5 +669,13 @@ following differences:
- Names are defined in the `fmt` namespace instead of `std` to avoid
collisions with standard library implementations.
+
- Width calculation doesn't use grapheme clusterization. The latter has
been implemented in a separate branch but hasn't been integrated yet.
+
+- The default floating-point representation in {fmt} uses the smallest
+ precision that provides round-trip guarantees similarly to other languages
+ like Java and Python. `std::format` is currently specified in terms of
+ `std::to_chars` which tries to generate the smallest number of characters
+ (ignoring redundant digits and sign in exponent) and may procude more
+ decimal digits than necessary.
diff --git a/external/fmt/doc/index.md b/external/fmt/doc/index.md
index 4f28e114..a2694736 100644
--- a/external/fmt/doc/index.md
+++ b/external/fmt/doc/index.md
@@ -122,7 +122,7 @@ hide:
The library is highly portable and requires only a minimal subset of
- C++11 features which are available in GCC 4.9, Clang 3.4, MSVC 19.10
+ C++11 features which are available in GCC 4.9, Clang 3.6, MSVC 19.10
(2017) and later. Newer compiler and standard library features are used
if available, and enable additional functionality.
diff --git a/external/fmt/include/fmt/args.h b/external/fmt/include/fmt/args.h
index 3ff47880..d8fe241c 100644
--- a/external/fmt/include/fmt/args.h
+++ b/external/fmt/include/fmt/args.h
@@ -71,7 +71,7 @@ class dynamic_arg_list {
* It can be implicitly converted into `fmt::basic_format_args` for passing
* into type-erased formatting functions such as `fmt::vformat`.
*/
-template class dynamic_format_arg_store {
+FMT_EXPORT template class dynamic_format_arg_store {
private:
using char_type = typename Context::char_type;
diff --git a/external/fmt/include/fmt/base.h b/external/fmt/include/fmt/base.h
index a6948d40..81d8fc03 100644
--- a/external/fmt/include/fmt/base.h
+++ b/external/fmt/include/fmt/base.h
@@ -21,7 +21,7 @@
#endif
// The fmt library version in the form major * 10000 + minor * 100 + patch.
-#define FMT_VERSION 110101
+#define FMT_VERSION 110201
// Detect compiler versions.
#if defined(__clang__) && !defined(__ibmxl__)
@@ -96,9 +96,9 @@
// Detect C++14 relaxed constexpr.
#ifdef FMT_USE_CONSTEXPR
// Use the provided definition.
-#elif FMT_GCC_VERSION >= 600 && FMT_CPLUSPLUS >= 201402L
-// GCC only allows throw in constexpr since version 6:
-// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67371.
+#elif FMT_GCC_VERSION >= 702 && FMT_CPLUSPLUS >= 201402L
+// GCC only allows constexpr member functions in non-literal types since 7.2:
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66297.
# define FMT_USE_CONSTEXPR 1
#elif FMT_ICC_VERSION
# define FMT_USE_CONSTEXPR 0 // https://github.com/fmtlib/fmt/issues/1628
@@ -209,20 +209,6 @@
# define FMT_DEPRECATED /* deprecated */
#endif
-#ifdef FMT_ALWAYS_INLINE
-// Use the provided definition.
-#elif FMT_GCC_VERSION || FMT_CLANG_VERSION
-# define FMT_ALWAYS_INLINE inline __attribute__((always_inline))
-#else
-# define FMT_ALWAYS_INLINE inline
-#endif
-// A version of FMT_ALWAYS_INLINE to prevent code bloat in debug mode.
-#ifdef NDEBUG
-# define FMT_INLINE FMT_ALWAYS_INLINE
-#else
-# define FMT_INLINE inline
-#endif
-
#if FMT_GCC_VERSION || FMT_CLANG_VERSION
# define FMT_VISIBILITY(value) __attribute__((visibility(value)))
#else
@@ -249,6 +235,28 @@
# define FMT_MSC_WARNING(...)
#endif
+// Enable minimal optimizations for more compact code in debug mode.
+FMT_PRAGMA_GCC(push_options)
+#if !defined(__OPTIMIZE__) && !defined(__CUDACC__) && !defined(FMT_MODULE)
+FMT_PRAGMA_GCC(optimize("Og"))
+# define FMT_GCC_OPTIMIZED
+#endif
+FMT_PRAGMA_CLANG(diagnostic push)
+
+#ifdef FMT_ALWAYS_INLINE
+// Use the provided definition.
+#elif FMT_GCC_VERSION || FMT_CLANG_VERSION
+# define FMT_ALWAYS_INLINE inline __attribute__((always_inline))
+#else
+# define FMT_ALWAYS_INLINE inline
+#endif
+// A version of FMT_ALWAYS_INLINE to prevent code bloat in debug mode.
+#if defined(NDEBUG) || defined(FMT_GCC_OPTIMIZED)
+# define FMT_INLINE FMT_ALWAYS_INLINE
+#else
+# define FMT_INLINE inline
+#endif
+
#ifndef FMT_BEGIN_NAMESPACE
# define FMT_BEGIN_NAMESPACE \
namespace fmt { \
@@ -294,15 +302,8 @@
#endif
#define FMT_APPLY_VARIADIC(expr) \
- using ignore = int[]; \
- (void)ignore { 0, (expr, 0)... }
-
-// Enable minimal optimizations for more compact code in debug mode.
-FMT_PRAGMA_GCC(push_options)
-#if !defined(__OPTIMIZE__) && !defined(__CUDACC__)
-FMT_PRAGMA_GCC(optimize("Og"))
-#endif
-FMT_PRAGMA_CLANG(diagnostic push)
+ using unused = int[]; \
+ (void)unused { 0, (expr, 0)... }
FMT_BEGIN_NAMESPACE
@@ -325,8 +326,8 @@ using underlying_t = typename std::underlying_type::type;
template using decay_t = typename std::decay::type;
using nullptr_t = decltype(nullptr);
-#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
-// A workaround for gcc 4.9 to make void_t work in a SFINAE context.
+#if (FMT_GCC_VERSION && FMT_GCC_VERSION < 500) || FMT_MSC_VERSION
+// A workaround for gcc 4.9 & MSVC v141 to make void_t work in a SFINAE context.
template struct void_t_impl {
using type = void;
};
@@ -466,8 +467,7 @@ template constexpr const char* narrow(const T*) { return nullptr; }
constexpr FMT_ALWAYS_INLINE const char* narrow(const char* s) { return s; }
template
-FMT_CONSTEXPR auto compare(const Char* s1, const Char* s2, std::size_t n)
- -> int {
+FMT_CONSTEXPR auto compare(const Char* s1, const Char* s2, size_t n) -> int {
if (!is_constant_evaluated() && sizeof(Char) == 1) return memcmp(s1, s2, n);
for (; n != 0; ++s1, ++s2, --n) {
if (*s1 < *s2) return -1;
@@ -526,20 +526,20 @@ template class basic_string_view {
constexpr basic_string_view() noexcept : data_(nullptr), size_(0) {}
- /// Constructs a string reference object from a C string and a size.
+ /// Constructs a string view object from a C string and a size.
constexpr basic_string_view(const Char* s, size_t count) noexcept
: data_(s), size_(count) {}
constexpr basic_string_view(nullptr_t) = delete;
- /// Constructs a string reference object from a C string.
+ /// Constructs a string view object from a C string.
#if FMT_GCC_VERSION
FMT_ALWAYS_INLINE
#endif
FMT_CONSTEXPR20 basic_string_view(const Char* s) : data_(s) {
-#if FMT_HAS_BUILTIN(__buitin_strlen) || FMT_GCC_VERSION || FMT_CLANG_VERSION
- if (std::is_same::value) {
- size_ = __builtin_strlen(detail::narrow(s));
+#if FMT_HAS_BUILTIN(__builtin_strlen) || FMT_GCC_VERSION || FMT_CLANG_VERSION
+ if (std::is_same::value && !detail::is_constant_evaluated()) {
+ size_ = __builtin_strlen(detail::narrow(s)); // strlen is not constexpr.
return;
}
#endif
@@ -548,7 +548,7 @@ template class basic_string_view {
size_ = len;
}
- /// Constructs a string reference from a `std::basic_string` or a
+ /// Constructs a string view from a `std::basic_string` or a
/// `std::basic_string_view` object.
template ::value&& std::is_same<
@@ -585,7 +585,6 @@ template class basic_string_view {
return starts_with(basic_string_view(s));
}
- // Lexicographically compare this string reference to other.
FMT_CONSTEXPR auto compare(basic_string_view other) const -> int {
int result =
detail::compare(data_, other.data_, min_of(size_, other.size_));
@@ -616,7 +615,7 @@ template class basic_string_view {
using string_view = basic_string_view;
-/// Specifies if `T` is an extended character type. Can be specialized by users.
+// DEPRECATED! Will be merged with is_char and moved to detail.
template struct is_xchar : std::false_type {};
template <> struct is_xchar : std::true_type {};
template <> struct is_xchar : std::true_type {};
@@ -625,7 +624,7 @@ template <> struct is_xchar : std::true_type {};
template <> struct is_xchar : std::true_type {};
#endif
-// DEPRECATED! Will be replaced with an alias to prevent specializations.
+// Specifies if `T` is a character (code unit) type.
template struct is_char : is_xchar {};
template <> struct is_char : std::true_type {};
@@ -739,13 +738,15 @@ class basic_specs {
max_fill_size = 4
};
- size_t data_ = 1 << fill_size_shift;
+ unsigned data_ = 1 << fill_size_shift;
+ static_assert(sizeof(basic_specs::data_) * CHAR_BIT >= 18, "");
// Character (code unit) type is erased to prevent template bloat.
char fill_data_[max_fill_size] = {' '};
FMT_CONSTEXPR void set_fill_size(size_t size) {
- data_ = (data_ & ~fill_size_mask) | (size << fill_size_shift);
+ data_ = (data_ & ~fill_size_mask) |
+ (static_cast(size) << fill_size_shift);
}
public:
@@ -843,7 +844,7 @@ class basic_specs {
fill_data_[i & 3] = static_cast(s[i]);
}
- FMT_CONSTEXPR void set_fill(const basic_specs& specs) {
+ FMT_CONSTEXPR void copy_fill_from(const basic_specs& specs) {
set_fill_size(specs.fill_size());
for (size_t i = 0; i < max_fill_size; ++i)
fill_data_[i] = specs.fill_data_[i];
@@ -1030,6 +1031,11 @@ enum {
struct view {};
+template
+struct is_view : std::false_type {};
+template
+struct is_view> : std::is_base_of {};
+
template struct named_arg;
template struct is_named_arg : std::false_type {};
template struct is_static_named_arg : std::false_type {};
@@ -1062,6 +1068,16 @@ template struct named_arg_info {
int id;
};
+// named_args is non-const to suppress a bogus -Wmaybe-uninitialized in gcc 13.
+template
+FMT_CONSTEXPR void check_for_duplicate(named_arg_info* named_args,
+ int named_arg_index,
+ basic_string_view arg_name) {
+ for (int i = 0; i < named_arg_index; ++i) {
+ if (named_args[i].name == arg_name) report_error("duplicate named arg");
+ }
+}
+
template ::value)>
void init_named_arg(named_arg_info*, int& arg_index, int&, const T&) {
++arg_index;
@@ -1069,6 +1085,7 @@ void init_named_arg(named_arg_info*, int& arg_index, int&, const T&) {
template ::value)>
void init_named_arg(named_arg_info* named_args, int& arg_index,
int& named_arg_index, const T& arg) {
+ check_for_duplicate(named_args, named_arg_index, arg.name);
named_args[named_arg_index++] = {arg.name, arg_index++};
}
@@ -1082,12 +1099,13 @@ template ::value)>
FMT_CONSTEXPR void init_static_named_arg(named_arg_info* named_args,
int& arg_index, int& named_arg_index) {
+ check_for_duplicate(named_args, named_arg_index, T::name);
named_args[named_arg_index++] = {T::name, arg_index++};
}
// To minimize the number of types we need to deal with, long is translated
// either to int or to long long depending on its size.
-enum { long_short = sizeof(long) == sizeof(int) };
+enum { long_short = sizeof(long) == sizeof(int) && FMT_BUILTIN_TYPES };
using long_type = conditional_t;
using ulong_type = conditional_t;
@@ -1119,7 +1137,7 @@ using use_formatter =
bool_constant<(std::is_class::value || std::is_enum::value ||
std::is_union::value || std::is_array::value) &&
!has_to_string_view::value && !is_named_arg::value &&
- !use_format_as::value && !use_format_as_member::value>;
+ !use_format_as::value && !use_format_as_member::value>;
template >
auto has_formatter_impl(T* p, buffered_context* ctx = nullptr)
@@ -1660,12 +1678,12 @@ template struct arg_pack {};
template
class format_string_checker {
private:
- type types_[max_of(1, NUM_ARGS)];
- named_arg_info named_args_[max_of(1, NUM_NAMED_ARGS)];
+ type types_[max_of(1, NUM_ARGS)];
+ named_arg_info named_args_[max_of(1, NUM_NAMED_ARGS)];
compile_parse_context context_;
using parse_func = auto (*)(parse_context&) -> const Char*;
- parse_func parse_funcs_[max_of(1, NUM_ARGS)];
+ parse_func parse_funcs_[max_of(1, NUM_ARGS)];
public:
template
@@ -1704,7 +1722,17 @@ class format_string_checker {
-> const Char* {
context_.advance_to(begin);
if (id >= 0 && id < NUM_ARGS) return parse_funcs_[id](context_);
- while (begin != end && *begin != '}') ++begin;
+
+ // If id is out of range, it means we do not know the type and cannot parse
+ // the format at compile time. Instead, skip over content until we finish
+ // the format spec, accounting for any nested replacements.
+ for (int bracket_count = 0;
+ begin != end && (bracket_count > 0 || *begin != '}'); ++begin) {
+ if (*begin == '{')
+ ++bracket_count;
+ else if (*begin == '}')
+ --bracket_count;
+ }
return begin;
}
@@ -2004,6 +2032,17 @@ struct has_back_insert_iterator_container_append<
.append(std::declval(),
std::declval()))>> : std::true_type {};
+template
+struct has_back_insert_iterator_container_insert_at_end : std::false_type {};
+
+template
+struct has_back_insert_iterator_container_insert_at_end<
+ OutputIt, InputIt,
+ void_t())
+ .insert(get_container(std::declval()).end(),
+ std::declval(),
+ std::declval()))>> : std::true_type {};
+
// An optimized version of std::copy with the output value type (T).
template ::value&&
@@ -2018,6 +2057,8 @@ FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out)
template ::value &&
!has_back_insert_iterator_container_append<
+ OutputIt, InputIt>::value &&
+ has_back_insert_iterator_container_insert_at_end<
OutputIt, InputIt>::value)>
FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out)
-> OutputIt {
@@ -2027,7 +2068,11 @@ FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out)
}
template ::value)>
+ FMT_ENABLE_IF(!(is_back_insert_iterator::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(*begin++);
return out;
@@ -2234,6 +2279,7 @@ template class value {
}
// Formats an argument of a custom type, such as a user-defined class.
+ // DEPRECATED! Formatter template parameter will be removed.
template
static void format_custom(void* arg, parse_context& parse_ctx,
Context& ctx) {
@@ -2261,28 +2307,27 @@ template <> struct is_output_iterator : std::true_type {};
template
struct is_output_iterator<
It, T,
- void_t&>()++ = std::declval())>>
- : std::true_type {};
+ enable_if_t&>()++),
+ T>::value>> : std::true_type {};
#ifndef FMT_USE_LOCALE
# define FMT_USE_LOCALE (FMT_OPTIMIZE_SIZE <= 1)
#endif
// A type-erased reference to an std::locale to avoid a heavy include.
-struct locale_ref {
+class locale_ref {
#if FMT_USE_LOCALE
private:
const void* locale_; // A type-erased pointer to std::locale.
public:
constexpr locale_ref() : locale_(nullptr) {}
-
- template
- locale_ref(const Locale& loc);
+ template locale_ref(const Locale& loc);
inline explicit operator bool() const noexcept { return locale_ != nullptr; }
#endif // FMT_USE_LOCALE
+ public:
template auto get() const -> Locale;
};
@@ -2310,8 +2355,9 @@ template
struct named_arg_store {
// args_[0].named_args points to named_args to avoid bloating format_args.
- arg_t args[1 + NUM_ARGS];
- named_arg_info named_args[NUM_NAMED_ARGS];
+ arg_t args[1u + NUM_ARGS];
+ named_arg_info
+ named_args[static_cast(NUM_NAMED_ARGS)];
template
FMT_CONSTEXPR FMT_ALWAYS_INLINE named_arg_store(T&... values)
@@ -2344,7 +2390,7 @@ struct format_arg_store {
// +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
using type =
conditional_t[max_of(1, NUM_ARGS)],
+ arg_t[max_of(1, NUM_ARGS)],
named_arg_store>;
type args;
};
@@ -2656,6 +2702,7 @@ class context {
FMT_CONSTEXPR auto arg_id(string_view name) const -> int {
return args_.get_id(name);
}
+ auto args() const -> const format_args& { return args_; }
// Returns an iterator to the beginning of the output range.
FMT_CONSTEXPR auto out() const -> iterator { return out_; }
@@ -2701,7 +2748,7 @@ template struct fstring {
template
FMT_CONSTEVAL FMT_ALWAYS_INLINE fstring(const char (&s)[N]) : str(s, N - 1) {
using namespace detail;
- static_assert(count<(std::is_base_of>::value &&
+ static_assert(count<(is_view>::value &&
std::is_reference::value)...>() == 0,
"passing views as lvalues is disallowed");
if (FMT_USE_CONSTEVAL) parse_format_string(s, checker(s, arg_pack()));
@@ -2728,9 +2775,9 @@ template struct fstring {
std::is_same::value)>
FMT_ALWAYS_INLINE fstring(const S&) : str(S()) {
FMT_CONSTEXPR auto sv = string_view(S());
- FMT_CONSTEXPR int ignore =
+ FMT_CONSTEXPR int unused =
(parse_format_string(sv, checker(sv, arg_pack())), 0);
- detail::ignore_unused(ignore);
+ detail::ignore_unused(unused);
}
fstring(runtime_format_string<> fmt) : str(fmt.str) {}
diff --git a/external/fmt/include/fmt/chrono.h b/external/fmt/include/fmt/chrono.h
index abf3671e..6f9a363e 100644
--- a/external/fmt/include/fmt/chrono.h
+++ b/external/fmt/include/fmt/chrono.h
@@ -22,21 +22,6 @@
#include "format.h"
-namespace fmt_detail {
-struct time_zone {
- template
- auto to_sys(T)
- -> std::chrono::time_point {
- return {};
- }
-};
-template inline auto current_zone(T...) -> time_zone* {
- return nullptr;
-}
-
-template inline void _tzset(T...) {}
-} // namespace fmt_detail
-
FMT_BEGIN_NAMESPACE
// Enable safe chrono durations, unless explicitly disabled.
@@ -261,7 +246,7 @@ namespace detail {
using utc_clock = std::chrono::utc_clock;
#else
struct utc_clock {
- void to_sys();
+ template void to_sys(T);
};
#endif
@@ -341,7 +326,7 @@ inline auto get_classic_locale() -> const std::locale& {
}
template struct codecvt_result {
- static constexpr const size_t max_size = 32;
+ static constexpr size_t max_size = 32;
CodeUnit buf[max_size];
CodeUnit* end;
};
@@ -364,7 +349,7 @@ void write_codecvt(codecvt_result& out, string_view in,
template
auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc)
-> OutputIt {
- if (detail::use_utf8 && loc != get_classic_locale()) {
+ if (const_check(detail::use_utf8) && loc != get_classic_locale()) {
// char16_t and char32_t codecvts are broken in MSVC (linkage errors) and
// gcc-4.
#if FMT_MSC_VERSION != 0 || \
@@ -435,14 +420,11 @@ auto write(OutputIt out, const std::tm& time, const std::locale& loc,
return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc);
}
-template
-struct is_same_arithmetic_type
- : public std::integral_constant::value &&
- std::is_integral::value) ||
- (std::is_floating_point::value &&
- std::is_floating_point::value)> {
-};
+template
+using is_similar_arithmetic_type =
+ bool_constant<(std::is_integral::value && std::is_integral::value) ||
+ (std::is_floating_point::value &&
+ std::is_floating_point::value)>;
FMT_NORETURN inline void throw_duration_error() {
FMT_THROW(format_error("cannot format duration"));
@@ -501,9 +483,9 @@ auto duration_cast(std::chrono::duration from) -> To {
#endif
}
-template <
- typename To, typename FromRep, typename FromPeriod,
- FMT_ENABLE_IF(!is_same_arithmetic_type::value)>
+template ::value)>
auto duration_cast(std::chrono::duration from) -> To {
// Mixed integer <-> float cast is not supported by safe_duration_cast.
return std::chrono::duration_cast(from);
@@ -519,12 +501,30 @@ auto to_time_t(sys_time time_point) -> std::time_t {
.count();
}
-// Workaround a bug in libstdc++ which sets __cpp_lib_chrono to 201907 without
-// providing current_zone(): https://github.com/fmtlib/fmt/issues/4160.
-template FMT_CONSTEXPR auto has_current_zone() -> bool {
- using namespace std::chrono;
- using namespace fmt_detail;
- return !std::is_same::value;
+namespace tz {
+
+// DEPRECATED!
+struct time_zone {
+ template
+ auto to_sys(LocalTime) -> sys_time {
+ return {};
+ }
+};
+template auto current_zone(T...) -> time_zone* {
+ return nullptr;
+}
+
+template void _tzset(T...) {}
+} // namespace tz
+
+// DEPRECATED!
+inline void tzset_once() {
+ static bool init = []() {
+ using namespace tz;
+ _tzset();
+ return false;
+ }();
+ ignore_unused(init);
}
} // namespace detail
@@ -535,7 +535,7 @@ FMT_BEGIN_EXPORT
* expressed in local time. Unlike `std::localtime`, this function is
* thread-safe on most platforms.
*/
-inline auto localtime(std::time_t time) -> std::tm {
+FMT_DEPRECATED inline auto localtime(std::time_t time) -> std::tm {
struct dispatcher {
std::time_t time_;
std::tm tm_;
@@ -572,11 +572,11 @@ inline auto localtime(std::time_t time) -> std::tm {
}
#if FMT_USE_LOCAL_TIME
-template ())>
-inline auto localtime(std::chrono::local_time time) -> std::tm {
+template
+FMT_DEPRECATED auto localtime(std::chrono::local_time time)
+ -> std::tm {
using namespace std::chrono;
- using namespace fmt_detail;
+ using namespace detail::tz;
return localtime(detail::to_time_t(current_zone()->to_sys(time)));
}
#endif
@@ -652,7 +652,7 @@ inline void write_digit2_separated(char* buf, unsigned a, unsigned b,
// Add ASCII '0' to each digit byte and insert separators.
digits |= 0x3030003030003030 | (usep << 16) | (usep << 40);
- constexpr const size_t len = 8;
+ constexpr size_t len = 8;
if (const_check(is_big_endian())) {
char tmp[len];
std::memcpy(tmp, &digits, len);
@@ -911,7 +911,14 @@ template struct null_chrono_spec_handler {
FMT_CONSTEXPR void on_tz_name() { unsupported(); }
};
-struct tm_format_checker : null_chrono_spec_handler {
+class tm_format_checker : public null_chrono_spec_handler {
+ private:
+ bool has_timezone_ = false;
+
+ public:
+ constexpr explicit tm_format_checker(bool has_timezone)
+ : has_timezone_(has_timezone) {}
+
FMT_NORETURN inline void unsupported() {
FMT_THROW(format_error("no format"));
}
@@ -949,8 +956,12 @@ struct tm_format_checker : null_chrono_spec_handler {
FMT_CONSTEXPR void on_24_hour_time() {}
FMT_CONSTEXPR void on_iso_time() {}
FMT_CONSTEXPR void on_am_pm() {}
- FMT_CONSTEXPR void on_utc_offset(numeric_system) {}
- FMT_CONSTEXPR void on_tz_name() {}
+ FMT_CONSTEXPR void on_utc_offset(numeric_system) {
+ if (!has_timezone_) FMT_THROW(format_error("no timezone"));
+ }
+ FMT_CONSTEXPR void on_tz_name() {
+ if (!has_timezone_) FMT_THROW(format_error("no timezone"));
+ }
};
inline auto tm_wday_full_name(int wday) -> const char* {
@@ -980,24 +991,27 @@ inline auto tm_mon_short_name(int mon) -> const char* {
}
template
-struct has_member_data_tm_gmtoff : std::false_type {};
+struct has_tm_gmtoff : std::false_type {};
template
-struct has_member_data_tm_gmtoff>
- : std::true_type {};
+struct has_tm_gmtoff> : std::true_type {};
-template
-struct has_member_data_tm_zone : std::false_type {};
+template struct has_tm_zone : std::false_type {};
template
-struct has_member_data_tm_zone>
- : std::true_type {};
+struct has_tm_zone> : std::true_type {};
-inline void tzset_once() {
- static bool init = []() {
- using namespace fmt_detail;
- _tzset();
- return false;
- }();
- ignore_unused(init);
+template ::value)>
+bool set_tm_zone(T& time, char* tz) {
+ time.tm_zone = tz;
+ return true;
+}
+template ::value)>
+bool set_tm_zone(T&, char*) {
+ return false;
+}
+
+inline char* utc() {
+ static char tz[] = "UTC";
+ return tz;
}
// Converts value to Int and checks that it's in the range [0, upper).
@@ -1005,7 +1019,7 @@ template ::value)>
inline auto to_nonnegative_int(T value, Int upper) -> Int {
if (!std::is_unsigned::value &&
(value < 0 || to_unsigned(value) > to_unsigned(upper))) {
- FMT_THROW(fmt::format_error("chrono value is out of range"));
+ FMT_THROW(format_error("chrono value is out of range"));
}
return static_cast(value);
}
@@ -1090,7 +1104,7 @@ void write_fractional_seconds(OutputIt& out, Duration d, int precision = -1) {
// Format subseconds which are given as a floating point type with an
// appropriate number of digits. We cannot pass the Duration here, as we
-// explicitly need to pass the Rep value in the chrono_formatter.
+// explicitly need to pass the Rep value in the duration_formatter.
template
void write_floating_seconds(memory_buffer& buf, Duration duration,
int num_fractional_digits = -1) {
@@ -1124,7 +1138,7 @@ class tm_writer {
static constexpr int days_per_week = 7;
const std::locale& loc_;
- const bool is_classic_;
+ bool is_classic_;
OutputIt out_;
const Duration* subsecs_;
const std::tm& tm_;
@@ -1160,8 +1174,8 @@ class tm_writer {
}
auto tm_hour12() const noexcept -> int {
- const auto h = tm_hour();
- const auto z = h < 12 ? h : h - 12;
+ auto h = tm_hour();
+ auto z = h < 12 ? h : h - 12;
return z == 0 ? 12 : z;
}
@@ -1177,11 +1191,11 @@ class tm_writer {
// Algorithm: https://en.wikipedia.org/wiki/ISO_week_date.
auto iso_year_weeks(long long curr_year) const noexcept -> int {
- const auto prev_year = curr_year - 1;
- const auto curr_p =
+ auto prev_year = curr_year - 1;
+ auto curr_p =
(curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) %
days_per_week;
- const auto prev_p =
+ auto prev_p =
(prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) %
days_per_week;
return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0);
@@ -1191,15 +1205,15 @@ class tm_writer {
days_per_week;
}
auto tm_iso_week_year() const noexcept -> long long {
- const auto year = tm_year();
- const auto w = iso_week_num(tm_yday(), tm_wday());
+ auto year = tm_year();
+ auto w = iso_week_num(tm_yday(), tm_wday());
if (w < 1) return year - 1;
if (w > iso_year_weeks(year)) return year + 1;
return year;
}
auto tm_iso_week_of_year() const noexcept -> int {
- const auto year = tm_year();
- const auto w = iso_week_num(tm_yday(), tm_wday());
+ auto year = tm_year();
+ auto w = iso_week_num(tm_yday(), tm_wday());
if (w < 1) return iso_year_weeks(year - 1);
if (w > iso_year_weeks(year)) return 1;
return w;
@@ -1236,9 +1250,8 @@ class tm_writer {
uint32_or_64_or_128_t n = to_unsigned(year);
const int num_digits = count_digits(n);
if (negative && pad == pad_type::zero) *out_++ = '-';
- if (width > num_digits) {
+ if (width > num_digits)
out_ = detail::write_padding(out_, pad, width - num_digits);
- }
if (negative && pad != pad_type::zero) *out_++ = '-';
out_ = format_decimal(out_, n, num_digits);
}
@@ -1259,45 +1272,22 @@ class tm_writer {
write2(static_cast(offset % 60));
}
- template ::value)>
- void format_utc_offset_impl(const T& tm, numeric_system ns) {
+ template ::value)>
+ void format_utc_offset(const T& tm, numeric_system ns) {
write_utc_offset(tm.tm_gmtoff, ns);
}
- template ::value)>
- void format_utc_offset_impl(const T& tm, numeric_system ns) {
-#if defined(_WIN32) && defined(_UCRT)
- tzset_once();
- long offset = 0;
- _get_timezone(&offset);
- if (tm.tm_isdst) {
- long dstbias = 0;
- _get_dstbias(&dstbias);
- offset += dstbias;
- }
- write_utc_offset(-offset, ns);
-#else
- if (ns == numeric_system::standard) return format_localized('z');
-
- // Extract timezone offset from timezone conversion functions.
- std::tm gtm = tm;
- std::time_t gt = std::mktime(>m);
- std::tm ltm = gmtime(gt);
- std::time_t lt = std::mktime(<m);
- long long offset = gt - lt;
- write_utc_offset(offset, ns);
-#endif
+ template ::value)>
+ void format_utc_offset(const T&, numeric_system ns) {
+ write_utc_offset(0, ns);
}
- template ::value)>
- void format_tz_name_impl(const T& tm) {
- if (is_classic_)
- out_ = write_tm_str(out_, tm.tm_zone, loc_);
- else
- format_localized('Z');
+ template ::value)>
+ void format_tz_name(const T& tm) {
+ out_ = write_tm_str(out_, tm.tm_zone, loc_);
}
- template ::value)>
- void format_tz_name_impl(const T&) {
- format_localized('Z');
+ template ::value)>
+ void format_tz_name(const T&) {
+ out_ = std::copy_n(utc(), 3, out_);
}
void format_localized(char format, char modifier = 0) {
@@ -1408,8 +1398,8 @@ class tm_writer {
out_ = copy(std::begin(buf) + offset, std::end(buf), out_);
}
- void on_utc_offset(numeric_system ns) { format_utc_offset_impl(tm_, ns); }
- void on_tz_name() { format_tz_name_impl(tm_); }
+ void on_utc_offset(numeric_system ns) { format_utc_offset(tm_, ns); }
+ void on_tz_name() { format_tz_name(tm_); }
void on_year(numeric_system ns, pad_type pad) {
if (is_classic_ || ns == numeric_system::standard)
@@ -1483,11 +1473,10 @@ class tm_writer {
void on_day_of_year(pad_type pad) {
auto yday = tm_yday() + 1;
auto digit1 = yday / 100;
- if (digit1 != 0) {
+ if (digit1 != 0)
write1(digit1);
- } else {
+ else
out_ = detail::write_padding(out_, pad);
- }
write2(yday % 100, pad);
}
@@ -1624,18 +1613,16 @@ template ::value)>
inline auto get_milliseconds(std::chrono::duration d)
-> std::chrono::duration {
- // this may overflow and/or the result may not fit in the
- // target type.
+ // This may overflow and/or the result may not fit in the target type.
#if FMT_SAFE_DURATION_CAST
- using CommonSecondsType =
+ using common_seconds_type =
typename std::common_type::type;
- const auto d_as_common = detail::duration_cast(d);
- const auto d_as_whole_seconds =
+ auto d_as_common = detail::duration_cast(d);
+ auto d_as_whole_seconds =
detail::duration_cast(d_as_common);
- // this conversion should be nonproblematic
- const auto diff = d_as_common - d_as_whole_seconds;
- const auto ms =
- detail::duration_cast>(diff);
+ // This conversion should be nonproblematic.
+ auto diff = d_as_common - d_as_whole_seconds;
+ auto ms = detail::duration_cast>(diff);
return ms;
#else
auto s = detail::duration_cast(d);
@@ -1707,32 +1694,28 @@ class get_locale {
}
};
-template
-struct chrono_formatter {
- FormatContext& context;
- OutputIt out;
- int precision;
- bool localized = false;
+template
+struct duration_formatter {
+ using iterator = basic_appender;
+ iterator out;
// rep is unsigned to avoid overflow.
using rep =
conditional_t::value && sizeof(Rep) < sizeof(int),
unsigned, typename make_unsigned_or_unchanged::type>;
rep val;
+ int precision;
+ locale_ref locale;
+ bool localized = false;
using seconds = std::chrono::duration;
seconds s;
using milliseconds = std::chrono::duration;
bool negative;
- using char_type = typename FormatContext::char_type;
- using tm_writer_type = tm_writer;
+ using tm_writer_type = tm_writer;
- chrono_formatter(FormatContext& ctx, OutputIt o,
- std::chrono::duration d)
- : context(ctx),
- out(o),
- val(static_cast(d.count())),
- negative(false) {
+ duration_formatter(iterator o, std::chrono::duration d,
+ locale_ref loc)
+ : out(o), val(static_cast(d.count())), locale(loc), negative(false) {
if (d.count() < 0) {
val = 0 - val;
negative = true;
@@ -1746,19 +1729,16 @@ struct chrono_formatter {
// returns true if nan or inf, writes to out.
auto handle_nan_inf() -> bool {
- if (isfinite(val)) {
- return false;
- }
+ if (isfinite(val)) return false;
if (isnan(val)) {
write_nan();
return true;
}
// must be +-inf
- if (val > 0) {
- write_pinf();
- } else {
- write_ninf();
- }
+ if (val > 0)
+ std::copy_n("inf", 3, out);
+ else
+ std::copy_n("-inf", 4, out);
return true;
}
@@ -1786,10 +1766,9 @@ struct chrono_formatter {
}
void write_sign() {
- if (negative) {
- *out++ = '-';
- negative = false;
- }
+ if (!negative) return;
+ *out++ = '-';
+ negative = false;
}
void write(Rep value, int width, pad_type pad = pad_type::zero) {
@@ -1801,24 +1780,22 @@ struct chrono_formatter {
if (width > num_digits) {
out = detail::write_padding(out, pad, width - num_digits);
}
- out = format_decimal(out, n, num_digits);
+ out = format_decimal(out, n, num_digits);
}
void write_nan() { std::copy_n("nan", 3, out); }
- void write_pinf() { std::copy_n("inf", 3, out); }
- void write_ninf() { std::copy_n("-inf", 4, out); }
template
void format_tm(const tm& time, Callback cb, Args... args) {
if (isnan(val)) return write_nan();
- get_locale loc(localized, context.locale());
+ get_locale loc(localized, locale);
auto w = tm_writer_type(loc, out, time);
(w.*cb)(args...);
out = w.out();
}
- void on_text(const char_type* begin, const char_type* end) {
- copy(begin, end, out);
+ void on_text(const Char* begin, const Char* end) {
+ copy(begin, end, out);
}
// These are not implemented because durations don't have date information.
@@ -1888,13 +1865,12 @@ struct chrono_formatter {
write_floating_seconds(buf, std::chrono::duration(val),
precision);
if (negative) *out++ = '-';
- if (buf.size() < 2 || buf[1] == '.') {
+ if (buf.size() < 2 || buf[1] == '.')
out = detail::write_padding(out, pad);
- }
- out = copy(buf.begin(), buf.end(), out);
+ out = copy(buf.begin(), buf.end(), out);
} else {
write(second(), 2, pad);
- write_fractional_seconds(
+ write_fractional_seconds(
out, std::chrono::duration(val), precision);
}
return;
@@ -1936,12 +1912,10 @@ struct chrono_formatter {
void on_duration_value() {
if (handle_nan_inf()) return;
write_sign();
- out = format_duration_value(out, val, precision);
+ out = format_duration_value(out, val, precision);
}
- void on_duration_unit() {
- out = format_duration_unit(out);
- }
+ void on_duration_unit() { out = format_duration_unit(out); }
};
} // namespace detail
@@ -2011,12 +1985,11 @@ class year_month_day {
constexpr auto month() const noexcept -> fmt::month { return month_; }
constexpr auto day() const noexcept -> fmt::day { return day_; }
};
-#endif
+#endif // __cpp_lib_chrono >= 201907
template
struct formatter : private formatter {
private:
- bool localized_ = false;
bool use_tm_formatter_ = false;
public:
@@ -2024,8 +1997,7 @@ struct formatter : private formatter {
auto it = ctx.begin(), end = ctx.end();
if (it != end && *it == 'L') {
++it;
- localized_ = true;
- return it;
+ this->set_localized();
}
use_tm_formatter_ = it != end && *it != '}';
return use_tm_formatter_ ? formatter::parse(ctx) : it;
@@ -2036,7 +2008,7 @@ struct formatter : private formatter {
auto time = std::tm();
time.tm_wday = static_cast(wd.c_encoding());
if (use_tm_formatter_) return formatter::format(time, ctx);
- detail::get_locale loc(localized_, ctx.locale());
+ detail::get_locale loc(this->localized(), ctx.locale());
auto w = detail::tm_writer(loc, ctx.out(), time);
w.on_abbr_weekday();
return w.out();
@@ -2070,7 +2042,6 @@ struct formatter : private formatter {
template
struct formatter : private formatter {
private:
- bool localized_ = false;
bool use_tm_formatter_ = false;
public:
@@ -2078,8 +2049,7 @@ struct formatter : private formatter {
auto it = ctx.begin(), end = ctx.end();
if (it != end && *it == 'L') {
++it;
- localized_ = true;
- return it;
+ this->set_localized();
}
use_tm_formatter_ = it != end && *it != '}';
return use_tm_formatter_ ? formatter::parse(ctx) : it;
@@ -2090,7 +2060,7 @@ struct formatter : private formatter {
auto time = std::tm();
time.tm_mon = static_cast(static_cast(m)) - 1;
if (use_tm_formatter_) return formatter::format(time, ctx);
- detail::get_locale loc(localized_, ctx.locale());
+ detail::get_locale loc(this->localized(), ctx.locale());
auto w = detail::tm_writer(loc, ctx.out(), time);
w.on_abbr_month();
return w.out();
@@ -2154,7 +2124,6 @@ struct formatter, Char> {
format_specs specs_;
detail::arg_ref width_ref_;
detail::arg_ref precision_ref_;
- bool localized_ = false;
basic_string_view fmt_;
public:
@@ -2177,7 +2146,7 @@ struct formatter, Char> {
it = detail::parse_precision(it, end, specs_, precision_ref_, ctx);
}
if (it != end && *it == 'L') {
- localized_ = true;
+ specs_.set_localized();
++it;
}
end = detail::parse_chrono_format(it, end, checker);
@@ -2204,11 +2173,10 @@ struct formatter, Char> {
out = detail::format_duration_value(out, d.count(), precision);
detail::format_duration_unit