mirror of
https://github.com/pineappleEA/pineapple-src.git
synced 2024-11-25 07:28:25 -05:00
early-access version 2875
This commit is contained in:
parent
8ac1d0357b
commit
b65fa338c9
@ -38,9 +38,13 @@ option(YUZU_USE_BUNDLED_OPUS "Compile bundled opus" ON)
|
|||||||
|
|
||||||
option(YUZU_TESTS "Compile tests" ON)
|
option(YUZU_TESTS "Compile tests" ON)
|
||||||
|
|
||||||
option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" OFF)
|
option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}")
|
||||||
|
|
||||||
if (YUZU_USE_BUNDLED_VCPKG)
|
if (YUZU_USE_BUNDLED_VCPKG)
|
||||||
|
if (YUZU_TESTS)
|
||||||
|
list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests")
|
||||||
|
endif()
|
||||||
|
|
||||||
include(${CMAKE_SOURCE_DIR}/externals/vcpkg/scripts/buildsystems/vcpkg.cmake)
|
include(${CMAKE_SOURCE_DIR}/externals/vcpkg/scripts/buildsystems/vcpkg.cmake)
|
||||||
elseif(NOT "$ENV{VCPKG_TOOLCHAIN_FILE}" STREQUAL "")
|
elseif(NOT "$ENV{VCPKG_TOOLCHAIN_FILE}" STREQUAL "")
|
||||||
# Disable manifest mode (use vcpkg classic mode) when using a custom vcpkg installation
|
# Disable manifest mode (use vcpkg classic mode) when using a custom vcpkg installation
|
||||||
@ -165,7 +169,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
|||||||
# =======================================================================
|
# =======================================================================
|
||||||
|
|
||||||
find_package(fmt 8.0.1 REQUIRED CONFIG)
|
find_package(fmt 8.0.1 REQUIRED CONFIG)
|
||||||
find_package(lz4 1.8 REQUIRED)
|
|
||||||
find_package(nlohmann_json 3.8 REQUIRED CONFIG)
|
find_package(nlohmann_json 3.8 REQUIRED CONFIG)
|
||||||
find_package(ZLIB 1.2 REQUIRED)
|
find_package(ZLIB 1.2 REQUIRED)
|
||||||
|
|
||||||
@ -175,6 +178,12 @@ if (NOT zstd_FOUND)
|
|||||||
find_package(zstd 1.5 REQUIRED)
|
find_package(zstd 1.5 REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# lz4 1.8 is required, but vcpkg's lz4-config.cmake does not have version info
|
||||||
|
find_package(lz4 CONFIG)
|
||||||
|
if (NOT lz4_FOUND)
|
||||||
|
find_package(lz4 1.8 REQUIRED)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (YUZU_TESTS)
|
if (YUZU_TESTS)
|
||||||
find_package(Catch2 2.13.7 REQUIRED CONFIG)
|
find_package(Catch2 2.13.7 REQUIRED CONFIG)
|
||||||
endif()
|
endif()
|
||||||
@ -360,16 +369,10 @@ if (ENABLE_SDL2)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# TODO(lat9nq): Determine what if any of this we still need
|
# Reexport some targets that are named differently when using the upstream CmakeConfig
|
||||||
#
|
|
||||||
# Reexport some targets that are named differently when using the upstream CmakeConfig vs the generated Conan config
|
|
||||||
# In order to ALIAS targets to a new name, they first need to be IMPORTED_GLOBAL
|
# In order to ALIAS targets to a new name, they first need to be IMPORTED_GLOBAL
|
||||||
# Dynarmic checks for target `boost` and so we want to make sure it can find it through our system instead of using their external
|
# Dynarmic checks for target `boost` and so we want to make sure it can find it through our system instead of using their external
|
||||||
if (TARGET Boost::Boost)
|
if (TARGET Boost::boost)
|
||||||
set_target_properties(Boost::Boost PROPERTIES IMPORTED_GLOBAL TRUE)
|
|
||||||
add_library(Boost::boost ALIAS Boost::Boost)
|
|
||||||
add_library(boost ALIAS Boost::Boost)
|
|
||||||
elseif (TARGET Boost::boost)
|
|
||||||
set_target_properties(Boost::boost PROPERTIES IMPORTED_GLOBAL TRUE)
|
set_target_properties(Boost::boost PROPERTIES IMPORTED_GLOBAL TRUE)
|
||||||
add_library(boost ALIAS Boost::boost)
|
add_library(boost ALIAS Boost::boost)
|
||||||
endif()
|
endif()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 2874.
|
This is the source code for early-access 2875.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
102
externals/dynarmic/.github/workflows/x86-64.yml
vendored
Executable file
102
externals/dynarmic/.github/workflows/x86-64.yml
vendored
Executable file
@ -0,0 +1,102 @@
|
|||||||
|
name: x86-64
|
||||||
|
|
||||||
|
on: [ push, pull_request ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
BUILD_TYPE: Release
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ windows-latest, ubuntu-latest, macos-latest ]
|
||||||
|
cpu_detection: [ 0, 1 ]
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Install build dependencies
|
||||||
|
if: ${{matrix.os == 'ubuntu-latest'}}
|
||||||
|
run: sudo apt-get install llvm ninja-build
|
||||||
|
|
||||||
|
- name: Install build dependencies
|
||||||
|
if: ${{matrix.os == 'macos-latest'}}
|
||||||
|
run: |
|
||||||
|
brew install llvm ninja
|
||||||
|
echo "/usr/local/opt/llvm/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
|
- name: Checkout dynarmic repo
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Checkout ext-boost repo
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: MerryMage/ext-boost
|
||||||
|
path: externals/ext-boost
|
||||||
|
|
||||||
|
- name: Checkout unicorn repo
|
||||||
|
if: ${{matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest'}}
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: MerryMage/unicorn
|
||||||
|
path: externals/unicorn
|
||||||
|
|
||||||
|
- name: Build unicorn
|
||||||
|
if: ${{matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest'}}
|
||||||
|
working-directory: externals/unicorn
|
||||||
|
run: UNICORN_ARCHS=aarch64,arm ./make.sh
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
if: ${{matrix.os == 'ubuntu-latest'}}
|
||||||
|
env:
|
||||||
|
CC: gcc-10
|
||||||
|
CXX: g++-10
|
||||||
|
CXXFLAGS: -Wp,-D_GLIBCXX_ASSERTIONS
|
||||||
|
run: >
|
||||||
|
cmake
|
||||||
|
-B ${{github.workspace}}/build
|
||||||
|
-DBoost_INCLUDE_DIRS=${{github.workspace}}/externals/ext-boost
|
||||||
|
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||||
|
-DDYNARMIC_ENABLE_CPU_FEATURE_DETECTION=${{matrix.cpu_detection}}
|
||||||
|
-DDYNARMIC_TESTS_USE_UNICORN=1
|
||||||
|
-DDYNARMIC_USE_LLVM=1
|
||||||
|
-DLIBUNICORN_INCLUDE_DIR=${{github.workspace}}/externals/unicorn/include
|
||||||
|
-DLIBUNICORN_LIBRARY=${{github.workspace}}/externals/unicorn/libunicorn.a
|
||||||
|
-G Ninja
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
if: ${{matrix.os == 'macos-latest'}}
|
||||||
|
run: >
|
||||||
|
cmake
|
||||||
|
-B ${{github.workspace}}/build
|
||||||
|
-DBoost_INCLUDE_DIRS=${{github.workspace}}/externals/ext-boost
|
||||||
|
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||||
|
-DDYNARMIC_ENABLE_CPU_FEATURE_DETECTION=${{matrix.cpu_detection}}
|
||||||
|
-DDYNARMIC_TESTS_USE_UNICORN=1
|
||||||
|
-DDYNARMIC_USE_LLVM=1
|
||||||
|
-DLIBUNICORN_INCLUDE_DIR=${{github.workspace}}/externals/unicorn/include
|
||||||
|
-DLIBUNICORN_LIBRARY=${{github.workspace}}/externals/unicorn/libunicorn.a
|
||||||
|
-G Ninja
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
if: ${{matrix.os == 'windows-latest'}}
|
||||||
|
run: >
|
||||||
|
cmake
|
||||||
|
-B ${{github.workspace}}/build
|
||||||
|
-DBoost_INCLUDE_DIRS=${{github.workspace}}/externals/ext-boost
|
||||||
|
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||||
|
-DDYNARMIC_ENABLE_CPU_FEATURE_DETECTION=${{matrix.cpu_detection}}
|
||||||
|
-G "Visual Studio 17 2022"
|
||||||
|
-A x64
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
working-directory: ${{github.workspace}}/build
|
||||||
|
run: cmake --build . --config Release
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
env:
|
||||||
|
DYLD_FALLBACK_LIBRARY_PATH: ${{github.workspace}}/externals/unicorn
|
||||||
|
working-directory: ${{github.workspace}}/build
|
||||||
|
run: ctest --extra-verbose -C ${{env.BUILD_TYPE}}
|
2
externals/dynarmic/CMakeLists.txt
vendored
2
externals/dynarmic/CMakeLists.txt
vendored
@ -1,5 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.8)
|
cmake_minimum_required(VERSION 3.8)
|
||||||
project(dynarmic LANGUAGES C CXX ASM VERSION 6.2.1)
|
project(dynarmic LANGUAGES C CXX ASM VERSION 6.2.3)
|
||||||
|
|
||||||
# Determine if we're built as a subproject (using add_subdirectory)
|
# Determine if we're built as a subproject (using add_subdirectory)
|
||||||
# or if this is the master project.
|
# or if this is the master project.
|
||||||
|
6
externals/dynarmic/externals/fmt/.github/issue_template.md
vendored
Executable file
6
externals/dynarmic/externals/fmt/.github/issue_template.md
vendored
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
<!--
|
||||||
|
Please make sure that the problem reproduces on the current master before
|
||||||
|
submitting an issue.
|
||||||
|
If possible please provide a repro on Compiler Explorer:
|
||||||
|
https://godbolt.org/z/fxccbh53W.
|
||||||
|
-->
|
@ -2,6 +2,9 @@ name: doc
|
|||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
# Use Ubuntu 20.04 because doxygen 1.8.13 from Ubuntu 18.04 is broken.
|
# Use Ubuntu 20.04 because doxygen 1.8.13 from Ubuntu 18.04 is broken.
|
||||||
|
@ -2,6 +2,9 @@ name: linux
|
|||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
@ -20,6 +23,11 @@ jobs:
|
|||||||
std: 14
|
std: 14
|
||||||
install: sudo apt install g++-8
|
install: sudo apt install g++-8
|
||||||
os: ubuntu-18.04
|
os: ubuntu-18.04
|
||||||
|
- cxx: g++-8
|
||||||
|
build_type: Debug
|
||||||
|
std: 17
|
||||||
|
install: sudo apt install g++-8
|
||||||
|
os: ubuntu-18.04
|
||||||
- cxx: g++-10
|
- cxx: g++-10
|
||||||
build_type: Debug
|
build_type: Debug
|
||||||
std: 17
|
std: 17
|
||||||
@ -29,6 +37,12 @@ jobs:
|
|||||||
std: 20
|
std: 20
|
||||||
os: ubuntu-20.04
|
os: ubuntu-20.04
|
||||||
install: sudo apt install g++-11
|
install: sudo apt install g++-11
|
||||||
|
- cxx: clang++-8
|
||||||
|
build_type: Debug
|
||||||
|
std: 17
|
||||||
|
cxxflags: -stdlib=libc++
|
||||||
|
os: ubuntu-18.04
|
||||||
|
install: sudo apt install clang-8 libc++-8-dev libc++abi-8-dev
|
||||||
- cxx: clang++-9
|
- cxx: clang++-9
|
||||||
build_type: Debug
|
build_type: Debug
|
||||||
fuzz: -DFMT_FUZZ=ON -DFMT_FUZZ_LINKMAIN=ON
|
fuzz: -DFMT_FUZZ=ON -DFMT_FUZZ_LINKMAIN=ON
|
||||||
@ -52,6 +66,7 @@ jobs:
|
|||||||
- name: Create Build Environment
|
- name: Create Build Environment
|
||||||
run: |
|
run: |
|
||||||
${{matrix.install}}
|
${{matrix.install}}
|
||||||
|
sudo apt update
|
||||||
sudo apt install locales-all
|
sudo apt install locales-all
|
||||||
cmake -E make_directory ${{runner.workspace}}/build
|
cmake -E make_directory ${{runner.workspace}}/build
|
||||||
|
|
||||||
|
@ -2,6 +2,9 @@ name: macos
|
|||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: macos-10.15
|
runs-on: macos-10.15
|
||||||
|
@ -2,31 +2,34 @@ name: windows
|
|||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
# windows-2016 and windows-2019 have MSVC 2017 and 2019 installed
|
# windows-2019 has MSVC 2019 installed;
|
||||||
# respectively: https://github.com/actions/virtual-environments.
|
# windows-2022 has MSVC 2022 installed:
|
||||||
os: [windows-2016, windows-2019]
|
# https://github.com/actions/virtual-environments.
|
||||||
|
os: [windows-2019]
|
||||||
platform: [Win32, x64]
|
platform: [Win32, x64]
|
||||||
build_type: [Debug, Release]
|
build_type: [Debug, Release]
|
||||||
standard: [11, 17, 20]
|
standard: [11, 17, 20]
|
||||||
include:
|
include:
|
||||||
- os: windows-2016
|
- os: windows-2019
|
||||||
platform: Win32
|
platform: Win32
|
||||||
build_type: Debug
|
build_type: Debug
|
||||||
shared: -DBUILD_SHARED_LIBS=ON
|
shared: -DBUILD_SHARED_LIBS=ON
|
||||||
exclude:
|
- os: windows-2022
|
||||||
- os: windows-2016
|
platform: x64
|
||||||
platform: Win32
|
build_type: Debug
|
||||||
- os: windows-2016
|
|
||||||
standard: 17
|
|
||||||
- os: windows-2016
|
|
||||||
standard: 20
|
standard: 20
|
||||||
|
exclude:
|
||||||
- os: windows-2019
|
- os: windows-2019
|
||||||
standard: 11
|
standard: 11
|
||||||
|
platform: Win32
|
||||||
- os: windows-2019
|
- os: windows-2019
|
||||||
standard: 20
|
standard: 20
|
||||||
platform: Win32
|
platform: Win32
|
||||||
|
30
externals/dynarmic/externals/fmt/CMakeLists.txt
vendored
30
externals/dynarmic/externals/fmt/CMakeLists.txt
vendored
@ -125,7 +125,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
|
|||||||
"${CMAKE_CURRENT_SOURCE_DIR}/support/cmake")
|
"${CMAKE_CURRENT_SOURCE_DIR}/support/cmake")
|
||||||
|
|
||||||
include(cxx14)
|
include(cxx14)
|
||||||
include(CheckCXXCompilerFlag)
|
|
||||||
include(JoinPaths)
|
include(JoinPaths)
|
||||||
|
|
||||||
list(FIND CMAKE_CXX_COMPILE_FEATURES "cxx_variadic_templates" index)
|
list(FIND CMAKE_CXX_COMPILE_FEATURES "cxx_variadic_templates" index)
|
||||||
@ -209,18 +208,6 @@ if (FMT_MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
|
|||||||
${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*")
|
${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(strtod_l_headers stdlib.h)
|
|
||||||
if (APPLE)
|
|
||||||
set(strtod_l_headers ${strtod_l_headers} xlocale.h)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
include(CheckSymbolExists)
|
|
||||||
if (WIN32)
|
|
||||||
check_symbol_exists(_strtod_l "${strtod_l_headers}" HAVE_STRTOD_L)
|
|
||||||
else ()
|
|
||||||
check_symbol_exists(strtod_l "${strtod_l_headers}" HAVE_STRTOD_L)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
function(add_headers VAR)
|
function(add_headers VAR)
|
||||||
set(headers ${${VAR}})
|
set(headers ${${VAR}})
|
||||||
foreach (header ${ARGN})
|
foreach (header ${ARGN})
|
||||||
@ -231,7 +218,7 @@ endfunction()
|
|||||||
|
|
||||||
# Define the fmt library, its includes and the needed defines.
|
# Define the fmt library, its includes and the needed defines.
|
||||||
add_headers(FMT_HEADERS args.h chrono.h color.h compile.h core.h format.h
|
add_headers(FMT_HEADERS args.h chrono.h color.h compile.h core.h format.h
|
||||||
format-inl.h locale.h os.h ostream.h printf.h ranges.h
|
format-inl.h os.h ostream.h printf.h ranges.h std.h
|
||||||
xchar.h)
|
xchar.h)
|
||||||
if (FMT_MODULE)
|
if (FMT_MODULE)
|
||||||
set(FMT_SOURCES src/fmt.cc)
|
set(FMT_SOURCES src/fmt.cc)
|
||||||
@ -244,17 +231,6 @@ endif ()
|
|||||||
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst)
|
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst)
|
||||||
add_library(fmt::fmt ALIAS fmt)
|
add_library(fmt::fmt ALIAS fmt)
|
||||||
|
|
||||||
if (HAVE_STRTOD_L)
|
|
||||||
target_compile_definitions(fmt PUBLIC FMT_LOCALE)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (MINGW)
|
|
||||||
check_cxx_compiler_flag("-Wa,-mbig-obj" FMT_HAS_MBIG_OBJ)
|
|
||||||
if (${FMT_HAS_MBIG_OBJ})
|
|
||||||
target_compile_options(fmt PUBLIC "-Wa,-mbig-obj")
|
|
||||||
endif()
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (FMT_WERROR)
|
if (FMT_WERROR)
|
||||||
target_compile_options(fmt PRIVATE ${WERROR_FLAG})
|
target_compile_options(fmt PRIVATE ${WERROR_FLAG})
|
||||||
endif ()
|
endif ()
|
||||||
@ -275,6 +251,7 @@ set(FMT_DEBUG_POSTFIX d CACHE STRING "Debug library postfix.")
|
|||||||
|
|
||||||
set_target_properties(fmt PROPERTIES
|
set_target_properties(fmt PROPERTIES
|
||||||
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
|
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
|
||||||
|
PUBLIC_HEADER "${FMT_HEADERS}"
|
||||||
DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}")
|
DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}")
|
||||||
|
|
||||||
# Set FMT_LIB_NAME for pkg-config fmt.pc. We cannot use the OUTPUT_NAME target
|
# Set FMT_LIB_NAME for pkg-config fmt.pc. We cannot use the OUTPUT_NAME target
|
||||||
@ -352,6 +329,8 @@ if (FMT_INSTALL)
|
|||||||
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
|
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
|
||||||
LIBRARY DESTINATION ${FMT_LIB_DIR}
|
LIBRARY DESTINATION ${FMT_LIB_DIR}
|
||||||
ARCHIVE DESTINATION ${FMT_LIB_DIR}
|
ARCHIVE DESTINATION ${FMT_LIB_DIR}
|
||||||
|
PUBLIC_HEADER DESTINATION "${FMT_INC_DIR}/fmt"
|
||||||
|
FRAMEWORK DESTINATION "."
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
|
|
||||||
# Use a namespace because CMake provides better diagnostics for namespaced
|
# Use a namespace because CMake provides better diagnostics for namespaced
|
||||||
@ -368,7 +347,6 @@ if (FMT_INSTALL)
|
|||||||
|
|
||||||
install(FILES $<TARGET_PDB_FILE:${INSTALL_TARGETS}>
|
install(FILES $<TARGET_PDB_FILE:${INSTALL_TARGETS}>
|
||||||
DESTINATION ${FMT_LIB_DIR} OPTIONAL)
|
DESTINATION ${FMT_LIB_DIR} OPTIONAL)
|
||||||
install(FILES ${FMT_HEADERS} DESTINATION "${FMT_INC_DIR}/fmt")
|
|
||||||
install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}")
|
install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
395
externals/dynarmic/externals/fmt/ChangeLog.rst
vendored
395
externals/dynarmic/externals/fmt/ChangeLog.rst
vendored
@ -1,3 +1,389 @@
|
|||||||
|
9.0.0 - 2022-07-04
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Switched to the internal floating point formatter for all decimal presentation
|
||||||
|
formats. In particular this results in consistent rounding on all platforms
|
||||||
|
and removing the ``s[n]printf`` fallback for decimal FP formatting.
|
||||||
|
|
||||||
|
* Compile-time floating point formatting no longer requires the header-only
|
||||||
|
mode. For example (`godbolt <https://godbolt.org/z/G37PTeG3b>`__):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <fmt/compile.h>
|
||||||
|
|
||||||
|
consteval auto compile_time_dtoa(double value) -> std::array<char, 10> {
|
||||||
|
auto result = std::array<char, 10>();
|
||||||
|
fmt::format_to(result.data(), FMT_COMPILE("{}"), value);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto answer = compile_time_itoa(0.42);
|
||||||
|
|
||||||
|
works with the default settings.
|
||||||
|
|
||||||
|
* Improved the implementation of
|
||||||
|
`Dragonbox <https://github.com/jk-jeon/dragonbox>`_, the algorithm used for
|
||||||
|
the default floating-point formatting
|
||||||
|
(`#2713 <https://github.com/fmtlib/fmt/pull/2713>`_,
|
||||||
|
`#2750 <https://github.com/fmtlib/fmt/pull/2750>`_).
|
||||||
|
Thanks `@jk-jeon (Junekey Jeon) <https://github.com/jk-jeon>`_.
|
||||||
|
|
||||||
|
* Made ``fmt::to_string`` work with ``__float128``. This uses the internal
|
||||||
|
FP formatter and works even on system without ``__float128`` support in
|
||||||
|
``[s]printf``.
|
||||||
|
|
||||||
|
* Disabled automatic ``std::ostream`` insertion operator (``operator<<``)
|
||||||
|
discovery when ``fmt/ostream.h`` is included to prevent ODR violations.
|
||||||
|
You can get the old behavior by defining ``FMT_DEPRECATED_OSTREAM`` but this
|
||||||
|
will be removed in the next major release. Use ``fmt::streamed`` or
|
||||||
|
``fmt::ostream_formatter`` to enable formatting via ``std::ostream`` instead.
|
||||||
|
|
||||||
|
* Added ``fmt::ostream_formatter`` that can be used to write ``formatter``
|
||||||
|
specializations that perform formatting via ``std::ostream``.
|
||||||
|
For example (`godbolt <https://godbolt.org/z/5sEc5qMsf>`__):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <fmt/ostream.h>
|
||||||
|
|
||||||
|
struct date {
|
||||||
|
int year, month, day;
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, const date& d) {
|
||||||
|
return os << d.year << '-' << d.month << '-' << d.day;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct fmt::formatter<date> : ostream_formatter {};
|
||||||
|
|
||||||
|
std::string s = fmt::format("The date is {}", date{2012, 12, 9});
|
||||||
|
// s == "The date is 2012-12-9"
|
||||||
|
|
||||||
|
* Added the ``fmt::streamed`` function that takes an object and formats it
|
||||||
|
via ``std::ostream``.
|
||||||
|
For example (`godbolt <https://godbolt.org/z/5G3346G1f>`__):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <fmt/ostream.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
fmt::print("Current thread id: {}\n",
|
||||||
|
fmt::streamed(std::this_thread::get_id()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Note that ``fmt/std.h`` provides a ``formatter`` specialization for
|
||||||
|
``std::thread::id`` so you don't need to format it via ``std::ostream``.
|
||||||
|
|
||||||
|
* Deprecated implicit conversions of unscoped enums to integers for consistency
|
||||||
|
with scoped enums.
|
||||||
|
|
||||||
|
* Added an argument-dependent lookup based ``format_as`` extension API to
|
||||||
|
simplify formatting of enums.
|
||||||
|
|
||||||
|
* Added experimental ``std::variant`` formatting support
|
||||||
|
(`#2941 <https://github.com/fmtlib/fmt/pull/2941>`_).
|
||||||
|
For example (`godbolt <https://godbolt.org/z/KG9z6cq68>`__):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
#include <fmt/std.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto v = std::variant<int, std::string>(42);
|
||||||
|
fmt::print("{}\n", v);
|
||||||
|
}
|
||||||
|
|
||||||
|
prints::
|
||||||
|
|
||||||
|
variant(42)
|
||||||
|
|
||||||
|
Thanks `@jehelset <https://github.com/jehelset>`_.
|
||||||
|
|
||||||
|
* Added experimental ``std::filesystem::path`` formatting support
|
||||||
|
(`#2865 <https://github.com/fmtlib/fmt/issues/2865>`_,
|
||||||
|
`#2902 <https://github.com/fmtlib/fmt/pull/2902>`_,
|
||||||
|
`#2917 <https://github.com/fmtlib/fmt/issues/2917>`_,
|
||||||
|
`#2918 <https://github.com/fmtlib/fmt/pull/2918>`_).
|
||||||
|
For example (`godbolt <https://godbolt.org/z/o44dMexEb>`__):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fmt/std.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
fmt::print("There is no place like {}.", std::filesystem::path("/home"));
|
||||||
|
}
|
||||||
|
|
||||||
|
prints::
|
||||||
|
|
||||||
|
There is no place like "/home".
|
||||||
|
|
||||||
|
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
|
||||||
|
|
||||||
|
* Added a ``std::thread::id`` formatter to ``fmt/std.h``.
|
||||||
|
For example (`godbolt <https://godbolt.org/z/j1azbYf3E>`__):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <fmt/std.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
fmt::print("Current thread id: {}\n", std::this_thread::get_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
* Added ``fmt::styled`` that applies a text style to an individual argument
|
||||||
|
(`#2793 <https://github.com/fmtlib/fmt/pull/2793>`_).
|
||||||
|
For example (`godbolt <https://godbolt.org/z/vWGW7v5M6>`__):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <fmt/chrono.h>
|
||||||
|
#include <fmt/color.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
fmt::print(
|
||||||
|
"[{}] {}: {}\n",
|
||||||
|
fmt::styled(now, fmt::emphasis::bold),
|
||||||
|
fmt::styled("error", fg(fmt::color::red)),
|
||||||
|
"something went wrong");
|
||||||
|
}
|
||||||
|
|
||||||
|
prints
|
||||||
|
|
||||||
|
.. image:: https://user-images.githubusercontent.com/576385/
|
||||||
|
175071215-12809244-dab0-4005-96d8-7cd911c964d5.png
|
||||||
|
|
||||||
|
Thanks `@rbrugo (Riccardo Brugo) <https://github.com/rbrugo>`_.
|
||||||
|
|
||||||
|
* Made ``fmt::print`` overload for text styles correctly handle UTF-8
|
||||||
|
(`#2681 <https://github.com/fmtlib/fmt/issues/2681>`_,
|
||||||
|
`#2701 <https://github.com/fmtlib/fmt/pull/2701>`_).
|
||||||
|
Thanks `@AlexGuteniev (Alex Guteniev) <https://github.com/AlexGuteniev>`_.
|
||||||
|
|
||||||
|
* Fixed Unicode handling when writing to an ostream.
|
||||||
|
|
||||||
|
* Added support for nested specifiers to range formatting
|
||||||
|
(`#2673 <https://github.com/fmtlib/fmt/pull/2673>`_).
|
||||||
|
For example (`godbolt <https://godbolt.org/z/xd3Gj38cf>`__):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <fmt/ranges.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
fmt::print("{::#x}\n", std::vector{10, 20, 30});
|
||||||
|
}
|
||||||
|
|
||||||
|
prints ``[0xa, 0x14, 0x1e]``.
|
||||||
|
|
||||||
|
Thanks `@BRevzin (Barry Revzin) <https://github.com/BRevzin>`_.
|
||||||
|
|
||||||
|
* Implemented escaping of wide strings in ranges
|
||||||
|
(`#2904 <https://github.com/fmtlib/fmt/pull/2904>`_).
|
||||||
|
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
|
||||||
|
|
||||||
|
* Added support for ranges with ``begin`` / ``end`` found via the
|
||||||
|
argument-dependent lookup
|
||||||
|
(`#2807 <https://github.com/fmtlib/fmt/pull/2807>`_).
|
||||||
|
Thanks `@rbrugo (Riccardo Brugo) <https://github.com/rbrugo>`_.
|
||||||
|
|
||||||
|
* Fixed formatting of certain kinds of ranges of ranges
|
||||||
|
(`#2787 <https://github.com/fmtlib/fmt/pull/2787>`_).
|
||||||
|
Thanks `@BRevzin (Barry Revzin) <https://github.com/BRevzin>`_.
|
||||||
|
|
||||||
|
* Fixed handling of maps with element types other than ``std::pair``
|
||||||
|
(`#2944 <https://github.com/fmtlib/fmt/pull/2944>`_).
|
||||||
|
Thanks `@BrukerJWD (Jonathan W) <https://github.com/BrukerJWD>`_.
|
||||||
|
|
||||||
|
* Made tuple formatter enabled only if elements are formattable
|
||||||
|
(`#2939 <https://github.com/fmtlib/fmt/issues/2939>`_,
|
||||||
|
`#2940 <https://github.com/fmtlib/fmt/pull/2940>`_).
|
||||||
|
Thanks `@jehelset <https://github.com/jehelset>`_.
|
||||||
|
|
||||||
|
* Made ``fmt::join`` compatible with format string compilation
|
||||||
|
(`#2719 <https://github.com/fmtlib/fmt/issues/2719>`_,
|
||||||
|
`#2720 <https://github.com/fmtlib/fmt/pull/2720>`_).
|
||||||
|
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
|
||||||
|
|
||||||
|
* Made compile-time checks work with named arguments of custom types and
|
||||||
|
``std::ostream`` ``print`` overloads
|
||||||
|
(`#2816 <https://github.com/fmtlib/fmt/issues/2816>`_,
|
||||||
|
`#2817 <https://github.com/fmtlib/fmt/issues/2817>`_,
|
||||||
|
`#2819 <https://github.com/fmtlib/fmt/pull/2819>`_).
|
||||||
|
Thanks `@timsong-cpp <https://github.com/timsong-cpp>`_.
|
||||||
|
|
||||||
|
* Removed ``make_args_checked`` because it is no longer needed for compile-time
|
||||||
|
checks (`#2760 <https://github.com/fmtlib/fmt/pull/2760>`_).
|
||||||
|
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
|
||||||
|
|
||||||
|
* Removed the following deprecated APIs: ``_format``, ``arg_join``,
|
||||||
|
the ``format_to`` overload that takes a memory buffer,
|
||||||
|
``[v]fprintf`` that takes an ``ostream``.
|
||||||
|
|
||||||
|
* Removed the deprecated implicit conversion of ``[const] signed char*`` and
|
||||||
|
``[const] unsigned char*`` to C strings.
|
||||||
|
|
||||||
|
* Removed the deprecated ``fmt/locale.h``.
|
||||||
|
|
||||||
|
* Replaced the deprecated ``fileno()`` with ``descriptor()`` in
|
||||||
|
``buffered_file``.
|
||||||
|
|
||||||
|
* Moved ``to_string_view`` to the ``detail`` namespace since it's an
|
||||||
|
implementation detail.
|
||||||
|
|
||||||
|
* Made access mode of a created file consistent with ``fopen`` by setting
|
||||||
|
``S_IWGRP`` and ``S_IWOTH``
|
||||||
|
(`#2733 <https://github.com/fmtlib/fmt/pull/2733>`_).
|
||||||
|
Thanks `@arogge (Andreas Rogge) <https://github.com/arogge>`_.
|
||||||
|
|
||||||
|
* Removed a redundant buffer resize when formatting to ``std::ostream``
|
||||||
|
(`#2842 <https://github.com/fmtlib/fmt/issues/2842>`_,
|
||||||
|
`#2843 <https://github.com/fmtlib/fmt/pull/2843>`_).
|
||||||
|
Thanks `@jcelerier (Jean-Michaël Celerier) <https://github.com/jcelerier>`_.
|
||||||
|
|
||||||
|
* Made precision computation for strings consistent with width
|
||||||
|
(`#2888 <https://github.com/fmtlib/fmt/issues/2888>`_).
|
||||||
|
|
||||||
|
* Fixed handling of locale separators in floating point formatting
|
||||||
|
(`#2830 <https://github.com/fmtlib/fmt/issues/2830>`_).
|
||||||
|
|
||||||
|
* Made sign specifiers work with ``__int128_t``
|
||||||
|
(`#2773 <https://github.com/fmtlib/fmt/issues/2773>`_).
|
||||||
|
|
||||||
|
* Improved support for systems such as CHERI with extra data stored in pointers
|
||||||
|
(`#2932 <https://github.com/fmtlib/fmt/pull/2932>`_).
|
||||||
|
Thanks `@davidchisnall (David Chisnall) <https://github.com/davidchisnall>`_.
|
||||||
|
|
||||||
|
* Improved documentation
|
||||||
|
(`#2706 <https://github.com/fmtlib/fmt/pull/2706>`_,
|
||||||
|
`#2712 <https://github.com/fmtlib/fmt/pull/2712>`_,
|
||||||
|
`#2789 <https://github.com/fmtlib/fmt/pull/2789>`_,
|
||||||
|
`#2803 <https://github.com/fmtlib/fmt/pull/2803>`_,
|
||||||
|
`#2805 <https://github.com/fmtlib/fmt/pull/2805>`_,
|
||||||
|
`#2815 <https://github.com/fmtlib/fmt/pull/2815>`_,
|
||||||
|
`#2924 <https://github.com/fmtlib/fmt/pull/2924>`_).
|
||||||
|
Thanks `@BRevzin (Barry Revzin) <https://github.com/BRevzin>`_,
|
||||||
|
`@Pokechu22 <https://github.com/Pokechu22>`_,
|
||||||
|
`@setoye (Alta) <https://github.com/setoye>`_,
|
||||||
|
`@rtobar <https://github.com/rtobar>`_,
|
||||||
|
`@rbrugo (Riccardo Brugo) <https://github.com/rbrugo>`_,
|
||||||
|
`@anoonD (cre) <https://github.com/anoonD>`_,
|
||||||
|
`@leha-bot (Alex) <https://github.com/leha-bot>`_.
|
||||||
|
|
||||||
|
* Improved build configuration
|
||||||
|
(`#2766 <https://github.com/fmtlib/fmt/pull/2766>`_,
|
||||||
|
`#2772 <https://github.com/fmtlib/fmt/pull/2772>`_,
|
||||||
|
`#2836 <https://github.com/fmtlib/fmt/pull/2836>`_,
|
||||||
|
`#2852 <https://github.com/fmtlib/fmt/pull/2852>`_,
|
||||||
|
`#2907 <https://github.com/fmtlib/fmt/pull/2907>`_,
|
||||||
|
`#2913 <https://github.com/fmtlib/fmt/pull/2913>`_,
|
||||||
|
`#2914 <https://github.com/fmtlib/fmt/pull/2914>`_).
|
||||||
|
Thanks `@kambala-decapitator (Andrey Filipenkov)
|
||||||
|
<https://github.com/kambala-decapitator>`_,
|
||||||
|
`@mattiasljungstrom (Mattias Ljungström)
|
||||||
|
<https://github.com/mattiasljungstrom>`_,
|
||||||
|
`@kieselnb (Nick Kiesel) <https://github.com/kieselnb>`_,
|
||||||
|
`@nathannaveen <https://github.com/nathannaveen>`_,
|
||||||
|
`@Vertexwahn <https://github.com/Vertexwahn>`_.
|
||||||
|
|
||||||
|
* Fixed various warnings and compilation issues
|
||||||
|
(`#2408 <https://github.com/fmtlib/fmt/issues/2408>`_,
|
||||||
|
`#2507 <https://github.com/fmtlib/fmt/issues/2507>`_,
|
||||||
|
`#2697 <https://github.com/fmtlib/fmt/issues/2697>`_,
|
||||||
|
`#2715 <https://github.com/fmtlib/fmt/issues/2715>`_,
|
||||||
|
`#2717 <https://github.com/fmtlib/fmt/issues/2717>`_,
|
||||||
|
`#2722 <https://github.com/fmtlib/fmt/pull/2722>`_,
|
||||||
|
`#2724 <https://github.com/fmtlib/fmt/pull/2724>`_,
|
||||||
|
`#2725 <https://github.com/fmtlib/fmt/pull/2725>`_,
|
||||||
|
`#2726 <https://github.com/fmtlib/fmt/issues/2726>`_,
|
||||||
|
`#2728 <https://github.com/fmtlib/fmt/pull/2728>`_,
|
||||||
|
`#2732 <https://github.com/fmtlib/fmt/pull/2732>`_,
|
||||||
|
`#2738 <https://github.com/fmtlib/fmt/issues/2738>`_,
|
||||||
|
`#2742 <https://github.com/fmtlib/fmt/pull/2742>`_,
|
||||||
|
`#2744 <https://github.com/fmtlib/fmt/issues/2744>`_,
|
||||||
|
`#2745 <https://github.com/fmtlib/fmt/issues/2745>`_,
|
||||||
|
`#2746 <https://github.com/fmtlib/fmt/issues/2746>`_,
|
||||||
|
`#2754 <https://github.com/fmtlib/fmt/issues/2754>`_,
|
||||||
|
`#2755 <https://github.com/fmtlib/fmt/pull/2755>`_,
|
||||||
|
`#2757 <https://github.com/fmtlib/fmt/issues/2757>`_,
|
||||||
|
`#2758 <https://github.com/fmtlib/fmt/pull/2758>`_,
|
||||||
|
`#2761 <https://github.com/fmtlib/fmt/issues/2761>`_,
|
||||||
|
`#2762 <https://github.com/fmtlib/fmt/pull/2762>`_,
|
||||||
|
`#2763 <https://github.com/fmtlib/fmt/issues/2763>`_,
|
||||||
|
`#2765 <https://github.com/fmtlib/fmt/pull/2765>`_,
|
||||||
|
`#2769 <https://github.com/fmtlib/fmt/issues/2769>`_,
|
||||||
|
`#2770 <https://github.com/fmtlib/fmt/pull/2770>`_,
|
||||||
|
`#2771 <https://github.com/fmtlib/fmt/issues/2771>`_,
|
||||||
|
`#2777 <https://github.com/fmtlib/fmt/issues/2777>`_,
|
||||||
|
`#2779 <https://github.com/fmtlib/fmt/pull/2779>`_,
|
||||||
|
`#2782 <https://github.com/fmtlib/fmt/pull/2782>`_,
|
||||||
|
`#2783 <https://github.com/fmtlib/fmt/pull/2783>`_,
|
||||||
|
`#2794 <https://github.com/fmtlib/fmt/issues/2794>`_,
|
||||||
|
`#2796 <https://github.com/fmtlib/fmt/issues/2796>`_,
|
||||||
|
`#2797 <https://github.com/fmtlib/fmt/pull/2797>`_,
|
||||||
|
`#2801 <https://github.com/fmtlib/fmt/pull/2801>`_,
|
||||||
|
`#2802 <https://github.com/fmtlib/fmt/pull/2802>`_,
|
||||||
|
`#2808 <https://github.com/fmtlib/fmt/issues/2808>`_,
|
||||||
|
`#2818 <https://github.com/fmtlib/fmt/issues/2818>`_,
|
||||||
|
`#2819 <https://github.com/fmtlib/fmt/pull/2819>`_,
|
||||||
|
`#2829 <https://github.com/fmtlib/fmt/issues/2829>`_,
|
||||||
|
`#2835 <https://github.com/fmtlib/fmt/issues/2835>`_,
|
||||||
|
`#2848 <https://github.com/fmtlib/fmt/issues/2848>`_,
|
||||||
|
`#2860 <https://github.com/fmtlib/fmt/issues/2860>`_,
|
||||||
|
`#2861 <https://github.com/fmtlib/fmt/pull/2861>`_,
|
||||||
|
`#2882 <https://github.com/fmtlib/fmt/pull/2882>`_,
|
||||||
|
`#2886 <https://github.com/fmtlib/fmt/issues/2886>`_,
|
||||||
|
`#2891 <https://github.com/fmtlib/fmt/issues/2891>`_,
|
||||||
|
`#2892 <https://github.com/fmtlib/fmt/pull/2892>`_,
|
||||||
|
`#2895 <https://github.com/fmtlib/fmt/issues/2895>`_,
|
||||||
|
`#2896 <https://github.com/fmtlib/fmt/issues/2896>`_,
|
||||||
|
`#2903 <https://github.com/fmtlib/fmt/pull/2903>`_,
|
||||||
|
`#2906 <https://github.com/fmtlib/fmt/issues/2906>`_,
|
||||||
|
`#2908 <https://github.com/fmtlib/fmt/issues/2908>`_,
|
||||||
|
`#2909 <https://github.com/fmtlib/fmt/pull/2909>`_,
|
||||||
|
`#2920 <https://github.com/fmtlib/fmt/issues/2920>`_,
|
||||||
|
`#2922 <https://github.com/fmtlib/fmt/pull/2922>`_,
|
||||||
|
`#2927 <https://github.com/fmtlib/fmt/pull/2927>`_,
|
||||||
|
`#2929 <https://github.com/fmtlib/fmt/pull/2929>`_,
|
||||||
|
`#2936 <https://github.com/fmtlib/fmt/issues/2936>`_,
|
||||||
|
`#2937 <https://github.com/fmtlib/fmt/pull/2937>`_,
|
||||||
|
`#2938 <https://github.com/fmtlib/fmt/pull/2938>`_,
|
||||||
|
`#2951 <https://github.com/fmtlib/fmt/pull/2951>`_,
|
||||||
|
`#2954 <https://github.com/fmtlib/fmt/issues/2954>`_,
|
||||||
|
`#2957 <https://github.com/fmtlib/fmt/pull/2957>`_,
|
||||||
|
`#2958 <https://github.com/fmtlib/fmt/issues/2958>`_,
|
||||||
|
`#2960 <https://github.com/fmtlib/fmt/pull/2960>`_).
|
||||||
|
Thanks `@matrackif <https://github.com/matrackif>`_
|
||||||
|
`@Tobi823 (Tobias Hellmann) <https://github.com/Tobi823>`_,
|
||||||
|
`@ivan-volnov (Ivan Volnov) <https://github.com/ivan-volnov>`_,
|
||||||
|
`@VasiliPupkin256 <https://github.com/VasiliPupkin256>`_,
|
||||||
|
`@federico-busato (Federico) <https://github.com/federico-busato>`_,
|
||||||
|
`@barcharcraz (Charlie Barto) <https://github.com/barcharcraz>`_,
|
||||||
|
`@jk-jeon (Junekey Jeon) <https://github.com/jk-jeon>`_,
|
||||||
|
`@HazardyKnusperkeks (Björn Schäpers)
|
||||||
|
<https://github.com/HazardyKnusperkeks>`_,
|
||||||
|
`@dalboris (Boris Dalstein) <https://github.com/dalboris>`_,
|
||||||
|
`@seanm (Sean McBride) <https://github.com/seanm>`_,
|
||||||
|
`@gsjaardema (Greg Sjaardema) <https://github.com/gsjaardema>`_,
|
||||||
|
`@timsong-cpp <https://github.com/timsong-cpp>`_,
|
||||||
|
`@seanm (Sean McBride) <https://github.com/seanm>`_,
|
||||||
|
`@frithrah <https://github.com/frithrah>`_,
|
||||||
|
`@chronoxor (Ivan Shynkarenka) <https://github.com/chronoxor>`_,
|
||||||
|
`@Agga <https://github.com/Agga>`_,
|
||||||
|
`@madmaxoft (Mattes D) <https://github.com/madmaxoft>`_,
|
||||||
|
`@JurajX (Juraj) <https://github.com/JurajX>`_,
|
||||||
|
`@phprus (Vladislav Shchapov) <https://github.com/phprus>`_,
|
||||||
|
`@Dani-Hub (Daniel Krügler) <https://github.com/Dani-Hub>`_.
|
||||||
|
|
||||||
8.1.1 - 2022-01-06
|
8.1.1 - 2022-01-06
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
@ -6,7 +392,7 @@
|
|||||||
`#2696 <https://github.com/fmtlib/fmt/pull/2696>`_).
|
`#2696 <https://github.com/fmtlib/fmt/pull/2696>`_).
|
||||||
Thanks `@saraedum (Julian Rüth) <https://github.com/saraedum>`_.
|
Thanks `@saraedum (Julian Rüth) <https://github.com/saraedum>`_.
|
||||||
|
|
||||||
* Fixed chorno formatting on big endian systems
|
* Fixed chrono formatting on big endian systems
|
||||||
(`#2698 <https://github.com/fmtlib/fmt/issues/2698>`_,
|
(`#2698 <https://github.com/fmtlib/fmt/issues/2698>`_,
|
||||||
`#2699 <https://github.com/fmtlib/fmt/pull/2699>`_).
|
`#2699 <https://github.com/fmtlib/fmt/pull/2699>`_).
|
||||||
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_ and
|
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_ and
|
||||||
@ -148,6 +534,10 @@
|
|||||||
["
|
["
|
||||||
aan"]
|
aan"]
|
||||||
|
|
||||||
|
* Added an experimental ``?`` specifier for escaping strings.
|
||||||
|
(`#2674 <https://github.com/fmtlib/fmt/pull/2674>`_).
|
||||||
|
Thanks `@BRevzin (Barry Revzin) <https://github.com/BRevzin>`_.
|
||||||
|
|
||||||
* Switched to JSON-like representation of maps and sets for consistency with
|
* Switched to JSON-like representation of maps and sets for consistency with
|
||||||
Python's ``str.format``.
|
Python's ``str.format``.
|
||||||
For example (`godbolt <https://godbolt.org/z/seKjoY9W5>`__):
|
For example (`godbolt <https://godbolt.org/z/seKjoY9W5>`__):
|
||||||
@ -367,7 +757,8 @@
|
|||||||
`@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_,
|
`@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_,
|
||||||
`@andrewcorrigan (Andrew Corrigan) <https://github.com/andrewcorrigan>`_,
|
`@andrewcorrigan (Andrew Corrigan) <https://github.com/andrewcorrigan>`_,
|
||||||
`@lucpelletier <https://github.com/lucpelletier>`_,
|
`@lucpelletier <https://github.com/lucpelletier>`_,
|
||||||
`@HazardyKnusperkeks (Björn Schäpers) <https://github.com/HazardyKnusperkeks>`_.
|
`@HazardyKnusperkeks (Björn Schäpers)
|
||||||
|
<https://github.com/HazardyKnusperkeks>`_.
|
||||||
|
|
||||||
8.0.1 - 2021-07-02
|
8.0.1 - 2021-07-02
|
||||||
------------------
|
------------------
|
||||||
|
20
externals/dynarmic/externals/fmt/README.rst
vendored
20
externals/dynarmic/externals/fmt/README.rst
vendored
@ -1,5 +1,7 @@
|
|||||||
{fmt}
|
.. image:: https://user-images.githubusercontent.com/
|
||||||
=====
|
576385/156254208-f5b743a9-88cf-439d-b0c0-923d53e8d551.png
|
||||||
|
:width: 25%
|
||||||
|
:alt: {fmt}
|
||||||
|
|
||||||
.. image:: https://github.com/fmtlib/fmt/workflows/linux/badge.svg
|
.. image:: https://github.com/fmtlib/fmt/workflows/linux/badge.svg
|
||||||
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux
|
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux
|
||||||
@ -26,12 +28,13 @@
|
|||||||
**{fmt}** is an open-source formatting library providing a fast and safe
|
**{fmt}** is an open-source formatting library providing a fast and safe
|
||||||
alternative to C stdio and C++ iostreams.
|
alternative to C stdio and C++ iostreams.
|
||||||
|
|
||||||
If you like this project, please consider donating to the BYSOL
|
If you like this project, please consider donating to one of the funds that
|
||||||
Foundation that helps victims of political repressions in Belarus:
|
help victims of the war in Ukraine: https://www.stopputin.net/.
|
||||||
https://bysol.org/en/bs/general/.
|
|
||||||
|
|
||||||
`Documentation <https://fmt.dev>`__
|
`Documentation <https://fmt.dev>`__
|
||||||
|
|
||||||
|
`Cheat Sheets <https://hackingcpp.com/cpp/libs/fmt.html>`__
|
||||||
|
|
||||||
Q&A: ask questions on `StackOverflow with the tag fmt
|
Q&A: ask questions on `StackOverflow with the tag fmt
|
||||||
<https://stackoverflow.com/questions/tagged/fmt>`_.
|
<https://stackoverflow.com/questions/tagged/fmt>`_.
|
||||||
|
|
||||||
@ -123,7 +126,7 @@ Output::
|
|||||||
Default format: 42s 100ms
|
Default format: 42s 100ms
|
||||||
strftime-like format: 03:15:30
|
strftime-like format: 03:15:30
|
||||||
|
|
||||||
**Print a container** (`run <https://godbolt.org/z/MjsY7c>`_)
|
**Print a container** (`run <https://godbolt.org/z/MxM1YqjE7>`_)
|
||||||
|
|
||||||
.. code:: c++
|
.. code:: c++
|
||||||
|
|
||||||
@ -341,9 +344,12 @@ Projects using this library
|
|||||||
|
|
||||||
* `Folly <https://github.com/facebook/folly>`_: Facebook open-source library
|
* `Folly <https://github.com/facebook/folly>`_: Facebook open-source library
|
||||||
|
|
||||||
|
* `GemRB <https://gemrb.org/>`_: a portable open-source implementation of
|
||||||
|
Bioware’s Infinity Engine
|
||||||
|
|
||||||
* `Grand Mountain Adventure
|
* `Grand Mountain Adventure
|
||||||
<https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/>`_:
|
<https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/>`_:
|
||||||
A beautiful open-world ski & snowboarding game
|
a beautiful open-world ski & snowboarding game
|
||||||
|
|
||||||
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
|
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
|
||||||
Player vs Player Gaming Network with tweaks
|
Player vs Player Gaming Network with tweaks
|
||||||
|
141
externals/dynarmic/externals/fmt/doc/api.rst
vendored
141
externals/dynarmic/externals/fmt/doc/api.rst
vendored
@ -12,6 +12,7 @@ The {fmt} library API consists of the following parts:
|
|||||||
formatting functions and locale support
|
formatting functions and locale support
|
||||||
* :ref:`fmt/ranges.h <ranges-api>`: formatting of ranges and tuples
|
* :ref:`fmt/ranges.h <ranges-api>`: formatting of ranges and tuples
|
||||||
* :ref:`fmt/chrono.h <chrono-api>`: date and time formatting
|
* :ref:`fmt/chrono.h <chrono-api>`: date and time formatting
|
||||||
|
* :ref:`fmt/std.h <std-api>`: formatters for standard library types
|
||||||
* :ref:`fmt/compile.h <compile-api>`: format string compilation
|
* :ref:`fmt/compile.h <compile-api>`: format string compilation
|
||||||
* :ref:`fmt/color.h <color-api>`: terminal color and text style
|
* :ref:`fmt/color.h <color-api>`: terminal color and text style
|
||||||
* :ref:`fmt/os.h <os-api>`: system APIs
|
* :ref:`fmt/os.h <os-api>`: system APIs
|
||||||
@ -66,7 +67,7 @@ checked at compile time in C++20. To pass a runtime format string wrap it in
|
|||||||
.. doxygenfunction:: print(std::FILE *f, format_string<T...> fmt, T&&... args)
|
.. doxygenfunction:: print(std::FILE *f, format_string<T...> fmt, T&&... args)
|
||||||
.. doxygenfunction:: vprint(std::FILE *f, string_view fmt, format_args args)
|
.. doxygenfunction:: vprint(std::FILE *f, string_view fmt, format_args args)
|
||||||
|
|
||||||
Compile-time Format String Checks
|
Compile-Time Format String Checks
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
Compile-time checks are enabled when using ``FMT_STRING``. They support built-in
|
Compile-time checks are enabled when using ``FMT_STRING``. They support built-in
|
||||||
@ -113,8 +114,7 @@ binary footprint, for example (https://godbolt.org/z/oba4Mc):
|
|||||||
|
|
||||||
template <typename S, typename... Args>
|
template <typename S, typename... Args>
|
||||||
void log(const char* file, int line, const S& format, Args&&... args) {
|
void log(const char* file, int line, const S& format, Args&&... args) {
|
||||||
vlog(file, line, format,
|
vlog(file, line, format, fmt::make_format_args(args...));
|
||||||
fmt::make_args_checked<Args...>(format, args...));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MY_LOG(format, ...) \
|
#define MY_LOG(format, ...) \
|
||||||
@ -125,8 +125,6 @@ binary footprint, for example (https://godbolt.org/z/oba4Mc):
|
|||||||
Note that ``vlog`` is not parameterized on argument types which improves compile
|
Note that ``vlog`` is not parameterized on argument types which improves compile
|
||||||
times and reduces binary code size compared to a fully parameterized version.
|
times and reduces binary code size compared to a fully parameterized version.
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::make_args_checked(const S&, const remove_reference_t<Args>&...)
|
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::make_format_args(const Args&...)
|
.. doxygenfunction:: fmt::make_format_args(const Args&...)
|
||||||
|
|
||||||
.. doxygenclass:: fmt::format_arg_store
|
.. doxygenclass:: fmt::format_arg_store
|
||||||
@ -143,6 +141,9 @@ times and reduces binary code size compared to a fully parameterized version.
|
|||||||
.. doxygenclass:: fmt::basic_format_arg
|
.. doxygenclass:: fmt::basic_format_arg
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
.. doxygenclass:: fmt::basic_format_parse_context
|
||||||
|
:members:
|
||||||
|
|
||||||
.. doxygenclass:: fmt::basic_format_context
|
.. doxygenclass:: fmt::basic_format_context
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
@ -179,9 +180,15 @@ functions and locale support.
|
|||||||
|
|
||||||
.. _udt:
|
.. _udt:
|
||||||
|
|
||||||
Formatting User-defined Types
|
Formatting User-Defined Types
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
The {fmt} library provides formatters for many standard C++ types.
|
||||||
|
See :ref:`fmt/ranges.h <ranges-api>` for ranges and tuples including standard
|
||||||
|
containers such as ``std::vector``, :ref:`fmt/chrono.h <chrono-api>` for date
|
||||||
|
and time formatting and :ref:`fmt/std.h <std-api>` for path and variant
|
||||||
|
formatting.
|
||||||
|
|
||||||
To make a user-defined type formattable, specialize the ``formatter<T>`` struct
|
To make a user-defined type formattable, specialize the ``formatter<T>`` struct
|
||||||
template and implement ``parse`` and ``format`` methods::
|
template and implement ``parse`` and ``format`` methods::
|
||||||
|
|
||||||
@ -208,6 +215,10 @@ template and implement ``parse`` and ``format`` methods::
|
|||||||
// the formatter should parse the 'f' specifier and return an iterator
|
// the formatter should parse the 'f' specifier and return an iterator
|
||||||
// pointing to '}'.
|
// pointing to '}'.
|
||||||
|
|
||||||
|
// Please also note that this character range may be empty, in case of
|
||||||
|
// the "{}" format string, so therefore you should check ctx.begin()
|
||||||
|
// for equality with ctx.end().
|
||||||
|
|
||||||
// Parse the presentation format and store it in the formatter:
|
// Parse the presentation format and store it in the formatter:
|
||||||
auto it = ctx.begin(), end = ctx.end();
|
auto it = ctx.begin(), end = ctx.end();
|
||||||
if (it != end && (*it == 'f' || *it == 'e')) presentation = *it++;
|
if (it != end && (*it == 'f' || *it == 'e')) presentation = *it++;
|
||||||
@ -222,11 +233,11 @@ template and implement ``parse`` and ``format`` methods::
|
|||||||
// Formats the point p using the parsed format specification (presentation)
|
// Formats the point p using the parsed format specification (presentation)
|
||||||
// stored in this formatter.
|
// stored in this formatter.
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const point& p, FormatContext& ctx) -> decltype(ctx.out()) {
|
auto format(const point& p, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||||
// ctx.out() is an output iterator to write to.
|
// ctx.out() is an output iterator to write to.
|
||||||
return presentation == 'f'
|
return presentation == 'f'
|
||||||
? format_to(ctx.out(), "({:.1f}, {:.1f})", p.x, p.y)
|
? fmt::format_to(ctx.out(), "({:.1f}, {:.1f})", p.x, p.y)
|
||||||
: format_to(ctx.out(), "({:.1e}, {:.1e})", p.x, p.y);
|
: fmt::format_to(ctx.out(), "({:.1e}, {:.1e})", p.x, p.y);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -244,7 +255,7 @@ example::
|
|||||||
template <> struct fmt::formatter<color>: formatter<string_view> {
|
template <> struct fmt::formatter<color>: formatter<string_view> {
|
||||||
// parse is inherited from formatter<string_view>.
|
// parse is inherited from formatter<string_view>.
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(color c, FormatContext& ctx) {
|
auto format(color c, FormatContext& ctx) const {
|
||||||
string_view name = "unknown";
|
string_view name = "unknown";
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case color::red: name = "red"; break;
|
case color::red: name = "red"; break;
|
||||||
@ -282,7 +293,7 @@ You can also write a formatter for a hierarchy of classes::
|
|||||||
struct fmt::formatter<T, std::enable_if_t<std::is_base_of<A, T>::value, char>> :
|
struct fmt::formatter<T, std::enable_if_t<std::is_base_of<A, T>::value, char>> :
|
||||||
fmt::formatter<std::string> {
|
fmt::formatter<std::string> {
|
||||||
template <typename FormatCtx>
|
template <typename FormatCtx>
|
||||||
auto format(const A& a, FormatCtx& ctx) {
|
auto format(const A& a, FormatCtx& ctx) const {
|
||||||
return fmt::formatter<std::string>::format(a.name(), ctx);
|
return fmt::formatter<std::string>::format(a.name(), ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -297,17 +308,32 @@ If a type provides both a ``formatter`` specialization and an implicit
|
|||||||
conversion to a formattable type, the specialization takes precedence over the
|
conversion to a formattable type, the specialization takes precedence over the
|
||||||
conversion.
|
conversion.
|
||||||
|
|
||||||
.. doxygenclass:: fmt::basic_format_parse_context
|
For enums {fmt} also provides the ``format_as`` extension API. To format an enum
|
||||||
:members:
|
via this API define ``format_as`` that takes this enum and converts it to the
|
||||||
|
underlying type. ``format_as`` should be defined in the same namespace as the
|
||||||
|
enum.
|
||||||
|
|
||||||
Literal-based API
|
Example (https://godbolt.org/z/r7vvGE1v7)::
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
namespace kevin_namespacy {
|
||||||
|
enum class film {
|
||||||
|
house_of_cards, american_beauty, se7en = 7
|
||||||
|
};
|
||||||
|
auto format_as(film f) { return fmt::underlying(f); }
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
fmt::print("{}\n", kevin_namespacy::film::se7en); // prints "7"
|
||||||
|
}
|
||||||
|
|
||||||
|
Literal-Based API
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
The following user-defined literals are defined in ``fmt/format.h``.
|
The following user-defined literals are defined in ``fmt/format.h``.
|
||||||
|
|
||||||
.. doxygenfunction:: operator""_format(const char *s, size_t n) -> detail::udl_formatter<char>
|
.. doxygenfunction:: operator""_a()
|
||||||
|
|
||||||
.. doxygenfunction:: operator""_a(const char *s, size_t) -> detail::udl_arg<char>
|
|
||||||
|
|
||||||
Utilities
|
Utilities
|
||||||
---------
|
---------
|
||||||
@ -316,9 +342,9 @@ Utilities
|
|||||||
.. doxygenfunction:: fmt::ptr(const std::unique_ptr<T> &p) -> const void*
|
.. doxygenfunction:: fmt::ptr(const std::unique_ptr<T> &p) -> const void*
|
||||||
.. doxygenfunction:: fmt::ptr(const std::shared_ptr<T> &p) -> const void*
|
.. doxygenfunction:: fmt::ptr(const std::shared_ptr<T> &p) -> const void*
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::to_string(const T &value) -> std::string
|
.. doxygenfunction:: fmt::underlying(Enum e) -> typename std::underlying_type<Enum>::type
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::to_string_view(const Char *s) -> basic_string_view<Char>
|
.. doxygenfunction:: fmt::to_string(const T &value) -> std::string
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::join(Range &&range, string_view sep) -> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>>
|
.. doxygenfunction:: fmt::join(Range &&range, string_view sep) -> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>>
|
||||||
|
|
||||||
@ -381,8 +407,8 @@ non-default floating-point formatting that occasionally falls back on
|
|||||||
|
|
||||||
.. _ranges-api:
|
.. _ranges-api:
|
||||||
|
|
||||||
Ranges and Tuple Formatting
|
Range and Tuple Formatting
|
||||||
===========================
|
==========================
|
||||||
|
|
||||||
The library also supports convenient formatting of ranges and tuples::
|
The library also supports convenient formatting of ranges and tuples::
|
||||||
|
|
||||||
@ -441,24 +467,56 @@ The format syntax is described in :ref:`chrono-specs`.
|
|||||||
|
|
||||||
.. doxygenfunction:: gmtime(std::time_t time)
|
.. doxygenfunction:: gmtime(std::time_t time)
|
||||||
|
|
||||||
|
.. _std-api:
|
||||||
|
|
||||||
|
Standard Library Types Formatting
|
||||||
|
=================================
|
||||||
|
|
||||||
|
``fmt/std.h`` provides formatters for:
|
||||||
|
|
||||||
|
* `std::filesystem::path <std::filesystem::path>`_
|
||||||
|
* `std::thread::id <https://en.cppreference.com/w/cpp/thread/thread/id>`_
|
||||||
|
* `std::monostate <https://en.cppreference.com/w/cpp/utility/variant/monostate>`_
|
||||||
|
* `std::variant <https://en.cppreference.com/w/cpp/utility/variant/variant>`_
|
||||||
|
|
||||||
|
Formatting Variants
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
A ``std::variant`` is only formattable if every variant alternative is formattable, and requires the
|
||||||
|
``__cpp_lib_variant`` `library feature <https://en.cppreference.com/w/cpp/feature_test>`_.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
#include <fmt/std.h>
|
||||||
|
|
||||||
|
std::variant<char, float> v0{'x'};
|
||||||
|
// Prints "variant('x')"
|
||||||
|
fmt::print("{}", v0);
|
||||||
|
|
||||||
|
std::variant<std::monostate, char> v1;
|
||||||
|
// Prints "variant(monostate)"
|
||||||
|
|
||||||
.. _compile-api:
|
.. _compile-api:
|
||||||
|
|
||||||
Format string compilation
|
Format String Compilation
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
``fmt/compile.h`` provides format string compilation support when using
|
``fmt/compile.h`` provides format string compilation enabled via the
|
||||||
``FMT_COMPILE``. Format strings are parsed, checked and converted into efficient
|
``FMT_COMPILE`` macro or the ``_cf`` user-defined literal. Format strings
|
||||||
formatting code at compile-time. This supports arguments of built-in and string
|
marked with ``FMT_COMPILE`` or ``_cf`` are parsed, checked and converted into
|
||||||
types as well as user-defined types with ``constexpr`` ``parse`` functions in
|
efficient formatting code at compile-time. This supports arguments of built-in
|
||||||
their ``formatter`` specializations. Format string compilation can generate more
|
and string types as well as user-defined types with ``constexpr`` ``parse``
|
||||||
binary code compared to the default API and is only recommended in places where
|
functions in their ``formatter`` specializations. Format string compilation can
|
||||||
formatting is a performance bottleneck.
|
generate more binary code compared to the default API and is only recommended in
|
||||||
|
places where formatting is a performance bottleneck.
|
||||||
|
|
||||||
.. doxygendefine:: FMT_COMPILE
|
.. doxygendefine:: FMT_COMPILE
|
||||||
|
|
||||||
|
.. doxygenfunction:: operator""_cf()
|
||||||
|
|
||||||
.. _color-api:
|
.. _color-api:
|
||||||
|
|
||||||
Terminal color and text style
|
Terminal Color and Text Style
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
``fmt/color.h`` provides support for terminal color and text style output.
|
``fmt/color.h`` provides support for terminal color and text style output.
|
||||||
@ -469,6 +527,8 @@ Terminal color and text style
|
|||||||
|
|
||||||
.. doxygenfunction:: bg(detail::color_type)
|
.. doxygenfunction:: bg(detail::color_type)
|
||||||
|
|
||||||
|
.. doxygenfunction:: styled(const T& value, text_style ts)
|
||||||
|
|
||||||
.. _os-api:
|
.. _os-api:
|
||||||
|
|
||||||
System APIs
|
System APIs
|
||||||
@ -486,27 +546,28 @@ System APIs
|
|||||||
========================
|
========================
|
||||||
|
|
||||||
``fmt/ostream.h`` provides ``std::ostream`` support including formatting of
|
``fmt/ostream.h`` provides ``std::ostream`` support including formatting of
|
||||||
user-defined types that have an overloaded insertion operator (``operator<<``)::
|
user-defined types that have an overloaded insertion operator (``operator<<``).
|
||||||
|
In order to make a type formattable via ``std::ostream`` you should provide a
|
||||||
|
``formatter`` specialization inherited from ``ostream_formatter``::
|
||||||
|
|
||||||
#include <fmt/ostream.h>
|
#include <fmt/ostream.h>
|
||||||
|
|
||||||
class date {
|
struct date {
|
||||||
int year_, month_, day_;
|
int year, month, day;
|
||||||
public:
|
|
||||||
date(int year, int month, int day): year_(year), month_(month), day_(day) {}
|
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& os, const date& d) {
|
friend std::ostream& operator<<(std::ostream& os, const date& d) {
|
||||||
return os << d.year_ << '-' << d.month_ << '-' << d.day_;
|
return os << d.year << '-' << d.month << '-' << d.day;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string s = fmt::format("The date is {}", date(2012, 12, 9));
|
template <> struct fmt::formatter<date> : ostream_formatter {};
|
||||||
|
|
||||||
|
std::string s = fmt::format("The date is {}", date{2012, 12, 9});
|
||||||
// s == "The date is 2012-12-9"
|
// s == "The date is 2012-12-9"
|
||||||
|
|
||||||
{fmt} only supports insertion operators that are defined in the same namespaces
|
.. doxygenfunction:: streamed(const T &)
|
||||||
as the types they format and can be found with the argument-dependent lookup.
|
|
||||||
|
|
||||||
.. doxygenfunction:: print(std::basic_ostream<Char> &os, const S &format_str, Args&&... args)
|
.. doxygenfunction:: print(std::ostream &os, format_string<T...> fmt, T&&... args)
|
||||||
|
|
||||||
.. _printf-api:
|
.. _printf-api:
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
import errno, os, re, sys
|
import errno, os, re, sys
|
||||||
from subprocess import check_call, CalledProcessError, Popen, PIPE, STDOUT
|
from subprocess import check_call, CalledProcessError, Popen, PIPE, STDOUT
|
||||||
|
|
||||||
versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0', '5.1.0', '5.2.0', '5.2.1', '5.3.0', '6.0.0', '6.1.0', '6.1.1', '6.1.2', '6.2.0', '6.2.1', '7.0.0', '7.0.1', '7.0.2', '7.0.3', '7.1.0', '7.1.1', '7.1.2', '7.1.3', '8.0.0', '8.0.1', '8.1.0', '8.1.1']
|
versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0', '5.1.0', '5.2.0', '5.2.1', '5.3.0', '6.0.0', '6.1.0', '6.1.1', '6.1.2', '6.2.0', '6.2.1', '7.0.0', '7.0.1', '7.0.2', '7.0.3', '7.1.0', '7.1.1', '7.1.2', '7.1.3', '8.0.0', '8.0.1', '8.1.0', '8.1.1', '9.0.0']
|
||||||
|
|
||||||
class Pip:
|
class Pip:
|
||||||
def __init__(self, venv_dir):
|
def __init__(self, venv_dir):
|
||||||
@ -28,6 +28,9 @@ def create_build_env(venv_dir='virtualenv'):
|
|||||||
pip.install('six')
|
pip.install('six')
|
||||||
# See: https://github.com/sphinx-doc/sphinx/issues/9777
|
# See: https://github.com/sphinx-doc/sphinx/issues/9777
|
||||||
pip.install('docutils==0.17.1')
|
pip.install('docutils==0.17.1')
|
||||||
|
# Jinja2 >= 3.1 incompatible with sphinx 3.3.0
|
||||||
|
# See: https://github.com/sphinx-doc/sphinx/issues/10291
|
||||||
|
pip.install('Jinja2<3.1')
|
||||||
pip.install('sphinx-doc/sphinx', 'v3.3.0')
|
pip.install('sphinx-doc/sphinx', 'v3.3.0')
|
||||||
pip.install('michaeljones/breathe', 'v4.25.0')
|
pip.install('michaeljones/breathe', 'v4.25.0')
|
||||||
|
|
||||||
@ -65,6 +68,7 @@ def build_docs(version='dev', **kwargs):
|
|||||||
FMT_USE_RVALUE_REFERENCES=1 \
|
FMT_USE_RVALUE_REFERENCES=1 \
|
||||||
FMT_USE_USER_DEFINED_LITERALS=1 \
|
FMT_USE_USER_DEFINED_LITERALS=1 \
|
||||||
FMT_USE_ALIAS_TEMPLATES=1 \
|
FMT_USE_ALIAS_TEMPLATES=1 \
|
||||||
|
FMT_USE_NONTYPE_TEMPLATE_ARGS=1 \
|
||||||
FMT_API= \
|
FMT_API= \
|
||||||
"FMT_BEGIN_NAMESPACE=namespace fmt {{" \
|
"FMT_BEGIN_NAMESPACE=namespace fmt {{" \
|
||||||
"FMT_END_NAMESPACE=}}" \
|
"FMT_END_NAMESPACE=}}" \
|
||||||
|
@ -101,7 +101,7 @@ The code
|
|||||||
format(FMT_STRING("The answer is {:d}"), "forty-two");
|
format(FMT_STRING("The answer is {:d}"), "forty-two");
|
||||||
|
|
||||||
reports a compile-time error on compilers that support relaxed ``constexpr``.
|
reports a compile-time error on compilers that support relaxed ``constexpr``.
|
||||||
See `here <api.html#c.fmt>`_ for details.
|
See `here <api.html#compile-time-format-string-checks>`_ for details.
|
||||||
|
|
||||||
The following code
|
The following code
|
||||||
|
|
||||||
|
37
externals/dynarmic/externals/fmt/doc/syntax.rst
vendored
37
externals/dynarmic/externals/fmt/doc/syntax.rst
vendored
@ -304,7 +304,8 @@ The available presentation types for pointers are:
|
|||||||
Chrono Format Specifications
|
Chrono Format Specifications
|
||||||
============================
|
============================
|
||||||
|
|
||||||
Format specifications for chrono types have the following syntax:
|
Format specifications for chrono types and ``std::tm`` have the following
|
||||||
|
syntax:
|
||||||
|
|
||||||
.. productionlist:: sf
|
.. productionlist:: sf
|
||||||
chrono_format_spec: [[`fill`]`align`][`width`]["." `precision`][`chrono_specs`]
|
chrono_format_spec: [[`fill`]`align`][`width`]["." `precision`][`chrono_specs`]
|
||||||
@ -345,12 +346,38 @@ points are:
|
|||||||
| | command ``%OS`` produces the locale's alternative representation. |
|
| | command ``%OS`` produces the locale's alternative representation. |
|
||||||
+---------+--------------------------------------------------------------------+
|
+---------+--------------------------------------------------------------------+
|
||||||
|
|
||||||
Specifiers that have a calendaric component such as `'d'` (the day of month)
|
Specifiers that have a calendaric component such as ``'d'`` (the day of month)
|
||||||
are valid only for ``std::tm`` and not durations or time points.
|
are valid only for ``std::tm`` and not durations or time points.
|
||||||
|
|
||||||
``std::tm`` uses the system's `strftime
|
.. range-specs:
|
||||||
<https://en.cppreference.com/w/cpp/chrono/c/strftime>`_ so refer to its
|
|
||||||
documentation for details on supported conversion specifiers.
|
Range Format Specifications
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Format specifications for range types have the following syntax:
|
||||||
|
|
||||||
|
..productionlist:: sf
|
||||||
|
range_format_spec: [":" [`underlying_spec`]]
|
||||||
|
|
||||||
|
The `underlying_spec` is parsed based on the formatter of the range's
|
||||||
|
reference type.
|
||||||
|
|
||||||
|
By default, a range of characters or strings is printed escaped and quoted. But
|
||||||
|
if any `underlying_spec` is provided (even if it is empty), then the characters
|
||||||
|
or strings are printed according to the provided specification.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
fmt::format("{}", std::vector{10, 20, 30});
|
||||||
|
// Result: [10, 20, 30]
|
||||||
|
fmt::format("{::#x}", std::vector{10, 20, 30});
|
||||||
|
// Result: [0xa, 0x14, 0x13]
|
||||||
|
fmt::format("{}", vector{'h', 'e', 'l', 'l', 'o'});
|
||||||
|
// Result: ['h', 'e', 'l', 'l', 'o']
|
||||||
|
fmt::format("{::}", vector{'h', 'e', 'l', 'l', 'o'});
|
||||||
|
// Result: [h, e, l, l, o]
|
||||||
|
fmt::format("{::d}", vector{'h', 'e', 'l', 'l', 'o'});
|
||||||
|
// Result: [104, 101, 108, 108, 111]
|
||||||
|
|
||||||
.. _formatexamples:
|
.. _formatexamples:
|
||||||
|
|
||||||
|
@ -95,10 +95,10 @@ class dynamic_format_arg_store
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using stored_type = conditional_t<detail::is_string<T>::value &&
|
using stored_type = conditional_t<
|
||||||
!has_formatter<T, Context>::value &&
|
std::is_convertible<T, std::basic_string<char_type>>::value &&
|
||||||
!detail::is_reference_wrapper<T>::value,
|
!detail::is_reference_wrapper<T>::value,
|
||||||
std::basic_string<char_type>, T>;
|
std::basic_string<char_type>, T>;
|
||||||
|
|
||||||
// Storage of basic_format_arg must be contiguous.
|
// Storage of basic_format_arg must be contiguous.
|
||||||
std::vector<basic_format_arg<Context>> data_;
|
std::vector<basic_format_arg<Context>> data_;
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <cmath> // std::isfinite
|
||||||
|
#include <cstring> // std::memcpy
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
@ -321,14 +323,13 @@ constexpr const size_t codecvt_result<CodeUnit>::max_size;
|
|||||||
template <typename CodeUnit>
|
template <typename CodeUnit>
|
||||||
void write_codecvt(codecvt_result<CodeUnit>& out, string_view in_buf,
|
void write_codecvt(codecvt_result<CodeUnit>& out, string_view in_buf,
|
||||||
const std::locale& loc) {
|
const std::locale& loc) {
|
||||||
using codecvt = std::codecvt<CodeUnit, char, std::mbstate_t>;
|
|
||||||
#if FMT_CLANG_VERSION
|
#if FMT_CLANG_VERSION
|
||||||
# pragma clang diagnostic push
|
# pragma clang diagnostic push
|
||||||
# pragma clang diagnostic ignored "-Wdeprecated"
|
# pragma clang diagnostic ignored "-Wdeprecated"
|
||||||
auto& f = std::use_facet<codecvt>(loc);
|
auto& f = std::use_facet<std::codecvt<CodeUnit, char, std::mbstate_t>>(loc);
|
||||||
# pragma clang diagnostic pop
|
# pragma clang diagnostic pop
|
||||||
#else
|
#else
|
||||||
auto& f = std::use_facet<codecvt>(loc);
|
auto& f = std::use_facet<std::codecvt<CodeUnit, char, std::mbstate_t>>(loc);
|
||||||
#endif
|
#endif
|
||||||
auto mb = std::mbstate_t();
|
auto mb = std::mbstate_t();
|
||||||
const char* from_next = nullptr;
|
const char* from_next = nullptr;
|
||||||
@ -344,7 +345,7 @@ auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc)
|
|||||||
if (detail::is_utf8() && loc != get_classic_locale()) {
|
if (detail::is_utf8() && loc != get_classic_locale()) {
|
||||||
// char16_t and char32_t codecvts are broken in MSVC (linkage errors) and
|
// char16_t and char32_t codecvts are broken in MSVC (linkage errors) and
|
||||||
// gcc-4.
|
// gcc-4.
|
||||||
#if FMT_MSC_VER != 0 || \
|
#if FMT_MSC_VERSION != 0 || \
|
||||||
(defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI))
|
(defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI))
|
||||||
// The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5
|
// The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5
|
||||||
// and newer.
|
// and newer.
|
||||||
@ -468,7 +469,7 @@ inline std::tm localtime(std::time_t time) {
|
|||||||
|
|
||||||
bool fallback(int res) { return res == 0; }
|
bool fallback(int res) { return res == 0; }
|
||||||
|
|
||||||
#if !FMT_MSC_VER
|
#if !FMT_MSC_VERSION
|
||||||
bool fallback(detail::null<>) {
|
bool fallback(detail::null<>) {
|
||||||
using namespace fmt::detail;
|
using namespace fmt::detail;
|
||||||
std::tm* tm = std::localtime(&time_);
|
std::tm* tm = std::localtime(&time_);
|
||||||
@ -514,7 +515,7 @@ inline std::tm gmtime(std::time_t time) {
|
|||||||
|
|
||||||
bool fallback(int res) { return res == 0; }
|
bool fallback(int res) { return res == 0; }
|
||||||
|
|
||||||
#if !FMT_MSC_VER
|
#if !FMT_MSC_VERSION
|
||||||
bool fallback(detail::null<>) {
|
bool fallback(detail::null<>) {
|
||||||
std::tm* tm = std::gmtime(&time_);
|
std::tm* tm = std::gmtime(&time_);
|
||||||
if (tm) tm_ = *tm;
|
if (tm) tm_ = *tm;
|
||||||
@ -562,10 +563,10 @@ inline void write_digit2_separated(char* buf, unsigned a, unsigned b,
|
|||||||
constexpr const size_t len = 8;
|
constexpr const size_t len = 8;
|
||||||
if (const_check(is_big_endian())) {
|
if (const_check(is_big_endian())) {
|
||||||
char tmp[len];
|
char tmp[len];
|
||||||
memcpy(tmp, &digits, len);
|
std::memcpy(tmp, &digits, len);
|
||||||
std::reverse_copy(tmp, tmp + len, buf);
|
std::reverse_copy(tmp, tmp + len, buf);
|
||||||
} else {
|
} else {
|
||||||
memcpy(buf, &digits, len);
|
std::memcpy(buf, &digits, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1214,7 +1215,7 @@ template <typename OutputIt, typename Char> class tm_writer {
|
|||||||
char buf[10];
|
char buf[10];
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
if (year >= 0 && year < 10000) {
|
if (year >= 0 && year < 10000) {
|
||||||
copy2(buf, digits2(to_unsigned(year / 100)));
|
copy2(buf, digits2(static_cast<size_t>(year / 100)));
|
||||||
} else {
|
} else {
|
||||||
offset = 4;
|
offset = 4;
|
||||||
write_year_extended(year);
|
write_year_extended(year);
|
||||||
@ -1387,15 +1388,6 @@ struct chrono_format_checker : null_chrono_spec_handler<chrono_format_checker> {
|
|||||||
FMT_CONSTEXPR void on_duration_unit() {}
|
FMT_CONSTEXPR void on_duration_unit() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
|
||||||
inline bool isnan(T) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
|
|
||||||
inline bool isnan(T value) {
|
|
||||||
return std::isnan(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||||
inline bool isfinite(T) {
|
inline bool isfinite(T) {
|
||||||
return true;
|
return true;
|
||||||
@ -1470,14 +1462,22 @@ inline std::chrono::duration<Rep, std::milli> get_milliseconds(
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of fractional digits in the range [0, 18] according to the
|
// Counts the number of fractional digits in the range [0, 18] according to the
|
||||||
// C++20 spec. If more than 18 fractional digits are required then returns 6 for
|
// C++20 spec. If more than 18 fractional digits are required then returns 6 for
|
||||||
// microseconds precision.
|
// microseconds precision.
|
||||||
constexpr int count_fractional_digits(long long num, long long den, int n = 0) {
|
template <long long Num, long long Den, int N = 0,
|
||||||
return num % den == 0
|
bool Enabled = (N < 19) && (Num <= max_value<long long>() / 10)>
|
||||||
? n
|
struct count_fractional_digits {
|
||||||
: (n > 18 ? 6 : count_fractional_digits(num * 10, den, n + 1));
|
static constexpr int value =
|
||||||
}
|
Num % Den == 0 ? N : count_fractional_digits<Num * 10, Den, N + 1>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base case that doesn't instantiate any more templates
|
||||||
|
// in order to avoid overflow.
|
||||||
|
template <long long Num, long long Den, int N>
|
||||||
|
struct count_fractional_digits<Num, Den, N, false> {
|
||||||
|
static constexpr int value = (Num % Den == 0) ? N : 6;
|
||||||
|
};
|
||||||
|
|
||||||
constexpr long long pow10(std::uint32_t n) {
|
constexpr long long pow10(std::uint32_t n) {
|
||||||
return n == 0 ? 1 : 10 * pow10(n - 1);
|
return n == 0 ? 1 : 10 * pow10(n - 1);
|
||||||
@ -1663,9 +1663,11 @@ struct chrono_formatter {
|
|||||||
out = format_decimal<char_type>(out, n, num_digits).end;
|
out = format_decimal<char_type>(out, n, num_digits).end;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Duration> void write_fractional_seconds(Duration d) {
|
template <typename Duration> void write_fractional_seconds(Duration d) {
|
||||||
|
FMT_ASSERT(!std::is_floating_point<typename Duration::rep>::value, "");
|
||||||
constexpr auto num_fractional_digits =
|
constexpr auto num_fractional_digits =
|
||||||
count_fractional_digits(Duration::period::num, Duration::period::den);
|
count_fractional_digits<Duration::period::num,
|
||||||
|
Duration::period::den>::value;
|
||||||
|
|
||||||
using subsecond_precision = std::chrono::duration<
|
using subsecond_precision = std::chrono::duration<
|
||||||
typename std::common_type<typename Duration::rep,
|
typename std::common_type<typename Duration::rep,
|
||||||
@ -1674,12 +1676,9 @@ struct chrono_formatter {
|
|||||||
if (std::ratio_less<typename subsecond_precision::period,
|
if (std::ratio_less<typename subsecond_precision::period,
|
||||||
std::chrono::seconds::period>::value) {
|
std::chrono::seconds::period>::value) {
|
||||||
*out++ = '.';
|
*out++ = '.';
|
||||||
// Don't convert long double to integer seconds to avoid overflow.
|
auto fractional =
|
||||||
using sec = conditional_t<
|
detail::abs(d) - std::chrono::duration_cast<std::chrono::seconds>(d);
|
||||||
std::is_same<typename Duration::rep, long double>::value,
|
auto subseconds =
|
||||||
std::chrono::duration<long double>, std::chrono::seconds>;
|
|
||||||
auto fractional = detail::abs(d) - std::chrono::duration_cast<sec>(d);
|
|
||||||
const auto subseconds =
|
|
||||||
std::chrono::treat_as_floating_point<
|
std::chrono::treat_as_floating_point<
|
||||||
typename subsecond_precision::rep>::value
|
typename subsecond_precision::rep>::value
|
||||||
? fractional.count()
|
? fractional.count()
|
||||||
@ -1770,8 +1769,22 @@ struct chrono_formatter {
|
|||||||
if (handle_nan_inf()) return;
|
if (handle_nan_inf()) return;
|
||||||
|
|
||||||
if (ns == numeric_system::standard) {
|
if (ns == numeric_system::standard) {
|
||||||
write(second(), 2);
|
if (std::is_floating_point<rep>::value) {
|
||||||
write_fractional_seconds(std::chrono::duration<rep, Period>{val});
|
constexpr auto num_fractional_digits =
|
||||||
|
count_fractional_digits<Period::num, Period::den>::value;
|
||||||
|
auto buf = memory_buffer();
|
||||||
|
format_to(std::back_inserter(buf), runtime("{:.{}f}"),
|
||||||
|
std::fmod(val * static_cast<rep>(Period::num) /
|
||||||
|
static_cast<rep>(Period::den),
|
||||||
|
60),
|
||||||
|
num_fractional_digits);
|
||||||
|
if (negative) *out++ = '-';
|
||||||
|
if (buf.size() < 2 || buf[1] == '.') *out++ = '0';
|
||||||
|
out = std::copy(buf.begin(), buf.end(), out);
|
||||||
|
} else {
|
||||||
|
write(second(), 2);
|
||||||
|
write_fractional_seconds(std::chrono::duration<rep, Period>(val));
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto time = tm();
|
auto time = tm();
|
||||||
|
213
externals/dynarmic/externals/fmt/include/fmt/color.h
vendored
213
externals/dynarmic/externals/fmt/include/fmt/color.h
vendored
@ -10,13 +10,6 @@
|
|||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
// __declspec(deprecated) is broken in some MSVC versions.
|
|
||||||
#if FMT_MSC_VER
|
|
||||||
# define FMT_DEPRECATED_NONMSVC
|
|
||||||
#else
|
|
||||||
# define FMT_DEPRECATED_NONMSVC FMT_DEPRECATED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
FMT_MODULE_EXPORT_BEGIN
|
FMT_MODULE_EXPORT_BEGIN
|
||||||
|
|
||||||
@ -214,17 +207,16 @@ FMT_BEGIN_DETAIL_NAMESPACE
|
|||||||
|
|
||||||
// color is a struct of either a rgb color or a terminal color.
|
// color is a struct of either a rgb color or a terminal color.
|
||||||
struct color_type {
|
struct color_type {
|
||||||
FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {}
|
FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {}
|
||||||
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true),
|
FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} {
|
||||||
value{} {
|
|
||||||
value.rgb_color = static_cast<uint32_t>(rgb_color);
|
value.rgb_color = static_cast<uint32_t>(rgb_color);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} {
|
FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} {
|
||||||
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
|
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
|
||||||
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
|
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(),
|
FMT_CONSTEXPR color_type(terminal_color term_color) noexcept
|
||||||
value{} {
|
: is_rgb(), value{} {
|
||||||
value.term_color = static_cast<uint8_t>(term_color);
|
value.term_color = static_cast<uint8_t>(term_color);
|
||||||
}
|
}
|
||||||
bool is_rgb;
|
bool is_rgb;
|
||||||
@ -239,10 +231,8 @@ FMT_END_DETAIL_NAMESPACE
|
|||||||
/** A text style consisting of foreground and background colors and emphasis. */
|
/** A text style consisting of foreground and background colors and emphasis. */
|
||||||
class text_style {
|
class text_style {
|
||||||
public:
|
public:
|
||||||
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
|
FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept
|
||||||
: set_foreground_color(),
|
: set_foreground_color(), set_background_color(), ems(em) {}
|
||||||
set_background_color(),
|
|
||||||
ems(em) {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
|
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
|
||||||
if (!set_foreground_color) {
|
if (!set_foreground_color) {
|
||||||
@ -273,44 +263,32 @@ class text_style {
|
|||||||
return lhs |= rhs;
|
return lhs |= rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_DEPRECATED_NONMSVC FMT_CONSTEXPR text_style& operator&=(
|
FMT_CONSTEXPR bool has_foreground() const noexcept {
|
||||||
const text_style& rhs) {
|
|
||||||
return and_assign(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_DEPRECATED_NONMSVC friend FMT_CONSTEXPR text_style
|
|
||||||
operator&(text_style lhs, const text_style& rhs) {
|
|
||||||
return lhs.and_assign(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
|
|
||||||
return set_foreground_color;
|
return set_foreground_color;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR bool has_background() const noexcept {
|
||||||
return set_background_color;
|
return set_background_color;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR bool has_emphasis() const noexcept {
|
||||||
return static_cast<uint8_t>(ems) != 0;
|
return static_cast<uint8_t>(ems) != 0;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR detail::color_type get_foreground() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR detail::color_type get_foreground() const noexcept {
|
||||||
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
|
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
|
||||||
return foreground_color;
|
return foreground_color;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR detail::color_type get_background() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR detail::color_type get_background() const noexcept {
|
||||||
FMT_ASSERT(has_background(), "no background specified for this style");
|
FMT_ASSERT(has_background(), "no background specified for this style");
|
||||||
return background_color;
|
return background_color;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR emphasis get_emphasis() const noexcept {
|
||||||
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
|
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
|
||||||
return ems;
|
return ems;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FMT_CONSTEXPR text_style(bool is_foreground,
|
FMT_CONSTEXPR text_style(bool is_foreground,
|
||||||
detail::color_type text_color) FMT_NOEXCEPT
|
detail::color_type text_color) noexcept
|
||||||
: set_foreground_color(),
|
: set_foreground_color(), set_background_color(), ems() {
|
||||||
set_background_color(),
|
|
||||||
ems() {
|
|
||||||
if (is_foreground) {
|
if (is_foreground) {
|
||||||
foreground_color = text_color;
|
foreground_color = text_color;
|
||||||
set_foreground_color = true;
|
set_foreground_color = true;
|
||||||
@ -320,36 +298,9 @@ class text_style {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEPRECATED!
|
friend FMT_CONSTEXPR text_style fg(detail::color_type foreground) noexcept;
|
||||||
FMT_CONSTEXPR text_style& and_assign(const text_style& rhs) {
|
|
||||||
if (!set_foreground_color) {
|
|
||||||
set_foreground_color = rhs.set_foreground_color;
|
|
||||||
foreground_color = rhs.foreground_color;
|
|
||||||
} else if (rhs.set_foreground_color) {
|
|
||||||
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
|
|
||||||
FMT_THROW(format_error("can't AND a terminal color"));
|
|
||||||
foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!set_background_color) {
|
friend FMT_CONSTEXPR text_style bg(detail::color_type background) noexcept;
|
||||||
set_background_color = rhs.set_background_color;
|
|
||||||
background_color = rhs.background_color;
|
|
||||||
} else if (rhs.set_background_color) {
|
|
||||||
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
|
|
||||||
FMT_THROW(format_error("can't AND a terminal color"));
|
|
||||||
background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
|
|
||||||
static_cast<uint8_t>(rhs.ems));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground)
|
|
||||||
FMT_NOEXCEPT;
|
|
||||||
|
|
||||||
friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background)
|
|
||||||
FMT_NOEXCEPT;
|
|
||||||
|
|
||||||
detail::color_type foreground_color;
|
detail::color_type foreground_color;
|
||||||
detail::color_type background_color;
|
detail::color_type background_color;
|
||||||
@ -359,17 +310,16 @@ class text_style {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** Creates a text style from the foreground (text) color. */
|
/** Creates a text style from the foreground (text) color. */
|
||||||
FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) FMT_NOEXCEPT {
|
FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) noexcept {
|
||||||
return text_style(true, foreground);
|
return text_style(true, foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a text style from the background color. */
|
/** Creates a text style from the background color. */
|
||||||
FMT_CONSTEXPR inline text_style bg(detail::color_type background) FMT_NOEXCEPT {
|
FMT_CONSTEXPR inline text_style bg(detail::color_type background) noexcept {
|
||||||
return text_style(false, background);
|
return text_style(false, background);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR inline text_style operator|(emphasis lhs,
|
FMT_CONSTEXPR inline text_style operator|(emphasis lhs, emphasis rhs) noexcept {
|
||||||
emphasis rhs) FMT_NOEXCEPT {
|
|
||||||
return text_style(lhs) | rhs;
|
return text_style(lhs) | rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,7 +327,7 @@ FMT_BEGIN_DETAIL_NAMESPACE
|
|||||||
|
|
||||||
template <typename Char> struct ansi_color_escape {
|
template <typename Char> struct ansi_color_escape {
|
||||||
FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
|
FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
|
||||||
const char* esc) FMT_NOEXCEPT {
|
const char* esc) noexcept {
|
||||||
// If we have a terminal color, we need to output another escape code
|
// If we have a terminal color, we need to output another escape code
|
||||||
// sequence.
|
// sequence.
|
||||||
if (!text_color.is_rgb) {
|
if (!text_color.is_rgb) {
|
||||||
@ -412,7 +362,7 @@ template <typename Char> struct ansi_color_escape {
|
|||||||
to_esc(color.b, buffer + 15, 'm');
|
to_esc(color.b, buffer + 15, 'm');
|
||||||
buffer[19] = static_cast<Char>(0);
|
buffer[19] = static_cast<Char>(0);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
|
FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept {
|
||||||
uint8_t em_codes[num_emphases] = {};
|
uint8_t em_codes[num_emphases] = {};
|
||||||
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
|
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
|
||||||
if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
|
if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
|
||||||
@ -433,10 +383,10 @@ template <typename Char> struct ansi_color_escape {
|
|||||||
}
|
}
|
||||||
buffer[index++] = static_cast<Char>(0);
|
buffer[index++] = static_cast<Char>(0);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; }
|
FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; }
|
||||||
|
|
||||||
FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
|
FMT_CONSTEXPR const Char* begin() const noexcept { return buffer; }
|
||||||
FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const noexcept {
|
||||||
return buffer + std::char_traits<Char>::length(buffer);
|
return buffer + std::char_traits<Char>::length(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,59 +395,64 @@ template <typename Char> struct ansi_color_escape {
|
|||||||
Char buffer[7u + 3u * num_emphases + 1u];
|
Char buffer[7u + 3u * num_emphases + 1u];
|
||||||
|
|
||||||
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
|
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
|
||||||
char delimiter) FMT_NOEXCEPT {
|
char delimiter) noexcept {
|
||||||
out[0] = static_cast<Char>('0' + c / 100);
|
out[0] = static_cast<Char>('0' + c / 100);
|
||||||
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
||||||
out[2] = static_cast<Char>('0' + c % 10);
|
out[2] = static_cast<Char>('0' + c % 10);
|
||||||
out[3] = static_cast<Char>(delimiter);
|
out[3] = static_cast<Char>(delimiter);
|
||||||
}
|
}
|
||||||
static FMT_CONSTEXPR bool has_emphasis(emphasis em,
|
static FMT_CONSTEXPR bool has_emphasis(emphasis em, emphasis mask) noexcept {
|
||||||
emphasis mask) FMT_NOEXCEPT {
|
|
||||||
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
|
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
|
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
|
||||||
detail::color_type foreground) FMT_NOEXCEPT {
|
detail::color_type foreground) noexcept {
|
||||||
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
|
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
|
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
|
||||||
detail::color_type background) FMT_NOEXCEPT {
|
detail::color_type background) noexcept {
|
||||||
return ansi_color_escape<Char>(background, "\x1b[48;2;");
|
return ansi_color_escape<Char>(background, "\x1b[48;2;");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) FMT_NOEXCEPT {
|
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) noexcept {
|
||||||
return ansi_color_escape<Char>(em);
|
return ansi_color_escape<Char>(em);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char> inline void fputs(const Char* chars, FILE* stream) {
|
||||||
inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT {
|
int result = std::fputs(chars, stream);
|
||||||
std::fputs(chars, stream);
|
if (result < 0)
|
||||||
|
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <> inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) {
|
||||||
inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT {
|
int result = std::fputws(chars, stream);
|
||||||
std::fputws(chars, stream);
|
if (result < 0)
|
||||||
|
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT {
|
template <typename Char> inline void reset_color(FILE* stream) {
|
||||||
fputs("\x1b[0m", stream);
|
fputs("\x1b[0m", stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
|
template <> inline void reset_color<wchar_t>(FILE* stream) {
|
||||||
fputs(L"\x1b[0m", stream);
|
fputs(L"\x1b[0m", stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char> inline void reset_color(buffer<Char>& buffer) {
|
||||||
inline void reset_color(buffer<Char>& buffer) FMT_NOEXCEPT {
|
|
||||||
auto reset_color = string_view("\x1b[0m");
|
auto reset_color = string_view("\x1b[0m");
|
||||||
buffer.append(reset_color.begin(), reset_color.end());
|
buffer.append(reset_color.begin(), reset_color.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T> struct styled_arg {
|
||||||
|
const T& value;
|
||||||
|
text_style style;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void vformat_to(buffer<Char>& buf, const text_style& ts,
|
void vformat_to(buffer<Char>& buf, const text_style& ts,
|
||||||
basic_string_view<Char> format_str,
|
basic_string_view<Char> format_str,
|
||||||
@ -528,9 +483,13 @@ template <typename S, typename Char = char_t<S>>
|
|||||||
void vprint(std::FILE* f, const text_style& ts, const S& format,
|
void vprint(std::FILE* f, const text_style& ts, const S& format,
|
||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buf;
|
basic_memory_buffer<Char> buf;
|
||||||
detail::vformat_to(buf, ts, to_string_view(format), args);
|
detail::vformat_to(buf, ts, detail::to_string_view(format), args);
|
||||||
buf.push_back(Char(0));
|
if (detail::is_utf8()) {
|
||||||
detail::fputs(buf.data(), f);
|
detail::print(f, basic_string_view<Char>(buf.begin(), buf.size()));
|
||||||
|
} else {
|
||||||
|
buf.push_back(Char(0));
|
||||||
|
detail::fputs(buf.data(), f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -549,7 +508,7 @@ template <typename S, typename... Args,
|
|||||||
void print(std::FILE* f, const text_style& ts, const S& format_str,
|
void print(std::FILE* f, const text_style& ts, const S& format_str,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
vprint(f, ts, format_str,
|
vprint(f, ts, format_str,
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
fmt::make_format_args<buffer_context<char_t<S>>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -574,7 +533,7 @@ inline std::basic_string<Char> vformat(
|
|||||||
const text_style& ts, const S& format_str,
|
const text_style& ts, const S& format_str,
|
||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buf;
|
basic_memory_buffer<Char> buf;
|
||||||
detail::vformat_to(buf, ts, to_string_view(format_str), args);
|
detail::vformat_to(buf, ts, detail::to_string_view(format_str), args);
|
||||||
return fmt::to_string(buf);
|
return fmt::to_string(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -593,8 +552,8 @@ inline std::basic_string<Char> vformat(
|
|||||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
template <typename S, typename... Args, typename Char = char_t<S>>
|
||||||
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
return fmt::vformat(ts, to_string_view(format_str),
|
return fmt::vformat(ts, detail::to_string_view(format_str),
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -628,8 +587,62 @@ template <typename OutputIt, typename S, typename... Args,
|
|||||||
inline auto format_to(OutputIt out, const text_style& ts, const S& format_str,
|
inline auto format_to(OutputIt out, const text_style& ts, const S& format_str,
|
||||||
Args&&... args) ->
|
Args&&... args) ->
|
||||||
typename std::enable_if<enable, OutputIt>::type {
|
typename std::enable_if<enable, OutputIt>::type {
|
||||||
return vformat_to(out, ts, to_string_view(format_str),
|
return vformat_to(out, ts, detail::to_string_view(format_str),
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
fmt::make_format_args<buffer_context<char_t<S>>>(args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename Char>
|
||||||
|
struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> {
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
const auto& ts = arg.style;
|
||||||
|
const auto& value = arg.value;
|
||||||
|
auto out = ctx.out();
|
||||||
|
|
||||||
|
bool has_style = false;
|
||||||
|
if (ts.has_emphasis()) {
|
||||||
|
has_style = true;
|
||||||
|
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
|
||||||
|
out = std::copy(emphasis.begin(), emphasis.end(), out);
|
||||||
|
}
|
||||||
|
if (ts.has_foreground()) {
|
||||||
|
has_style = true;
|
||||||
|
auto foreground =
|
||||||
|
detail::make_foreground_color<Char>(ts.get_foreground());
|
||||||
|
out = std::copy(foreground.begin(), foreground.end(), out);
|
||||||
|
}
|
||||||
|
if (ts.has_background()) {
|
||||||
|
has_style = true;
|
||||||
|
auto background =
|
||||||
|
detail::make_background_color<Char>(ts.get_background());
|
||||||
|
out = std::copy(background.begin(), background.end(), out);
|
||||||
|
}
|
||||||
|
out = formatter<T, Char>::format(value, ctx);
|
||||||
|
if (has_style) {
|
||||||
|
auto reset_color = string_view("\x1b[0m");
|
||||||
|
out = std::copy(reset_color.begin(), reset_color.end(), out);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Returns an argument that will be formatted using ANSI escape sequences,
|
||||||
|
to be used in a formatting function.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
fmt::print("Elapsed time: {s:.2f} seconds",
|
||||||
|
fmt::styled(1.23, fmt::fg(fmt::color::green) |
|
||||||
|
fmt::bg(fmt::color::blue)));
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
FMT_CONSTEXPR auto styled(const T& value, text_style ts)
|
||||||
|
-> detail::styled_arg<remove_cvref_t<T>> {
|
||||||
|
return detail::styled_arg<remove_cvref_t<T>>{value, ts};
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_END
|
FMT_MODULE_EXPORT_END
|
||||||
|
@ -13,45 +13,6 @@
|
|||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
// An output iterator that counts the number of objects written to it and
|
|
||||||
// discards them.
|
|
||||||
class counting_iterator {
|
|
||||||
private:
|
|
||||||
size_t count_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using iterator_category = std::output_iterator_tag;
|
|
||||||
using difference_type = std::ptrdiff_t;
|
|
||||||
using pointer = void;
|
|
||||||
using reference = void;
|
|
||||||
using _Unchecked_type = counting_iterator; // Mark iterator as checked.
|
|
||||||
|
|
||||||
struct value_type {
|
|
||||||
template <typename T> void operator=(const T&) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
counting_iterator() : count_(0) {}
|
|
||||||
|
|
||||||
size_t count() const { return count_; }
|
|
||||||
|
|
||||||
counting_iterator& operator++() {
|
|
||||||
++count_;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
counting_iterator operator++(int) {
|
|
||||||
auto it = *this;
|
|
||||||
++*this;
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend counting_iterator operator+(counting_iterator it, difference_type n) {
|
|
||||||
it.count_ += static_cast<size_t>(n);
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type operator*() const { return {}; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char, typename InputIt>
|
template <typename Char, typename InputIt>
|
||||||
inline counting_iterator copy_str(InputIt begin, InputIt end,
|
inline counting_iterator copy_str(InputIt begin, InputIt end,
|
||||||
counting_iterator it) {
|
counting_iterator it) {
|
||||||
@ -75,8 +36,7 @@ template <typename OutputIt> class truncating_iterator_base {
|
|||||||
using difference_type = std::ptrdiff_t;
|
using difference_type = std::ptrdiff_t;
|
||||||
using pointer = void;
|
using pointer = void;
|
||||||
using reference = void;
|
using reference = void;
|
||||||
using _Unchecked_type =
|
FMT_UNCHECKED_ITERATOR(truncating_iterator_base);
|
||||||
truncating_iterator_base; // Mark iterator as checked.
|
|
||||||
|
|
||||||
OutputIt base() const { return out_; }
|
OutputIt base() const { return out_; }
|
||||||
size_t count() const { return count_; }
|
size_t count() const { return count_; }
|
||||||
@ -163,12 +123,12 @@ struct is_compiled_string : std::is_base_of<compiled_string, S> {};
|
|||||||
# define FMT_COMPILE(s) FMT_STRING(s)
|
# define FMT_COMPILE(s) FMT_STRING(s)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||||
template <typename Char, size_t N,
|
template <typename Char, size_t N,
|
||||||
fmt::detail_exported::fixed_string<Char, N> Str>
|
fmt::detail_exported::fixed_string<Char, N> Str>
|
||||||
struct udl_compiled_string : compiled_string {
|
struct udl_compiled_string : compiled_string {
|
||||||
using char_type = Char;
|
using char_type = Char;
|
||||||
constexpr operator basic_string_view<char_type>() const {
|
explicit constexpr operator basic_string_view<char_type>() const {
|
||||||
return {Str.data, N - 1};
|
return {Str.data, N - 1};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -377,7 +337,8 @@ template <typename T, typename Char>
|
|||||||
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
|
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
|
||||||
size_t pos, int next_arg_id) {
|
size_t pos, int next_arg_id) {
|
||||||
str.remove_prefix(pos);
|
str.remove_prefix(pos);
|
||||||
auto ctx = basic_format_parse_context<Char>(str, {}, next_arg_id);
|
auto ctx = compile_parse_context<Char>(str, max_value<int>(), nullptr, {},
|
||||||
|
next_arg_id);
|
||||||
auto f = formatter<T, Char>();
|
auto f = formatter<T, Char>();
|
||||||
auto end = f.parse(ctx);
|
auto end = f.parse(ctx);
|
||||||
return {f, pos + fmt::detail::to_unsigned(end - str.data()) + 1,
|
return {f, pos + fmt::detail::to_unsigned(end - str.data()) + 1,
|
||||||
@ -573,10 +534,11 @@ FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
|
|||||||
constexpr auto compiled = detail::compile<Args...>(S());
|
constexpr auto compiled = detail::compile<Args...>(S());
|
||||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||||
detail::unknown_format>()) {
|
detail::unknown_format>()) {
|
||||||
return format(static_cast<basic_string_view<typename S::char_type>>(S()),
|
return fmt::format(
|
||||||
std::forward<Args>(args)...);
|
static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
} else {
|
} else {
|
||||||
return format(compiled, std::forward<Args>(args)...);
|
return fmt::format(compiled, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -586,11 +548,11 @@ FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
|
|||||||
constexpr auto compiled = detail::compile<Args...>(S());
|
constexpr auto compiled = detail::compile<Args...>(S());
|
||||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||||
detail::unknown_format>()) {
|
detail::unknown_format>()) {
|
||||||
return format_to(out,
|
return fmt::format_to(
|
||||||
static_cast<basic_string_view<typename S::char_type>>(S()),
|
out, static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||||
std::forward<Args>(args)...);
|
std::forward<Args>(args)...);
|
||||||
} else {
|
} else {
|
||||||
return format_to(out, compiled, std::forward<Args>(args)...);
|
return fmt::format_to(out, compiled, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -599,22 +561,23 @@ template <typename OutputIt, typename S, typename... Args,
|
|||||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
|
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
|
||||||
const S& format_str, Args&&... args) {
|
const S& format_str, Args&&... args) {
|
||||||
auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), format_str,
|
auto it = fmt::format_to(detail::truncating_iterator<OutputIt>(out, n),
|
||||||
std::forward<Args>(args)...);
|
format_str, std::forward<Args>(args)...);
|
||||||
return {it.base(), it.count()};
|
return {it.base(), it.count()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename... Args,
|
template <typename S, typename... Args,
|
||||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
size_t formatted_size(const S& format_str, const Args&... args) {
|
size_t formatted_size(const S& format_str, const Args&... args) {
|
||||||
return format_to(detail::counting_iterator(), format_str, args...).count();
|
return fmt::format_to(detail::counting_iterator(), format_str, args...)
|
||||||
|
.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename... Args,
|
template <typename S, typename... Args,
|
||||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
void print(std::FILE* f, const S& format_str, const Args&... args) {
|
void print(std::FILE* f, const S& format_str, const Args&... args) {
|
||||||
memory_buffer buffer;
|
memory_buffer buffer;
|
||||||
format_to(std::back_inserter(buffer), format_str, args...);
|
fmt::format_to(std::back_inserter(buffer), format_str, args...);
|
||||||
detail::print(f, {buffer.data(), buffer.size()});
|
detail::print(f, {buffer.data(), buffer.size()});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -624,14 +587,12 @@ void print(const S& format_str, const Args&... args) {
|
|||||||
print(stdout, format_str, args...);
|
print(stdout, format_str, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||||
inline namespace literals {
|
inline namespace literals {
|
||||||
template <detail_exported::fixed_string Str>
|
template <detail_exported::fixed_string Str> constexpr auto operator""_cf() {
|
||||||
constexpr detail::udl_compiled_string<
|
using char_t = remove_cvref_t<decltype(Str.data[0])>;
|
||||||
remove_cvref_t<decltype(Str.data[0])>,
|
return detail::udl_compiled_string<char_t, sizeof(Str.data) / sizeof(char_t),
|
||||||
sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str>
|
Str>();
|
||||||
operator""_cf() {
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
} // namespace literals
|
} // namespace literals
|
||||||
#endif
|
#endif
|
||||||
|
804
externals/dynarmic/externals/fmt/include/fmt/core.h
vendored
804
externals/dynarmic/externals/fmt/include/fmt/core.h
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1888
externals/dynarmic/externals/fmt/include/fmt/format.h
vendored
1888
externals/dynarmic/externals/fmt/include/fmt/format.h
vendored
File diff suppressed because it is too large
Load Diff
101
externals/dynarmic/externals/fmt/include/fmt/os.h
vendored
101
externals/dynarmic/externals/fmt/include/fmt/os.h
vendored
@ -9,10 +9,8 @@
|
|||||||
#define FMT_OS_H_
|
#define FMT_OS_H_
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <clocale> // locale_t
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib> // strtod_l
|
|
||||||
#include <system_error> // std::system_error
|
#include <system_error> // std::system_error
|
||||||
|
|
||||||
#if defined __APPLE__ || defined(__FreeBSD__)
|
#if defined __APPLE__ || defined(__FreeBSD__)
|
||||||
@ -141,7 +139,7 @@ template <typename Char> struct formatter<std::error_code, Char> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
FMT_API const std::error_category& system_category() FMT_NOEXCEPT;
|
FMT_API const std::error_category& system_category() noexcept;
|
||||||
|
|
||||||
FMT_BEGIN_DETAIL_NAMESPACE
|
FMT_BEGIN_DETAIL_NAMESPACE
|
||||||
// A converter from UTF-16 to UTF-8.
|
// A converter from UTF-16 to UTF-8.
|
||||||
@ -165,7 +163,7 @@ class utf16_to_utf8 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
FMT_API void format_windows_error(buffer<char>& out, int error_code,
|
FMT_API void format_windows_error(buffer<char>& out, int error_code,
|
||||||
const char* message) FMT_NOEXCEPT;
|
const char* message) noexcept;
|
||||||
FMT_END_DETAIL_NAMESPACE
|
FMT_END_DETAIL_NAMESPACE
|
||||||
|
|
||||||
FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
|
FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
|
||||||
@ -207,10 +205,9 @@ std::system_error windows_error(int error_code, string_view message,
|
|||||||
|
|
||||||
// Reports a Windows error without throwing an exception.
|
// Reports a Windows error without throwing an exception.
|
||||||
// Can be used to report errors from destructors.
|
// Can be used to report errors from destructors.
|
||||||
FMT_API void report_windows_error(int error_code,
|
FMT_API void report_windows_error(int error_code, const char* message) noexcept;
|
||||||
const char* message) FMT_NOEXCEPT;
|
|
||||||
#else
|
#else
|
||||||
inline const std::error_category& system_category() FMT_NOEXCEPT {
|
inline const std::error_category& system_category() noexcept {
|
||||||
return std::system_category();
|
return std::system_category();
|
||||||
}
|
}
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
@ -237,13 +234,13 @@ class buffered_file {
|
|||||||
void operator=(const buffered_file&) = delete;
|
void operator=(const buffered_file&) = delete;
|
||||||
|
|
||||||
// Constructs a buffered_file object which doesn't represent any file.
|
// Constructs a buffered_file object which doesn't represent any file.
|
||||||
buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
|
buffered_file() noexcept : file_(nullptr) {}
|
||||||
|
|
||||||
// Destroys the object closing the file it represents if any.
|
// Destroys the object closing the file it represents if any.
|
||||||
FMT_API ~buffered_file() FMT_NOEXCEPT;
|
FMT_API ~buffered_file() noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
|
buffered_file(buffered_file&& other) noexcept : file_(other.file_) {
|
||||||
other.file_ = nullptr;
|
other.file_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,11 +258,9 @@ class buffered_file {
|
|||||||
FMT_API void close();
|
FMT_API void close();
|
||||||
|
|
||||||
// Returns the pointer to a FILE object representing this file.
|
// Returns the pointer to a FILE object representing this file.
|
||||||
FILE* get() const FMT_NOEXCEPT { return file_; }
|
FILE* get() const noexcept { return file_; }
|
||||||
|
|
||||||
// We place parentheses around fileno to workaround a bug in some versions
|
FMT_API int descriptor() const;
|
||||||
// of MinGW that define fileno as a macro.
|
|
||||||
FMT_API int(fileno)() const;
|
|
||||||
|
|
||||||
void vprint(string_view format_str, format_args args) {
|
void vprint(string_view format_str, format_args args) {
|
||||||
fmt::vprint(file_, format_str, args);
|
fmt::vprint(file_, format_str, args);
|
||||||
@ -279,12 +274,12 @@ class buffered_file {
|
|||||||
|
|
||||||
#if FMT_USE_FCNTL
|
#if FMT_USE_FCNTL
|
||||||
// A file. Closed file is represented by a file object with descriptor -1.
|
// A file. Closed file is represented by a file object with descriptor -1.
|
||||||
// Methods that are not declared with FMT_NOEXCEPT may throw
|
// Methods that are not declared with noexcept may throw
|
||||||
// fmt::system_error in case of failure. Note that some errors such as
|
// fmt::system_error in case of failure. Note that some errors such as
|
||||||
// closing the file multiple times will cause a crash on Windows rather
|
// closing the file multiple times will cause a crash on Windows rather
|
||||||
// than an exception. You can get standard behavior by overriding the
|
// than an exception. You can get standard behavior by overriding the
|
||||||
// invalid parameter handler with _set_invalid_parameter_handler.
|
// invalid parameter handler with _set_invalid_parameter_handler.
|
||||||
class file {
|
class FMT_API file {
|
||||||
private:
|
private:
|
||||||
int fd_; // File descriptor.
|
int fd_; // File descriptor.
|
||||||
|
|
||||||
@ -303,16 +298,16 @@ class file {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Constructs a file object which doesn't represent any file.
|
// Constructs a file object which doesn't represent any file.
|
||||||
file() FMT_NOEXCEPT : fd_(-1) {}
|
file() noexcept : fd_(-1) {}
|
||||||
|
|
||||||
// Opens a file and constructs a file object representing this file.
|
// Opens a file and constructs a file object representing this file.
|
||||||
FMT_API file(cstring_view path, int oflag);
|
file(cstring_view path, int oflag);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
file(const file&) = delete;
|
file(const file&) = delete;
|
||||||
void operator=(const file&) = delete;
|
void operator=(const file&) = delete;
|
||||||
|
|
||||||
file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
|
file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }
|
||||||
|
|
||||||
// Move assignment is not noexcept because close may throw.
|
// Move assignment is not noexcept because close may throw.
|
||||||
file& operator=(file&& other) {
|
file& operator=(file&& other) {
|
||||||
@ -323,43 +318,43 @@ class file {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Destroys the object closing the file it represents if any.
|
// Destroys the object closing the file it represents if any.
|
||||||
FMT_API ~file() FMT_NOEXCEPT;
|
~file() noexcept;
|
||||||
|
|
||||||
// Returns the file descriptor.
|
// Returns the file descriptor.
|
||||||
int descriptor() const FMT_NOEXCEPT { return fd_; }
|
int descriptor() const noexcept { return fd_; }
|
||||||
|
|
||||||
// Closes the file.
|
// Closes the file.
|
||||||
FMT_API void close();
|
void close();
|
||||||
|
|
||||||
// Returns the file size. The size has signed type for consistency with
|
// Returns the file size. The size has signed type for consistency with
|
||||||
// stat::st_size.
|
// stat::st_size.
|
||||||
FMT_API long long size() const;
|
long long size() const;
|
||||||
|
|
||||||
// Attempts to read count bytes from the file into the specified buffer.
|
// Attempts to read count bytes from the file into the specified buffer.
|
||||||
FMT_API size_t read(void* buffer, size_t count);
|
size_t read(void* buffer, size_t count);
|
||||||
|
|
||||||
// Attempts to write count bytes from the specified buffer to the file.
|
// Attempts to write count bytes from the specified buffer to the file.
|
||||||
FMT_API size_t write(const void* buffer, size_t count);
|
size_t write(const void* buffer, size_t count);
|
||||||
|
|
||||||
// Duplicates a file descriptor with the dup function and returns
|
// Duplicates a file descriptor with the dup function and returns
|
||||||
// the duplicate as a file object.
|
// the duplicate as a file object.
|
||||||
FMT_API static file dup(int fd);
|
static file dup(int fd);
|
||||||
|
|
||||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||||
// necessary.
|
// necessary.
|
||||||
FMT_API void dup2(int fd);
|
void dup2(int fd);
|
||||||
|
|
||||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||||
// necessary.
|
// necessary.
|
||||||
FMT_API void dup2(int fd, std::error_code& ec) FMT_NOEXCEPT;
|
void dup2(int fd, std::error_code& ec) noexcept;
|
||||||
|
|
||||||
// Creates a pipe setting up read_end and write_end file objects for reading
|
// Creates a pipe setting up read_end and write_end file objects for reading
|
||||||
// and writing respectively.
|
// and writing respectively.
|
||||||
FMT_API static void pipe(file& read_end, file& write_end);
|
static void pipe(file& read_end, file& write_end);
|
||||||
|
|
||||||
// Creates a buffered_file object associated with this file and detaches
|
// Creates a buffered_file object associated with this file and detaches
|
||||||
// this file object from the file.
|
// this file object from the file.
|
||||||
FMT_API buffered_file fdopen(const char* mode);
|
buffered_file fdopen(const char* mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns the memory page size.
|
// Returns the memory page size.
|
||||||
@ -462,7 +457,7 @@ class FMT_API ostream final : private detail::buffer<char> {
|
|||||||
|
|
||||||
* ``<integer>``: Flags passed to `open
|
* ``<integer>``: Flags passed to `open
|
||||||
<https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
|
<https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
|
||||||
(``file::WRONLY | file::CREATE`` by default)
|
(``file::WRONLY | file::CREATE | file::TRUNC`` by default)
|
||||||
* ``buffer_size=<integer>``: Output buffer size
|
* ``buffer_size=<integer>``: Output buffer size
|
||||||
|
|
||||||
**Example**::
|
**Example**::
|
||||||
@ -477,50 +472,6 @@ inline ostream output_file(cstring_view path, T... params) {
|
|||||||
}
|
}
|
||||||
#endif // FMT_USE_FCNTL
|
#endif // FMT_USE_FCNTL
|
||||||
|
|
||||||
#ifdef FMT_LOCALE
|
|
||||||
// A "C" numeric locale.
|
|
||||||
class locale {
|
|
||||||
private:
|
|
||||||
# ifdef _WIN32
|
|
||||||
using locale_t = _locale_t;
|
|
||||||
|
|
||||||
static void freelocale(locale_t loc) { _free_locale(loc); }
|
|
||||||
|
|
||||||
static double strtod_l(const char* nptr, char** endptr, _locale_t loc) {
|
|
||||||
return _strtod_l(nptr, endptr, loc);
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
locale_t locale_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using type = locale_t;
|
|
||||||
locale(const locale&) = delete;
|
|
||||||
void operator=(const locale&) = delete;
|
|
||||||
|
|
||||||
locale() {
|
|
||||||
# ifndef _WIN32
|
|
||||||
locale_ = FMT_SYSTEM(newlocale(LC_NUMERIC_MASK, "C", nullptr));
|
|
||||||
# else
|
|
||||||
locale_ = _create_locale(LC_NUMERIC, "C");
|
|
||||||
# endif
|
|
||||||
if (!locale_) FMT_THROW(system_error(errno, "cannot create locale"));
|
|
||||||
}
|
|
||||||
~locale() { freelocale(locale_); }
|
|
||||||
|
|
||||||
type get() const { return locale_; }
|
|
||||||
|
|
||||||
// Converts string to floating-point number and advances str past the end
|
|
||||||
// of the parsed input.
|
|
||||||
FMT_DEPRECATED double strtod(const char*& str) const {
|
|
||||||
char* end = nullptr;
|
|
||||||
double result = strtod_l(str, &end, locale_);
|
|
||||||
str = end;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
using Locale FMT_DEPRECATED_ALIAS = locale;
|
|
||||||
#endif // FMT_LOCALE
|
|
||||||
FMT_MODULE_EXPORT_END
|
FMT_MODULE_EXPORT_END
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#ifndef FMT_OSTREAM_H_
|
#ifndef FMT_OSTREAM_H_
|
||||||
#define FMT_OSTREAM_H_
|
#define FMT_OSTREAM_H_
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
@ -45,15 +46,59 @@ struct is_streamable<
|
|||||||
enable_if_t<
|
enable_if_t<
|
||||||
std::is_arithmetic<T>::value || std::is_array<T>::value ||
|
std::is_arithmetic<T>::value || std::is_array<T>::value ||
|
||||||
std::is_pointer<T>::value || std::is_same<T, char8_type>::value ||
|
std::is_pointer<T>::value || std::is_same<T, char8_type>::value ||
|
||||||
std::is_same<T, std::basic_string<Char>>::value ||
|
std::is_convertible<T, fmt::basic_string_view<Char>>::value ||
|
||||||
std::is_same<T, std_string_view<Char>>::value ||
|
std::is_same<T, std_string_view<Char>>::value ||
|
||||||
(std::is_convertible<T, int>::value && !std::is_enum<T>::value)>>
|
(std::is_convertible<T, int>::value && !std::is_enum<T>::value)>>
|
||||||
: std::false_type {};
|
: std::false_type {};
|
||||||
|
|
||||||
|
template <typename Char> FILE* get_file(std::basic_filebuf<Char>&) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dummy_filebuf {
|
||||||
|
FILE* _Myfile;
|
||||||
|
};
|
||||||
|
template <typename T, typename U = int> struct ms_filebuf {
|
||||||
|
using type = dummy_filebuf;
|
||||||
|
};
|
||||||
|
template <typename T> struct ms_filebuf<T, decltype(T::_Myfile, 0)> {
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
using filebuf_type = ms_filebuf<std::filebuf>::type;
|
||||||
|
|
||||||
|
FILE* get_file(filebuf_type& buf);
|
||||||
|
|
||||||
|
// Generate a unique explicit instantion in every translation unit using a tag
|
||||||
|
// type in an anonymous namespace.
|
||||||
|
namespace {
|
||||||
|
struct filebuf_access_tag {};
|
||||||
|
} // namespace
|
||||||
|
template <typename Tag, typename FileMemberPtr, FileMemberPtr file>
|
||||||
|
class filebuf_access {
|
||||||
|
friend FILE* get_file(filebuf_type& buf) { return buf.*file; }
|
||||||
|
};
|
||||||
|
template class filebuf_access<filebuf_access_tag,
|
||||||
|
decltype(&filebuf_type::_Myfile),
|
||||||
|
&filebuf_type::_Myfile>;
|
||||||
|
|
||||||
|
inline bool write(std::filebuf& buf, fmt::string_view data) {
|
||||||
|
FILE* f = get_file(buf);
|
||||||
|
if (!f) return false;
|
||||||
|
print(f, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
inline bool write(std::wfilebuf&, fmt::basic_string_view<wchar_t>) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Write the content of buf to os.
|
// Write the content of buf to os.
|
||||||
// It is a separate function rather than a part of vprint to simplify testing.
|
// It is a separate function rather than a part of vprint to simplify testing.
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
||||||
|
if (const_check(FMT_MSC_VERSION)) {
|
||||||
|
auto filebuf = dynamic_cast<std::basic_filebuf<Char>*>(os.rdbuf());
|
||||||
|
if (filebuf && write(*filebuf, {buf.data(), buf.size()})) return;
|
||||||
|
}
|
||||||
const Char* buf_data = buf.data();
|
const Char* buf_data = buf.data();
|
||||||
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
|
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
|
||||||
unsigned_streamsize size = buf.size();
|
unsigned_streamsize size = buf.size();
|
||||||
@ -76,38 +121,65 @@ void format_value(buffer<Char>& buf, const T& value,
|
|||||||
#endif
|
#endif
|
||||||
output << value;
|
output << value;
|
||||||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||||
buf.try_resize(buf.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formats an object of type T that has an overloaded ostream operator<<.
|
template <typename T> struct streamed_view { const T& value; };
|
||||||
template <typename T, typename Char>
|
|
||||||
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
|
|
||||||
: private formatter<basic_string_view<Char>, Char> {
|
|
||||||
using formatter<basic_string_view<Char>, Char>::parse;
|
|
||||||
|
|
||||||
template <typename OutputIt>
|
} // namespace detail
|
||||||
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx)
|
|
||||||
|
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||||
|
template <typename Char>
|
||||||
|
struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
|
||||||
|
template <typename T, typename OutputIt>
|
||||||
|
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const
|
||||||
-> OutputIt {
|
-> OutputIt {
|
||||||
auto buffer = basic_memory_buffer<Char>();
|
auto buffer = basic_memory_buffer<Char>();
|
||||||
format_value(buffer, value, ctx.locale());
|
format_value(buffer, value, ctx.locale());
|
||||||
return formatter<basic_string_view<Char>, Char>::format(
|
return formatter<basic_string_view<Char>, Char>::format(
|
||||||
{buffer.data(), buffer.size()}, ctx);
|
{buffer.data(), buffer.size()}, ctx);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// DEPRECATED!
|
using ostream_formatter = basic_ostream_formatter<char>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct formatter<detail::streamed_view<T>> : ostream_formatter {
|
||||||
template <typename OutputIt>
|
template <typename OutputIt>
|
||||||
auto format(const T& value, basic_printf_context<OutputIt, Char>& ctx)
|
auto format(detail::streamed_view<T> view,
|
||||||
-> OutputIt {
|
basic_format_context<OutputIt, char>& ctx) const -> OutputIt {
|
||||||
auto buffer = basic_memory_buffer<Char>();
|
return ostream_formatter::format(view.value, ctx);
|
||||||
format_value(buffer, value, ctx.locale());
|
|
||||||
return std::copy(buffer.begin(), buffer.end(), ctx.out());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Returns a view that formats `value` via an ostream ``operator<<``.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
fmt::print("Current thread id: {}\n",
|
||||||
|
fmt::streamed(std::this_thread::get_id()));
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
auto streamed(const T& value) -> detail::streamed_view<T> {
|
||||||
|
return {value};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||||
|
template <typename T, typename Char>
|
||||||
|
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
|
||||||
|
: basic_ostream_formatter<Char> {
|
||||||
|
using basic_ostream_formatter<Char>::format;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
FMT_MODULE_EXPORT
|
FMT_MODULE_EXPORT template <typename Char>
|
||||||
template <typename Char>
|
void vprint(std::basic_ostream<Char>& os,
|
||||||
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
|
basic_string_view<type_identity_t<Char>> format_str,
|
||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
auto buffer = basic_memory_buffer<Char>();
|
auto buffer = basic_memory_buffer<Char>();
|
||||||
detail::vformat_to(buffer, format_str, args);
|
detail::vformat_to(buffer, format_str, args);
|
||||||
@ -123,13 +195,19 @@ void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
|
|||||||
fmt::print(cerr, "Don't {}!", "panic");
|
fmt::print(cerr, "Don't {}!", "panic");
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
FMT_MODULE_EXPORT
|
FMT_MODULE_EXPORT template <typename... T>
|
||||||
template <typename S, typename... Args,
|
void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
|
||||||
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
vprint(os, fmt, fmt::make_format_args(args...));
|
||||||
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
|
|
||||||
vprint(os, to_string_view(format_str),
|
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FMT_MODULE_EXPORT
|
||||||
|
template <typename... Args>
|
||||||
|
void print(std::wostream& os,
|
||||||
|
basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
|
||||||
|
Args&&... args) {
|
||||||
|
vprint(os, fmt, fmt::make_format_args<buffer_context<wchar_t>>(args...));
|
||||||
|
}
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_OSTREAM_H_
|
#endif // FMT_OSTREAM_H_
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#include <algorithm> // std::max
|
#include <algorithm> // std::max
|
||||||
#include <limits> // std::numeric_limits
|
#include <limits> // std::numeric_limits
|
||||||
#include <ostream>
|
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
@ -561,7 +560,7 @@ inline auto vsprintf(
|
|||||||
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
|
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
|
||||||
-> std::basic_string<Char> {
|
-> std::basic_string<Char> {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
vprintf(buffer, to_string_view(fmt), args);
|
vprintf(buffer, detail::to_string_view(fmt), args);
|
||||||
return to_string(buffer);
|
return to_string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,7 +577,8 @@ template <typename S, typename... T,
|
|||||||
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
||||||
inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> {
|
inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> {
|
||||||
using context = basic_printf_context_t<Char>;
|
using context = basic_printf_context_t<Char>;
|
||||||
return vsprintf(to_string_view(fmt), fmt::make_format_args<context>(args...));
|
return vsprintf(detail::to_string_view(fmt),
|
||||||
|
fmt::make_format_args<context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
template <typename S, typename Char = char_t<S>>
|
||||||
@ -587,7 +587,7 @@ inline auto vfprintf(
|
|||||||
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
|
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
|
||||||
-> int {
|
-> int {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
vprintf(buffer, to_string_view(fmt), args);
|
vprintf(buffer, detail::to_string_view(fmt), args);
|
||||||
size_t size = buffer.size();
|
size_t size = buffer.size();
|
||||||
return std::fwrite(buffer.data(), sizeof(Char), size, f) < size
|
return std::fwrite(buffer.data(), sizeof(Char), size, f) < size
|
||||||
? -1
|
? -1
|
||||||
@ -606,7 +606,7 @@ inline auto vfprintf(
|
|||||||
template <typename S, typename... T, typename Char = char_t<S>>
|
template <typename S, typename... T, typename Char = char_t<S>>
|
||||||
inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int {
|
inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int {
|
||||||
using context = basic_printf_context_t<Char>;
|
using context = basic_printf_context_t<Char>;
|
||||||
return vfprintf(f, to_string_view(fmt),
|
return vfprintf(f, detail::to_string_view(fmt),
|
||||||
fmt::make_format_args<context>(args...));
|
fmt::make_format_args<context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,7 +615,7 @@ inline auto vprintf(
|
|||||||
const S& fmt,
|
const S& fmt,
|
||||||
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
|
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
|
||||||
-> int {
|
-> int {
|
||||||
return vfprintf(stdout, to_string_view(fmt), args);
|
return vfprintf(stdout, detail::to_string_view(fmt), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -630,27 +630,10 @@ inline auto vprintf(
|
|||||||
template <typename S, typename... T, FMT_ENABLE_IF(detail::is_string<S>::value)>
|
template <typename S, typename... T, FMT_ENABLE_IF(detail::is_string<S>::value)>
|
||||||
inline auto printf(const S& fmt, const T&... args) -> int {
|
inline auto printf(const S& fmt, const T&... args) -> int {
|
||||||
return vprintf(
|
return vprintf(
|
||||||
to_string_view(fmt),
|
detail::to_string_view(fmt),
|
||||||
fmt::make_format_args<basic_printf_context_t<char_t<S>>>(args...));
|
fmt::make_format_args<basic_printf_context_t<char_t<S>>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
|
||||||
FMT_DEPRECATED auto vfprintf(
|
|
||||||
std::basic_ostream<Char>& os, const S& fmt,
|
|
||||||
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
|
|
||||||
-> int {
|
|
||||||
basic_memory_buffer<Char> buffer;
|
|
||||||
vprintf(buffer, to_string_view(fmt), args);
|
|
||||||
os.write(buffer.data(), static_cast<std::streamsize>(buffer.size()));
|
|
||||||
return static_cast<int>(buffer.size());
|
|
||||||
}
|
|
||||||
template <typename S, typename... T, typename Char = char_t<S>>
|
|
||||||
FMT_DEPRECATED auto fprintf(std::basic_ostream<Char>& os, const S& fmt,
|
|
||||||
const T&... args) -> int {
|
|
||||||
return vfprintf(os, to_string_view(fmt),
|
|
||||||
fmt::make_format_args<basic_printf_context_t<Char>>(args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_END
|
FMT_MODULE_EXPORT_END
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ template <typename T> class is_std_string_like {
|
|||||||
template <typename> static void check(...);
|
template <typename> static void check(...);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static constexpr const bool value =
|
||||||
is_string<T>::value ||
|
is_string<T>::value ||
|
||||||
std::is_convertible<T, std_string_view<char>>::value ||
|
std::is_convertible<T, std_string_view<char>>::value ||
|
||||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||||
@ -70,9 +70,9 @@ template <typename T> class is_map {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
#ifdef FMT_FORMAT_MAP_AS_LIST
|
#ifdef FMT_FORMAT_MAP_AS_LIST
|
||||||
static FMT_CONSTEXPR_DECL const bool value = false;
|
static constexpr const bool value = false;
|
||||||
#else
|
#else
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static constexpr const bool value =
|
||||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
@ -83,9 +83,9 @@ template <typename T> class is_set {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
#ifdef FMT_FORMAT_SET_AS_LIST
|
#ifdef FMT_FORMAT_SET_AS_LIST
|
||||||
static FMT_CONSTEXPR_DECL const bool value = false;
|
static constexpr const bool value = false;
|
||||||
#else
|
#else
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static constexpr const bool value =
|
||||||
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
|
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
@ -94,7 +94,7 @@ template <typename... Ts> struct conditional_helper {};
|
|||||||
|
|
||||||
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
||||||
|
|
||||||
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
|
#if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1800
|
||||||
|
|
||||||
# define FMT_DECLTYPE_RETURN(val) \
|
# define FMT_DECLTYPE_RETURN(val) \
|
||||||
->decltype(val) { return val; } \
|
->decltype(val) { return val; } \
|
||||||
@ -174,12 +174,12 @@ template <typename T> class is_tuple_like_ {
|
|||||||
template <typename> static void check(...);
|
template <typename> static void check(...);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static constexpr const bool value =
|
||||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check for integer_sequence
|
// Check for integer_sequence
|
||||||
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
|
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900
|
||||||
template <typename T, T... N>
|
template <typename T, T... N>
|
||||||
using integer_sequence = std::integer_sequence<T, N...>;
|
using integer_sequence = std::integer_sequence<T, N...>;
|
||||||
template <size_t... N> using index_sequence = std::index_sequence<N...>;
|
template <size_t... N> using index_sequence = std::index_sequence<N...>;
|
||||||
@ -202,8 +202,33 @@ template <size_t N>
|
|||||||
using make_index_sequence = make_integer_sequence<size_t, N>;
|
using make_index_sequence = make_integer_sequence<size_t, N>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>;
|
||||||
|
|
||||||
|
template <typename T, typename C, bool = is_tuple_like_<T>::value>
|
||||||
|
class is_tuple_formattable_ {
|
||||||
|
public:
|
||||||
|
static constexpr const bool value = false;
|
||||||
|
};
|
||||||
|
template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
|
||||||
|
template <std::size_t... I>
|
||||||
|
static std::true_type check2(index_sequence<I...>,
|
||||||
|
integer_sequence<bool, (I == I)...>);
|
||||||
|
static std::false_type check2(...);
|
||||||
|
template <std::size_t... I>
|
||||||
|
static decltype(check2(
|
||||||
|
index_sequence<I...>{},
|
||||||
|
integer_sequence<
|
||||||
|
bool, (is_formattable<typename std::tuple_element<I, T>::type,
|
||||||
|
C>::value)...>{})) check(index_sequence<I...>);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr const bool value =
|
||||||
|
decltype(check(tuple_index_sequence<T>{}))::value;
|
||||||
|
};
|
||||||
|
|
||||||
template <class Tuple, class F, size_t... Is>
|
template <class Tuple, class F, size_t... Is>
|
||||||
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) FMT_NOEXCEPT {
|
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) noexcept {
|
||||||
using std::get;
|
using std::get;
|
||||||
// using free function get<I>(T) now.
|
// using free function get<I>(T) now.
|
||||||
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
|
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
|
||||||
@ -221,9 +246,36 @@ template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
|
|||||||
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
|
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920
|
||||||
|
// Older MSVC doesn't get the reference type correctly for arrays.
|
||||||
|
template <typename R> struct range_reference_type_impl {
|
||||||
|
using type = decltype(*detail::range_begin(std::declval<R&>()));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> {
|
||||||
|
using type = T&;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using range_reference_type = typename range_reference_type_impl<T>::type;
|
||||||
|
#else
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
using value_type =
|
using range_reference_type =
|
||||||
remove_cvref_t<decltype(*detail::range_begin(std::declval<Range>()))>;
|
decltype(*detail::range_begin(std::declval<Range&>()));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// We don't use the Range's value_type for anything, but we do need the Range's
|
||||||
|
// reference type, with cv-ref stripped.
|
||||||
|
template <typename Range>
|
||||||
|
using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
|
||||||
|
|
||||||
|
template <typename Range>
|
||||||
|
using uncvref_first_type = remove_cvref_t<
|
||||||
|
decltype(std::declval<range_reference_type<Range>>().first)>;
|
||||||
|
|
||||||
|
template <typename Range>
|
||||||
|
using uncvref_second_type = remove_cvref_t<
|
||||||
|
decltype(std::declval<range_reference_type<Range>>().second)>;
|
||||||
|
|
||||||
template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
|
template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
|
||||||
*out++ = ',';
|
*out++ = ',';
|
||||||
@ -231,286 +283,9 @@ template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct singleton {
|
|
||||||
unsigned char upper;
|
|
||||||
unsigned char lower_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline auto is_printable(uint16_t x, const singleton* singletons,
|
|
||||||
size_t singletons_size,
|
|
||||||
const unsigned char* singleton_lowers,
|
|
||||||
const unsigned char* normal, size_t normal_size)
|
|
||||||
-> bool {
|
|
||||||
auto upper = x >> 8;
|
|
||||||
auto lower_start = 0;
|
|
||||||
for (size_t i = 0; i < singletons_size; ++i) {
|
|
||||||
auto s = singletons[i];
|
|
||||||
auto lower_end = lower_start + s.lower_count;
|
|
||||||
if (upper < s.upper) break;
|
|
||||||
if (upper == s.upper) {
|
|
||||||
for (auto j = lower_start; j < lower_end; ++j) {
|
|
||||||
if (singleton_lowers[j] == (x & 0xff)) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lower_start = lower_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto xsigned = static_cast<int>(x);
|
|
||||||
auto current = true;
|
|
||||||
for (size_t i = 0; i < normal_size; ++i) {
|
|
||||||
auto v = static_cast<int>(normal[i]);
|
|
||||||
auto len = (v & 0x80) != 0 ? (v & 0x7f) << 8 | normal[++i] : v;
|
|
||||||
xsigned -= len;
|
|
||||||
if (xsigned < 0) break;
|
|
||||||
current = !current;
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true iff the code point cp is printable.
|
|
||||||
// This code is generated by support/printable.py.
|
|
||||||
inline auto is_printable(uint32_t cp) -> bool {
|
|
||||||
static constexpr singleton singletons0[] = {
|
|
||||||
{0x00, 1}, {0x03, 5}, {0x05, 6}, {0x06, 3}, {0x07, 6}, {0x08, 8},
|
|
||||||
{0x09, 17}, {0x0a, 28}, {0x0b, 25}, {0x0c, 20}, {0x0d, 16}, {0x0e, 13},
|
|
||||||
{0x0f, 4}, {0x10, 3}, {0x12, 18}, {0x13, 9}, {0x16, 1}, {0x17, 5},
|
|
||||||
{0x18, 2}, {0x19, 3}, {0x1a, 7}, {0x1c, 2}, {0x1d, 1}, {0x1f, 22},
|
|
||||||
{0x20, 3}, {0x2b, 3}, {0x2c, 2}, {0x2d, 11}, {0x2e, 1}, {0x30, 3},
|
|
||||||
{0x31, 2}, {0x32, 1}, {0xa7, 2}, {0xa9, 2}, {0xaa, 4}, {0xab, 8},
|
|
||||||
{0xfa, 2}, {0xfb, 5}, {0xfd, 4}, {0xfe, 3}, {0xff, 9},
|
|
||||||
};
|
|
||||||
static constexpr unsigned char singletons0_lower[] = {
|
|
||||||
0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x8b, 0x8c, 0x90,
|
|
||||||
0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f,
|
|
||||||
0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1,
|
|
||||||
0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04,
|
|
||||||
0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, 0x5d,
|
|
||||||
0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf,
|
|
||||||
0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
|
|
||||||
0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d,
|
|
||||||
0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, 0x8d,
|
|
||||||
0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d,
|
|
||||||
0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5,
|
|
||||||
0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7,
|
|
||||||
0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49,
|
|
||||||
0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7,
|
|
||||||
0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7,
|
|
||||||
0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e,
|
|
||||||
0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16,
|
|
||||||
0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e,
|
|
||||||
0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f,
|
|
||||||
0x74, 0x75, 0x96, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf,
|
|
||||||
0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, 0x1f, 0xc0,
|
|
||||||
0xc1, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27,
|
|
||||||
0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91,
|
|
||||||
0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7,
|
|
||||||
0xfe, 0xff,
|
|
||||||
};
|
|
||||||
static constexpr singleton singletons1[] = {
|
|
||||||
{0x00, 6}, {0x01, 1}, {0x03, 1}, {0x04, 2}, {0x08, 8}, {0x09, 2},
|
|
||||||
{0x0a, 5}, {0x0b, 2}, {0x0e, 4}, {0x10, 1}, {0x11, 2}, {0x12, 5},
|
|
||||||
{0x13, 17}, {0x14, 1}, {0x15, 2}, {0x17, 2}, {0x19, 13}, {0x1c, 5},
|
|
||||||
{0x1d, 8}, {0x24, 1}, {0x6a, 3}, {0x6b, 2}, {0xbc, 2}, {0xd1, 2},
|
|
||||||
{0xd4, 12}, {0xd5, 9}, {0xd6, 2}, {0xd7, 2}, {0xda, 1}, {0xe0, 5},
|
|
||||||
{0xe1, 2}, {0xe8, 2}, {0xee, 32}, {0xf0, 4}, {0xf8, 2}, {0xf9, 2},
|
|
||||||
{0xfa, 2}, {0xfb, 1},
|
|
||||||
};
|
|
||||||
static constexpr unsigned char singletons1_lower[] = {
|
|
||||||
0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07,
|
|
||||||
0x09, 0x36, 0x3d, 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36,
|
|
||||||
0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, 0x35, 0xe0, 0x12, 0x87,
|
|
||||||
0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
|
|
||||||
0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5c, 0xb6, 0xb7, 0x1b,
|
|
||||||
0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9,
|
|
||||||
0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66,
|
|
||||||
0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27,
|
|
||||||
0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc,
|
|
||||||
0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7,
|
|
||||||
0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xc5, 0xc6,
|
|
||||||
0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c,
|
|
||||||
0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66,
|
|
||||||
0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0,
|
|
||||||
0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93,
|
|
||||||
};
|
|
||||||
static constexpr unsigned char normal0[] = {
|
|
||||||
0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, 0x1b, 0x04,
|
|
||||||
0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x35, 0x28, 0x0b, 0x80, 0xe0,
|
|
||||||
0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01,
|
|
||||||
0x07, 0x06, 0x07, 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x07, 0x03,
|
|
||||||
0x04, 0x1c, 0x0a, 0x09, 0x03, 0x08, 0x03, 0x07, 0x03, 0x02, 0x03, 0x03,
|
|
||||||
0x03, 0x0c, 0x04, 0x05, 0x03, 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, 0x3a,
|
|
||||||
0x03, 0x11, 0x07, 0x06, 0x05, 0x10, 0x07, 0x57, 0x07, 0x02, 0x07, 0x15,
|
|
||||||
0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, 0x11, 0x06, 0x0f,
|
|
||||||
0x0c, 0x3a, 0x04, 0x1d, 0x25, 0x5f, 0x20, 0x6d, 0x04, 0x6a, 0x25, 0x80,
|
|
||||||
0xc8, 0x05, 0x82, 0xb0, 0x03, 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07,
|
|
||||||
0x15, 0x0b, 0x17, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, 0x0a, 0x06,
|
|
||||||
0x1a, 0x06, 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, 0x0c, 0x04,
|
|
||||||
0x01, 0x03, 0x31, 0x0b, 0x2c, 0x04, 0x1a, 0x06, 0x0b, 0x03, 0x80, 0xac,
|
|
||||||
0x06, 0x0a, 0x06, 0x21, 0x3f, 0x4c, 0x04, 0x2d, 0x03, 0x74, 0x08, 0x3c,
|
|
||||||
0x03, 0x0f, 0x03, 0x3c, 0x07, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11,
|
|
||||||
0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c,
|
|
||||||
0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b,
|
|
||||||
0x07, 0x02, 0x0e, 0x18, 0x09, 0x80, 0xb3, 0x2d, 0x74, 0x0c, 0x80, 0xd6,
|
|
||||||
0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, 0xee, 0x0d, 0x03,
|
|
||||||
0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, 0x80,
|
|
||||||
0xcb, 0x2a, 0x38, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, 0x0c, 0x06,
|
|
||||||
0x74, 0x0b, 0x1e, 0x03, 0x5a, 0x04, 0x59, 0x09, 0x80, 0x83, 0x18, 0x1c,
|
|
||||||
0x0a, 0x16, 0x09, 0x4c, 0x04, 0x80, 0x8a, 0x06, 0xab, 0xa4, 0x0c, 0x17,
|
|
||||||
0x04, 0x31, 0xa1, 0x04, 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, 0x80,
|
|
||||||
0xa5, 0x11, 0x81, 0x6d, 0x10, 0x78, 0x28, 0x2a, 0x06, 0x4c, 0x04, 0x80,
|
|
||||||
0x8d, 0x04, 0x80, 0xbe, 0x03, 0x1b, 0x03, 0x0f, 0x0d,
|
|
||||||
};
|
|
||||||
static constexpr unsigned char normal1[] = {
|
|
||||||
0x5e, 0x22, 0x7b, 0x05, 0x03, 0x04, 0x2d, 0x03, 0x66, 0x03, 0x01, 0x2f,
|
|
||||||
0x2e, 0x80, 0x82, 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, 0x24, 0x09, 0x1e,
|
|
||||||
0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, 0x80, 0xaa, 0x06, 0x24, 0x04,
|
|
||||||
0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, 0x01, 0x80, 0x90, 0x81, 0x37, 0x09,
|
|
||||||
0x16, 0x0a, 0x08, 0x80, 0x98, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, 0x16,
|
|
||||||
0x05, 0x21, 0x03, 0x1b, 0x05, 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, 0x2f,
|
|
||||||
0x04, 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, 0x0c, 0x09, 0x36,
|
|
||||||
0x03, 0x3a, 0x05, 0x1a, 0x07, 0x04, 0x0c, 0x07, 0x50, 0x49, 0x37, 0x33,
|
|
||||||
0x0d, 0x33, 0x07, 0x2e, 0x08, 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08,
|
|
||||||
0x2a, 0x56, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e,
|
|
||||||
0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41,
|
|
||||||
0x2a, 0x06, 0x3b, 0x05, 0x0a, 0x06, 0x51, 0x06, 0x01, 0x05, 0x10, 0x03,
|
|
||||||
0x05, 0x80, 0x8b, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22,
|
|
||||||
0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, 0x39, 0x07, 0x0a, 0x36, 0x2c, 0x04,
|
|
||||||
0x10, 0x80, 0xc0, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45,
|
|
||||||
0x1b, 0x48, 0x08, 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03,
|
|
||||||
0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, 0x0a, 0x81,
|
|
||||||
0x36, 0x19, 0x80, 0xb7, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75,
|
|
||||||
0x0b, 0x80, 0xc4, 0x8a, 0xbc, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1,
|
|
||||||
0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x02, 0x60, 0x26, 0x0a, 0x46, 0x0a,
|
|
||||||
0x28, 0x05, 0x13, 0x82, 0xb0, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, 0x11,
|
|
||||||
0x40, 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, 0x09,
|
|
||||||
0xa2, 0xf7, 0x81, 0x1f, 0x31, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89,
|
|
||||||
0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, 0x10, 0x93, 0x60, 0x80, 0xf6,
|
|
||||||
0x0a, 0x73, 0x08, 0x6e, 0x17, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09,
|
|
||||||
0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50,
|
|
||||||
0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, 0x02, 0x81, 0x70, 0x3a, 0x05,
|
|
||||||
0x01, 0x85, 0x00, 0x80, 0xd7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83,
|
|
||||||
0x11, 0x44, 0x4c, 0x3d, 0x80, 0xc2, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05,
|
|
||||||
0x1b, 0x34, 0x02, 0x81, 0x0e, 0x2c, 0x04, 0x64, 0x0c, 0x56, 0x0a, 0x80,
|
|
||||||
0xae, 0x38, 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80,
|
|
||||||
0x9a, 0x83, 0xd8, 0x08, 0x0d, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07,
|
|
||||||
0x0c, 0x14, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x22, 0x4e,
|
|
||||||
0x81, 0x54, 0x0c, 0x15, 0x03, 0x03, 0x05, 0x07, 0x09, 0x19, 0x07, 0x07,
|
|
||||||
0x09, 0x03, 0x0d, 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06,
|
|
||||||
};
|
|
||||||
auto lower = static_cast<uint16_t>(cp);
|
|
||||||
if (cp < 0x10000) {
|
|
||||||
return is_printable(lower, singletons0,
|
|
||||||
sizeof(singletons0) / sizeof(*singletons0),
|
|
||||||
singletons0_lower, normal0, sizeof(normal0));
|
|
||||||
}
|
|
||||||
if (cp < 0x20000) {
|
|
||||||
return is_printable(lower, singletons1,
|
|
||||||
sizeof(singletons1) / sizeof(*singletons1),
|
|
||||||
singletons1_lower, normal1, sizeof(normal1));
|
|
||||||
}
|
|
||||||
if (0x2a6de <= cp && cp < 0x2a700) return false;
|
|
||||||
if (0x2b735 <= cp && cp < 0x2b740) return false;
|
|
||||||
if (0x2b81e <= cp && cp < 0x2b820) return false;
|
|
||||||
if (0x2cea2 <= cp && cp < 0x2ceb0) return false;
|
|
||||||
if (0x2ebe1 <= cp && cp < 0x2f800) return false;
|
|
||||||
if (0x2fa1e <= cp && cp < 0x30000) return false;
|
|
||||||
if (0x3134b <= cp && cp < 0xe0100) return false;
|
|
||||||
if (0xe01f0 <= cp && cp < 0x110000) return false;
|
|
||||||
return cp < 0x110000;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto needs_escape(uint32_t cp) -> bool {
|
|
||||||
return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' ||
|
|
||||||
!is_printable(cp);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char> struct find_escape_result {
|
|
||||||
const Char* begin;
|
|
||||||
const Char* end;
|
|
||||||
uint32_t cp;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
auto find_escape(const Char* begin, const Char* end)
|
|
||||||
-> find_escape_result<Char> {
|
|
||||||
for (; begin != end; ++begin) {
|
|
||||||
auto cp = static_cast<typename std::make_unsigned<Char>::type>(*begin);
|
|
||||||
if (sizeof(Char) == 1 && cp >= 0x80) continue;
|
|
||||||
if (needs_escape(cp)) return {begin, begin + 1, cp};
|
|
||||||
}
|
|
||||||
return {begin, nullptr, 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto find_escape(const char* begin, const char* end)
|
|
||||||
-> find_escape_result<char> {
|
|
||||||
if (!is_utf8()) return find_escape<char>(begin, end);
|
|
||||||
auto result = find_escape_result<char>{end, nullptr, 0};
|
|
||||||
for_each_codepoint(string_view(begin, to_unsigned(end - begin)),
|
|
||||||
[&](uint32_t cp, string_view sv) {
|
|
||||||
if (needs_escape(cp)) {
|
|
||||||
result = {sv.begin(), sv.end(), cp};
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char, typename OutputIt>
|
template <typename Char, typename OutputIt>
|
||||||
auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt {
|
auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt {
|
||||||
*out++ = '"';
|
return write_escaped_string(out, str);
|
||||||
auto begin = str.begin(), end = str.end();
|
|
||||||
do {
|
|
||||||
auto escape = find_escape(begin, end);
|
|
||||||
out = copy_str<Char>(begin, escape.begin, out);
|
|
||||||
begin = escape.end;
|
|
||||||
if (!begin) break;
|
|
||||||
auto c = static_cast<Char>(escape.cp);
|
|
||||||
switch (escape.cp) {
|
|
||||||
case '\n':
|
|
||||||
*out++ = '\\';
|
|
||||||
c = 'n';
|
|
||||||
break;
|
|
||||||
case '\r':
|
|
||||||
*out++ = '\\';
|
|
||||||
c = 'r';
|
|
||||||
break;
|
|
||||||
case '\t':
|
|
||||||
*out++ = '\\';
|
|
||||||
c = 't';
|
|
||||||
break;
|
|
||||||
case '"':
|
|
||||||
FMT_FALLTHROUGH;
|
|
||||||
case '\\':
|
|
||||||
*out++ = '\\';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (is_utf8()) {
|
|
||||||
if (escape.cp < 0x100) {
|
|
||||||
out = format_to(out, "\\x{:02x}", escape.cp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (escape.cp < 0x10000) {
|
|
||||||
out = format_to(out, "\\u{:04x}", escape.cp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (escape.cp < 0x110000) {
|
|
||||||
out = format_to(out, "\\U{:08x}", escape.cp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (Char escape_char : basic_string_view<Char>(
|
|
||||||
escape.begin, to_unsigned(escape.end - escape.begin))) {
|
|
||||||
out = format_to(
|
|
||||||
out, "\\x{:02x}",
|
|
||||||
static_cast<typename std::make_unsigned<Char>::type>(escape_char));
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*out++ = c;
|
|
||||||
} while (begin != end);
|
|
||||||
*out++ = '"';
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename OutputIt, typename T,
|
template <typename Char, typename OutputIt, typename T,
|
||||||
@ -523,10 +298,7 @@ inline auto write_range_entry(OutputIt out, const T& str) -> OutputIt {
|
|||||||
template <typename Char, typename OutputIt, typename Arg,
|
template <typename Char, typename OutputIt, typename Arg,
|
||||||
FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
|
FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
|
||||||
OutputIt write_range_entry(OutputIt out, const Arg v) {
|
OutputIt write_range_entry(OutputIt out, const Arg v) {
|
||||||
*out++ = '\'';
|
return write_escaped_char(out, v);
|
||||||
*out++ = v;
|
|
||||||
*out++ = '\'';
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
@ -540,12 +312,19 @@ OutputIt write_range_entry(OutputIt out, const Arg& v) {
|
|||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <typename T> struct is_tuple_like {
|
template <typename T> struct is_tuple_like {
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static constexpr const bool value =
|
||||||
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
|
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, typename C> struct is_tuple_formattable {
|
||||||
|
static constexpr const bool value =
|
||||||
|
detail::is_tuple_formattable_<T, C>::value;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename TupleT, typename Char>
|
template <typename TupleT, typename Char>
|
||||||
struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
|
struct formatter<TupleT, Char,
|
||||||
|
enable_if_t<fmt::is_tuple_like<TupleT>::value &&
|
||||||
|
fmt::is_tuple_formattable<TupleT, Char>::value>> {
|
||||||
private:
|
private:
|
||||||
// C++11 generic lambda for format().
|
// C++11 generic lambda for format().
|
||||||
template <typename FormatContext> struct format_each {
|
template <typename FormatContext> struct format_each {
|
||||||
@ -565,7 +344,8 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext = format_context>
|
template <typename FormatContext = format_context>
|
||||||
auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) {
|
auto format(const TupleT& values, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
auto out = ctx.out();
|
auto out = ctx.out();
|
||||||
*out++ = '(';
|
*out++ = '(';
|
||||||
detail::for_each(values, format_each<FormatContext>{0, out});
|
detail::for_each(values, format_each<FormatContext>{0, out});
|
||||||
@ -575,50 +355,101 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename Char> struct is_range {
|
template <typename T, typename Char> struct is_range {
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static constexpr const bool value =
|
||||||
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
|
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
|
||||||
!detail::is_map<T>::value &&
|
!detail::is_map<T>::value &&
|
||||||
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
||||||
!std::is_constructible<detail::std_string_view<Char>, T>::value;
|
!std::is_constructible<detail::std_string_view<Char>, T>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename Char>
|
namespace detail {
|
||||||
|
template <typename Context> struct range_mapper {
|
||||||
|
using mapper = arg_mapper<Context>;
|
||||||
|
|
||||||
|
template <typename T,
|
||||||
|
FMT_ENABLE_IF(has_formatter<remove_cvref_t<T>, Context>::value)>
|
||||||
|
static auto map(T&& value) -> T&& {
|
||||||
|
return static_cast<T&&>(value);
|
||||||
|
}
|
||||||
|
template <typename T,
|
||||||
|
FMT_ENABLE_IF(!has_formatter<remove_cvref_t<T>, Context>::value)>
|
||||||
|
static auto map(T&& value)
|
||||||
|
-> decltype(mapper().map(static_cast<T&&>(value))) {
|
||||||
|
return mapper().map(static_cast<T&&>(value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, typename Element>
|
||||||
|
using range_formatter_type = conditional_t<
|
||||||
|
is_formattable<Element, Char>::value,
|
||||||
|
formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map(
|
||||||
|
std::declval<Element>()))>,
|
||||||
|
Char>,
|
||||||
|
fallback_formatter<Element, Char>>;
|
||||||
|
|
||||||
|
template <typename R>
|
||||||
|
using maybe_const_range =
|
||||||
|
conditional_t<has_const_begin_end<R>::value, const R, R>;
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template <typename R, typename Char>
|
||||||
struct formatter<
|
struct formatter<
|
||||||
T, Char,
|
R, Char,
|
||||||
enable_if_t<
|
enable_if_t<
|
||||||
fmt::is_range<T, Char>::value
|
conjunction<fmt::is_range<R, Char>
|
||||||
// Workaround a bug in MSVC 2019 and earlier.
|
// Workaround a bug in MSVC 2017 and earlier.
|
||||||
#if !FMT_MSC_VER
|
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1920
|
||||||
&& (is_formattable<detail::value_type<T>, Char>::value ||
|
,
|
||||||
detail::has_fallback_formatter<detail::value_type<T>, Char>::value)
|
disjunction<
|
||||||
|
is_formattable<detail::uncvref_type<detail::maybe_const_range<R>>,
|
||||||
|
Char>,
|
||||||
|
detail::has_fallback_formatter<
|
||||||
|
detail::uncvref_type<detail::maybe_const_range<R>>, Char>
|
||||||
|
>
|
||||||
#endif
|
#endif
|
||||||
|
>::value
|
||||||
>> {
|
>> {
|
||||||
|
|
||||||
|
using range_type = detail::maybe_const_range<R>;
|
||||||
|
using formatter_type =
|
||||||
|
detail::range_formatter_type<Char, detail::uncvref_type<range_type>>;
|
||||||
|
formatter_type underlying_;
|
||||||
|
bool custom_specs_ = false;
|
||||||
|
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
return ctx.begin();
|
auto it = ctx.begin();
|
||||||
|
auto end = ctx.end();
|
||||||
|
if (it == end || *it == '}') return it;
|
||||||
|
|
||||||
|
if (*it != ':')
|
||||||
|
FMT_THROW(format_error("no top-level range formatters supported"));
|
||||||
|
|
||||||
|
custom_specs_ = true;
|
||||||
|
++it;
|
||||||
|
ctx.advance_to(it);
|
||||||
|
return underlying_.parse(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <typename FormatContext>
|
||||||
typename FormatContext, typename U,
|
auto format(range_type& range, FormatContext& ctx) const
|
||||||
FMT_ENABLE_IF(
|
-> decltype(ctx.out()) {
|
||||||
std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value,
|
Char prefix = detail::is_set<R>::value ? '{' : '[';
|
||||||
const T, T>>::value)>
|
Char postfix = detail::is_set<R>::value ? '}' : ']';
|
||||||
auto format(U& range, FormatContext& ctx) -> decltype(ctx.out()) {
|
detail::range_mapper<buffer_context<Char>> mapper;
|
||||||
#ifdef FMT_DEPRECATED_BRACED_RANGES
|
|
||||||
Char prefix = '{';
|
|
||||||
Char postfix = '}';
|
|
||||||
#else
|
|
||||||
Char prefix = detail::is_set<T>::value ? '{' : '[';
|
|
||||||
Char postfix = detail::is_set<T>::value ? '}' : ']';
|
|
||||||
#endif
|
|
||||||
auto out = ctx.out();
|
auto out = ctx.out();
|
||||||
*out++ = prefix;
|
*out++ = prefix;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
auto it = std::begin(range);
|
auto it = detail::range_begin(range);
|
||||||
auto end = std::end(range);
|
auto end = detail::range_end(range);
|
||||||
for (; it != end; ++it) {
|
for (; it != end; ++it) {
|
||||||
if (i > 0) out = detail::write_delimiter(out);
|
if (i > 0) out = detail::write_delimiter(out);
|
||||||
out = detail::write_range_entry<Char>(out, *it);
|
if (custom_specs_) {
|
||||||
|
ctx.advance_to(out);
|
||||||
|
out = underlying_.format(mapper.map(*it), ctx);
|
||||||
|
} else {
|
||||||
|
out = detail::write_range_entry<Char>(out, *it);
|
||||||
|
}
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
*out++ = postfix;
|
*out++ = postfix;
|
||||||
@ -629,14 +460,21 @@ struct formatter<
|
|||||||
template <typename T, typename Char>
|
template <typename T, typename Char>
|
||||||
struct formatter<
|
struct formatter<
|
||||||
T, Char,
|
T, Char,
|
||||||
enable_if_t<
|
enable_if_t<conjunction<detail::is_map<T>
|
||||||
detail::is_map<T>::value
|
// Workaround a bug in MSVC 2017 and earlier.
|
||||||
// Workaround a bug in MSVC 2019 and earlier.
|
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1920
|
||||||
#if !FMT_MSC_VER
|
,
|
||||||
&& (is_formattable<detail::value_type<T>, Char>::value ||
|
disjunction<
|
||||||
detail::has_fallback_formatter<detail::value_type<T>, Char>::value)
|
is_formattable<detail::uncvref_first_type<T>, Char>,
|
||||||
|
detail::has_fallback_formatter<detail::uncvref_first_type<T>, Char>
|
||||||
|
>,
|
||||||
|
disjunction<
|
||||||
|
is_formattable<detail::uncvref_second_type<T>, Char>,
|
||||||
|
detail::has_fallback_formatter<detail::uncvref_second_type<T>, Char>
|
||||||
|
>
|
||||||
#endif
|
#endif
|
||||||
>> {
|
>::value
|
||||||
|
>> {
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
@ -647,7 +485,7 @@ struct formatter<
|
|||||||
FMT_ENABLE_IF(
|
FMT_ENABLE_IF(
|
||||||
std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value,
|
std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value,
|
||||||
const T, T>>::value)>
|
const T, T>>::value)>
|
||||||
auto format(U& map, FormatContext& ctx) -> decltype(ctx.out()) {
|
auto format(U& map, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||||
auto out = ctx.out();
|
auto out = ctx.out();
|
||||||
*out++ = '{';
|
*out++ = '{';
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
176
externals/dynarmic/externals/fmt/include/fmt/std.h
vendored
Executable file
176
externals/dynarmic/externals/fmt/include/fmt/std.h
vendored
Executable file
@ -0,0 +1,176 @@
|
|||||||
|
// Formatting library for C++ - formatters for standard library types
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_STD_H_
|
||||||
|
#define FMT_STD_H_
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "ostream.h"
|
||||||
|
|
||||||
|
#if FMT_HAS_INCLUDE(<version>)
|
||||||
|
# include <version>
|
||||||
|
#endif
|
||||||
|
// Checking FMT_CPLUSPLUS for warning suppression in MSVC.
|
||||||
|
#if FMT_CPLUSPLUS >= 201703L
|
||||||
|
# if FMT_HAS_INCLUDE(<filesystem>)
|
||||||
|
# include <filesystem>
|
||||||
|
# endif
|
||||||
|
# if FMT_HAS_INCLUDE(<variant>)
|
||||||
|
# include <variant>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cpp_lib_filesystem
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
void write_escaped_path(basic_memory_buffer<Char>& quoted,
|
||||||
|
const std::filesystem::path& p) {
|
||||||
|
write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
|
||||||
|
}
|
||||||
|
# ifdef _WIN32
|
||||||
|
template <>
|
||||||
|
inline void write_escaped_path<char>(basic_memory_buffer<char>& quoted,
|
||||||
|
const std::filesystem::path& p) {
|
||||||
|
auto s = p.u8string();
|
||||||
|
write_escaped_string<char>(
|
||||||
|
std::back_inserter(quoted),
|
||||||
|
string_view(reinterpret_cast<const char*>(s.c_str()), s.size()));
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
template <>
|
||||||
|
inline void write_escaped_path<std::filesystem::path::value_type>(
|
||||||
|
basic_memory_buffer<std::filesystem::path::value_type>& quoted,
|
||||||
|
const std::filesystem::path& p) {
|
||||||
|
write_escaped_string<std::filesystem::path::value_type>(
|
||||||
|
std::back_inserter(quoted), p.native());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1920
|
||||||
|
// For MSVC 2017 and earlier using the partial specialization
|
||||||
|
// would cause an ambiguity error, therefore we provide it only
|
||||||
|
// conditionally.
|
||||||
|
template <typename Char>
|
||||||
|
struct formatter<std::filesystem::path, Char>
|
||||||
|
: formatter<basic_string_view<Char>> {
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const std::filesystem::path& p, FormatContext& ctx) const ->
|
||||||
|
typename FormatContext::iterator {
|
||||||
|
basic_memory_buffer<Char> quoted;
|
||||||
|
detail::write_escaped_path(quoted, p);
|
||||||
|
return formatter<basic_string_view<Char>>::format(
|
||||||
|
basic_string_view<Char>(quoted.data(), quoted.size()), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
template <typename Char>
|
||||||
|
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef __cpp_lib_variant
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
template <typename Char> struct formatter<std::monostate, Char> {
|
||||||
|
template <typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const std::monostate&, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
auto out = ctx.out();
|
||||||
|
out = detail::write<Char>(out, "monostate");
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using variant_index_sequence =
|
||||||
|
std::make_index_sequence<std::variant_size<T>::value>;
|
||||||
|
|
||||||
|
// variant_size and variant_alternative check.
|
||||||
|
template <typename T, typename U = void>
|
||||||
|
struct is_variant_like_ : std::false_type {};
|
||||||
|
template <typename T>
|
||||||
|
struct is_variant_like_<T, std::void_t<decltype(std::variant_size<T>::value)>>
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
|
// formattable element check
|
||||||
|
template <typename T, typename C> class is_variant_formattable_ {
|
||||||
|
template <std::size_t... I>
|
||||||
|
static std::conjunction<
|
||||||
|
is_formattable<std::variant_alternative_t<I, T>, C>...>
|
||||||
|
check(std::index_sequence<I...>);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr const bool value =
|
||||||
|
decltype(check(variant_index_sequence<T>{}))::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, typename OutputIt, typename T>
|
||||||
|
auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt {
|
||||||
|
if constexpr (is_string<T>::value)
|
||||||
|
return write_escaped_string<Char>(out, detail::to_string_view(v));
|
||||||
|
else if constexpr (std::is_same_v<T, Char>)
|
||||||
|
return write_escaped_char(out, v);
|
||||||
|
else
|
||||||
|
return write<Char>(out, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template <typename T> struct is_variant_like {
|
||||||
|
static constexpr const bool value = detail::is_variant_like_<T>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename C> struct is_variant_formattable {
|
||||||
|
static constexpr const bool value =
|
||||||
|
detail::is_variant_formattable_<T, C>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Variant, typename Char>
|
||||||
|
struct formatter<
|
||||||
|
Variant, Char,
|
||||||
|
std::enable_if_t<std::conjunction_v<
|
||||||
|
is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
|
||||||
|
template <typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const Variant& value, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
auto out = ctx.out();
|
||||||
|
|
||||||
|
out = detail::write<Char>(out, "variant(");
|
||||||
|
std::visit(
|
||||||
|
[&](const auto& v) {
|
||||||
|
out = detail::write_variant_alternative<Char>(out, v);
|
||||||
|
},
|
||||||
|
value);
|
||||||
|
*out++ = ')';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // FMT_STD_H_
|
@ -47,12 +47,7 @@ constexpr format_arg_store<wformat_context, Args...> make_wformat_args(
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline namespace literals {
|
inline namespace literals {
|
||||||
constexpr auto operator"" _format(const wchar_t* s, size_t n)
|
#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||||
-> detail::udl_formatter<wchar_t> {
|
|
||||||
return {{s, n}};
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
|
||||||
constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) {
|
constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) {
|
||||||
return {s};
|
return {s};
|
||||||
}
|
}
|
||||||
@ -87,13 +82,23 @@ auto vformat(basic_string_view<Char> format_str,
|
|||||||
return to_string(buffer);
|
return to_string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 409
|
||||||
|
template <typename... Args>
|
||||||
|
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring {
|
||||||
|
return vformat(fmt, fmt::make_wformat_args(args...));
|
||||||
|
}
|
||||||
|
|
||||||
// Pass char_t as a default template parameter instead of using
|
// Pass char_t as a default template parameter instead of using
|
||||||
// std::basic_string<char_t<S>> to reduce the symbol size.
|
// std::basic_string<char_t<S>> to reduce the symbol size.
|
||||||
template <typename S, typename... Args, typename Char = char_t<S>,
|
template <typename S, typename... Args, typename Char = char_t<S>,
|
||||||
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
||||||
auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> {
|
auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
return vformat(detail::to_string_view(format_str),
|
||||||
return vformat(to_string_view(format_str), vargs);
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Locale, typename S, typename Char = char_t<S>,
|
template <typename Locale, typename S, typename Char = char_t<S>,
|
||||||
@ -103,7 +108,7 @@ inline auto vformat(
|
|||||||
const Locale& loc, const S& format_str,
|
const Locale& loc, const S& format_str,
|
||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
||||||
-> std::basic_string<Char> {
|
-> std::basic_string<Char> {
|
||||||
return detail::vformat(loc, to_string_view(format_str), args);
|
return detail::vformat(loc, detail::to_string_view(format_str), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Locale, typename S, typename... Args,
|
template <typename Locale, typename S, typename... Args,
|
||||||
@ -112,8 +117,8 @@ template <typename Locale, typename S, typename... Args,
|
|||||||
detail::is_exotic_char<Char>::value)>
|
detail::is_exotic_char<Char>::value)>
|
||||||
inline auto format(const Locale& loc, const S& format_str, Args&&... args)
|
inline auto format(const Locale& loc, const S& format_str, Args&&... args)
|
||||||
-> std::basic_string<Char> {
|
-> std::basic_string<Char> {
|
||||||
return detail::vformat(loc, to_string_view(format_str),
|
return detail::vformat(loc, detail::to_string_view(format_str),
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename S, typename Char = char_t<S>,
|
template <typename OutputIt, typename S, typename Char = char_t<S>,
|
||||||
@ -123,7 +128,7 @@ auto vformat_to(OutputIt out, const S& format_str,
|
|||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
||||||
-> OutputIt {
|
-> OutputIt {
|
||||||
auto&& buf = detail::get_buffer<Char>(out);
|
auto&& buf = detail::get_buffer<Char>(out);
|
||||||
detail::vformat_to(buf, to_string_view(format_str), args);
|
detail::vformat_to(buf, detail::to_string_view(format_str), args);
|
||||||
return detail::get_iterator(buf);
|
return detail::get_iterator(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,18 +137,8 @@ template <typename OutputIt, typename S, typename... Args,
|
|||||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||||
detail::is_exotic_char<Char>::value)>
|
detail::is_exotic_char<Char>::value)>
|
||||||
inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt {
|
inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
|
return vformat_to(out, detail::to_string_view(fmt),
|
||||||
return vformat_to(out, to_string_view(fmt), vargs);
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
|
||||||
|
|
||||||
template <typename S, typename... Args, typename Char, size_t SIZE,
|
|
||||||
typename Allocator, FMT_ENABLE_IF(detail::is_string<S>::value)>
|
|
||||||
FMT_DEPRECATED auto format_to(basic_memory_buffer<Char, SIZE, Allocator>& buf,
|
|
||||||
const S& format_str, Args&&... args) ->
|
|
||||||
typename buffer_context<Char>::iterator {
|
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
|
||||||
detail::vformat_to(buf, to_string_view(format_str), vargs, {});
|
|
||||||
return detail::buffer_appender<Char>(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Locale, typename S, typename OutputIt, typename... Args,
|
template <typename Locale, typename S, typename OutputIt, typename... Args,
|
||||||
@ -155,7 +150,8 @@ inline auto vformat_to(
|
|||||||
OutputIt out, const Locale& loc, const S& format_str,
|
OutputIt out, const Locale& loc, const S& format_str,
|
||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) -> OutputIt {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) -> OutputIt {
|
||||||
auto&& buf = detail::get_buffer<Char>(out);
|
auto&& buf = detail::get_buffer<Char>(out);
|
||||||
vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc));
|
vformat_to(buf, detail::to_string_view(format_str), args,
|
||||||
|
detail::locale_ref(loc));
|
||||||
return detail::get_iterator(buf);
|
return detail::get_iterator(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,8 +163,8 @@ template <
|
|||||||
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
|
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
|
||||||
Args&&... args) ->
|
Args&&... args) ->
|
||||||
typename std::enable_if<enable, OutputIt>::type {
|
typename std::enable_if<enable, OutputIt>::type {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
return vformat_to(out, loc, to_string_view(format_str),
|
||||||
return vformat_to(out, loc, to_string_view(format_str), vargs);
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename Char, typename... Args,
|
template <typename OutputIt, typename Char, typename... Args,
|
||||||
@ -190,16 +186,16 @@ template <typename OutputIt, typename S, typename... Args,
|
|||||||
detail::is_exotic_char<Char>::value)>
|
detail::is_exotic_char<Char>::value)>
|
||||||
inline auto format_to_n(OutputIt out, size_t n, const S& fmt,
|
inline auto format_to_n(OutputIt out, size_t n, const S& fmt,
|
||||||
const Args&... args) -> format_to_n_result<OutputIt> {
|
const Args&... args) -> format_to_n_result<OutputIt> {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
|
return vformat_to_n(out, n, detail::to_string_view(fmt),
|
||||||
return vformat_to_n(out, n, to_string_view(fmt), vargs);
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename... Args, typename Char = char_t<S>,
|
template <typename S, typename... Args, typename Char = char_t<S>,
|
||||||
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
|
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
|
||||||
inline auto formatted_size(const S& fmt, Args&&... args) -> size_t {
|
inline auto formatted_size(const S& fmt, Args&&... args) -> size_t {
|
||||||
detail::counting_buffer<Char> buf;
|
detail::counting_buffer<Char> buf;
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
|
detail::vformat_to(buf, detail::to_string_view(fmt),
|
||||||
detail::vformat_to(buf, to_string_view(fmt), vargs);
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
return buf.count();
|
return buf.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
109
externals/dynarmic/externals/fmt/src/format.cc
vendored
109
externals/dynarmic/externals/fmt/src/format.cc
vendored
@ -10,115 +10,38 @@
|
|||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
// DEPRECATED!
|
template FMT_API auto dragonbox::to_decimal(float x) noexcept
|
||||||
template <typename T = void> struct basic_data {
|
-> dragonbox::decimal_fp<float>;
|
||||||
FMT_API static constexpr const char digits[100][2] = {
|
template FMT_API auto dragonbox::to_decimal(double x) noexcept
|
||||||
{'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'},
|
-> dragonbox::decimal_fp<double>;
|
||||||
{'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'},
|
|
||||||
{'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'},
|
|
||||||
{'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'},
|
|
||||||
{'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'},
|
|
||||||
{'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'},
|
|
||||||
{'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'},
|
|
||||||
{'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'},
|
|
||||||
{'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'},
|
|
||||||
{'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'},
|
|
||||||
{'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'},
|
|
||||||
{'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'},
|
|
||||||
{'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'},
|
|
||||||
{'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'},
|
|
||||||
{'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'},
|
|
||||||
{'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'},
|
|
||||||
{'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}};
|
|
||||||
FMT_API static constexpr const char hex_digits[] = "0123456789abcdef";
|
|
||||||
FMT_API static constexpr const char signs[4] = {0, '-', '+', ' '};
|
|
||||||
FMT_API static constexpr const char left_padding_shifts[5] = {31, 31, 0, 1,
|
|
||||||
0};
|
|
||||||
FMT_API static constexpr const char right_padding_shifts[5] = {0, 31, 0, 1,
|
|
||||||
0};
|
|
||||||
FMT_API static constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+',
|
|
||||||
0x1000000u | ' '};
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef FMT_SHARED
|
|
||||||
// Required for -flto, -fivisibility=hidden and -shared to work
|
|
||||||
extern template struct basic_data<void>;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __cplusplus < 201703L
|
|
||||||
// DEPRECATED! These are here only for ABI compatiblity.
|
|
||||||
template <typename T> constexpr const char basic_data<T>::digits[][2];
|
|
||||||
template <typename T> constexpr const char basic_data<T>::hex_digits[];
|
|
||||||
template <typename T> constexpr const char basic_data<T>::signs[];
|
|
||||||
template <typename T> constexpr const char basic_data<T>::left_padding_shifts[];
|
|
||||||
template <typename T>
|
|
||||||
constexpr const char basic_data<T>::right_padding_shifts[];
|
|
||||||
template <typename T> constexpr const unsigned basic_data<T>::prefixes[];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
int format_float(char* buf, std::size_t size, const char* format, int precision,
|
|
||||||
T value) {
|
|
||||||
#ifdef FMT_FUZZ
|
|
||||||
if (precision > 100000)
|
|
||||||
throw std::runtime_error(
|
|
||||||
"fuzz mode - avoid large allocation inside snprintf");
|
|
||||||
#endif
|
|
||||||
// Suppress the warning about nonliteral format string.
|
|
||||||
int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF;
|
|
||||||
return precision < 0 ? snprintf_ptr(buf, size, format, value)
|
|
||||||
: snprintf_ptr(buf, size, format, precision, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template FMT_API dragonbox::decimal_fp<float> dragonbox::to_decimal(float x)
|
|
||||||
FMT_NOEXCEPT;
|
|
||||||
template FMT_API dragonbox::decimal_fp<double> dragonbox::to_decimal(double x)
|
|
||||||
FMT_NOEXCEPT;
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
|
|
||||||
int (*instantiate_format_float)(double, int, detail::float_specs,
|
|
||||||
detail::buffer<char>&) = detail::format_float;
|
|
||||||
|
|
||||||
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
template FMT_API detail::locale_ref::locale_ref(const std::locale& loc);
|
template FMT_API locale_ref::locale_ref(const std::locale& loc);
|
||||||
template FMT_API std::locale detail::locale_ref::get<std::locale>() const;
|
template FMT_API auto locale_ref::get<std::locale>() const -> std::locale;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Explicit instantiations for char.
|
// Explicit instantiations for char.
|
||||||
|
|
||||||
template FMT_API auto detail::thousands_sep_impl(locale_ref)
|
template FMT_API auto thousands_sep_impl(locale_ref)
|
||||||
-> thousands_sep_result<char>;
|
-> thousands_sep_result<char>;
|
||||||
template FMT_API char detail::decimal_point_impl(locale_ref);
|
template FMT_API auto decimal_point_impl(locale_ref) -> char;
|
||||||
|
|
||||||
template FMT_API void detail::buffer<char>::append(const char*, const char*);
|
template FMT_API void buffer<char>::append(const char*, const char*);
|
||||||
|
|
||||||
// DEPRECATED!
|
// DEPRECATED!
|
||||||
// There is no correspondent extern template in format.h because of
|
// There is no correspondent extern template in format.h because of
|
||||||
// incompatibility between clang and gcc (#2377).
|
// incompatibility between clang and gcc (#2377).
|
||||||
template FMT_API void detail::vformat_to(
|
template FMT_API void vformat_to(buffer<char>&, string_view,
|
||||||
detail::buffer<char>&, string_view,
|
basic_format_args<FMT_BUFFER_CONTEXT(char)>,
|
||||||
basic_format_args<FMT_BUFFER_CONTEXT(char)>, detail::locale_ref);
|
locale_ref);
|
||||||
|
|
||||||
template FMT_API int detail::snprintf_float(double, int, detail::float_specs,
|
|
||||||
detail::buffer<char>&);
|
|
||||||
template FMT_API int detail::snprintf_float(long double, int,
|
|
||||||
detail::float_specs,
|
|
||||||
detail::buffer<char>&);
|
|
||||||
template FMT_API int detail::format_float(double, int, detail::float_specs,
|
|
||||||
detail::buffer<char>&);
|
|
||||||
template FMT_API int detail::format_float(long double, int, detail::float_specs,
|
|
||||||
detail::buffer<char>&);
|
|
||||||
|
|
||||||
// Explicit instantiations for wchar_t.
|
// Explicit instantiations for wchar_t.
|
||||||
|
|
||||||
template FMT_API auto detail::thousands_sep_impl(locale_ref)
|
template FMT_API auto thousands_sep_impl(locale_ref)
|
||||||
-> thousands_sep_result<wchar_t>;
|
-> thousands_sep_result<wchar_t>;
|
||||||
template FMT_API wchar_t detail::decimal_point_impl(locale_ref);
|
template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
|
||||||
|
|
||||||
template FMT_API void detail::buffer<wchar_t>::append(const wchar_t*,
|
template FMT_API void buffer<wchar_t>::append(const wchar_t*, const wchar_t*);
|
||||||
const wchar_t*);
|
|
||||||
|
|
||||||
template struct detail::basic_data<void>;
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
42
externals/dynarmic/externals/fmt/src/os.cc
vendored
42
externals/dynarmic/externals/fmt/src/os.cc
vendored
@ -35,9 +35,15 @@
|
|||||||
# ifndef S_IRGRP
|
# ifndef S_IRGRP
|
||||||
# define S_IRGRP 0
|
# define S_IRGRP 0
|
||||||
# endif
|
# endif
|
||||||
|
# ifndef S_IWGRP
|
||||||
|
# define S_IWGRP 0
|
||||||
|
# endif
|
||||||
# ifndef S_IROTH
|
# ifndef S_IROTH
|
||||||
# define S_IROTH 0
|
# define S_IROTH 0
|
||||||
# endif
|
# endif
|
||||||
|
# ifndef S_IWOTH
|
||||||
|
# define S_IWOTH 0
|
||||||
|
# endif
|
||||||
# endif // _WIN32
|
# endif // _WIN32
|
||||||
#endif // FMT_USE_FCNTL
|
#endif // FMT_USE_FCNTL
|
||||||
|
|
||||||
@ -45,10 +51,6 @@
|
|||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef fileno
|
|
||||||
# undef fileno
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Return type of read and write functions.
|
// Return type of read and write functions.
|
||||||
@ -107,7 +109,7 @@ class system_message {
|
|||||||
unsigned long result_;
|
unsigned long result_;
|
||||||
wchar_t* message_;
|
wchar_t* message_;
|
||||||
|
|
||||||
static bool is_whitespace(wchar_t c) FMT_NOEXCEPT {
|
static bool is_whitespace(wchar_t c) noexcept {
|
||||||
return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0';
|
return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,15 +128,15 @@ class system_message {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
~system_message() { LocalFree(message_); }
|
~system_message() { LocalFree(message_); }
|
||||||
explicit operator bool() const FMT_NOEXCEPT { return result_ != 0; }
|
explicit operator bool() const noexcept { return result_ != 0; }
|
||||||
operator basic_string_view<wchar_t>() const FMT_NOEXCEPT {
|
operator basic_string_view<wchar_t>() const noexcept {
|
||||||
return basic_string_view<wchar_t>(message_, result_);
|
return basic_string_view<wchar_t>(message_, result_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class utf8_system_category final : public std::error_category {
|
class utf8_system_category final : public std::error_category {
|
||||||
public:
|
public:
|
||||||
const char* name() const FMT_NOEXCEPT override { return "system"; }
|
const char* name() const noexcept override { return "system"; }
|
||||||
std::string message(int error_code) const override {
|
std::string message(int error_code) const override {
|
||||||
system_message msg(error_code);
|
system_message msg(error_code);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
@ -149,7 +151,7 @@ class utf8_system_category final : public std::error_category {
|
|||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
FMT_API const std::error_category& system_category() FMT_NOEXCEPT {
|
FMT_API const std::error_category& system_category() noexcept {
|
||||||
static const detail::utf8_system_category category;
|
static const detail::utf8_system_category category;
|
||||||
return category;
|
return category;
|
||||||
}
|
}
|
||||||
@ -161,13 +163,13 @@ std::system_error vwindows_error(int err_code, string_view format_str,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void detail::format_windows_error(detail::buffer<char>& out, int error_code,
|
void detail::format_windows_error(detail::buffer<char>& out, int error_code,
|
||||||
const char* message) FMT_NOEXCEPT {
|
const char* message) noexcept {
|
||||||
FMT_TRY {
|
FMT_TRY {
|
||||||
system_message msg(error_code);
|
system_message msg(error_code);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
utf16_to_utf8 utf8_message;
|
utf16_to_utf8 utf8_message;
|
||||||
if (utf8_message.convert(msg) == ERROR_SUCCESS) {
|
if (utf8_message.convert(msg) == ERROR_SUCCESS) {
|
||||||
format_to(buffer_appender<char>(out), "{}: {}", message, utf8_message);
|
fmt::format_to(buffer_appender<char>(out), "{}: {}", message, utf8_message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -176,12 +178,12 @@ void detail::format_windows_error(detail::buffer<char>& out, int error_code,
|
|||||||
format_error_code(out, error_code, message);
|
format_error_code(out, error_code, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void report_windows_error(int error_code, const char* message) FMT_NOEXCEPT {
|
void report_windows_error(int error_code, const char* message) noexcept {
|
||||||
report_error(detail::format_windows_error, error_code, message);
|
report_error(detail::format_windows_error, error_code, message);
|
||||||
}
|
}
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
buffered_file::~buffered_file() FMT_NOEXCEPT {
|
buffered_file::~buffered_file() noexcept {
|
||||||
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
|
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
|
||||||
report_system_error(errno, "cannot close file");
|
report_system_error(errno, "cannot close file");
|
||||||
}
|
}
|
||||||
@ -200,11 +202,8 @@ void buffered_file::close() {
|
|||||||
if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
|
if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// A macro used to prevent expansion of fileno on broken versions of MinGW.
|
int buffered_file::descriptor() const {
|
||||||
#define FMT_ARGS
|
int fd = FMT_POSIX_CALL(fileno(file_));
|
||||||
|
|
||||||
int buffered_file::fileno() const {
|
|
||||||
int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
|
|
||||||
if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor"));
|
if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor"));
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
@ -214,7 +213,8 @@ file::file(cstring_view path, int oflag) {
|
|||||||
# ifdef _WIN32
|
# ifdef _WIN32
|
||||||
using mode_t = int;
|
using mode_t = int;
|
||||||
# endif
|
# endif
|
||||||
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
constexpr mode_t mode =
|
||||||
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
|
||||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||||
fd_ = -1;
|
fd_ = -1;
|
||||||
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
|
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
|
||||||
@ -225,7 +225,7 @@ file::file(cstring_view path, int oflag) {
|
|||||||
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
|
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
file::~file() FMT_NOEXCEPT {
|
file::~file() noexcept {
|
||||||
// Don't retry close in case of EINTR!
|
// Don't retry close in case of EINTR!
|
||||||
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
||||||
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
|
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
|
||||||
@ -299,7 +299,7 @@ void file::dup2(int fd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void file::dup2(int fd, std::error_code& ec) FMT_NOEXCEPT {
|
void file::dup2(int fd, std::error_code& ec) noexcept {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||||
if (result == -1) ec = std::error_code(errno, std::generic_category());
|
if (result == -1) ec = std::error_code(errno, std::generic_category());
|
||||||
|
@ -1 +1 @@
|
|||||||
4.2.1
|
5.1.1
|
||||||
|
@ -11,18 +11,17 @@ cc_library(
|
|||||||
"include/fmt/color.h",
|
"include/fmt/color.h",
|
||||||
"include/fmt/compile.h",
|
"include/fmt/compile.h",
|
||||||
"include/fmt/core.h",
|
"include/fmt/core.h",
|
||||||
"include/fmt/format.h",
|
|
||||||
"include/fmt/format-inl.h",
|
"include/fmt/format-inl.h",
|
||||||
"include/fmt/locale.h",
|
"include/fmt/format.h",
|
||||||
"include/fmt/os.h",
|
"include/fmt/os.h",
|
||||||
"include/fmt/ostream.h",
|
"include/fmt/ostream.h",
|
||||||
"include/fmt/printf.h",
|
"include/fmt/printf.h",
|
||||||
"include/fmt/ranges.h",
|
"include/fmt/ranges.h",
|
||||||
|
"include/fmt/std.h",
|
||||||
"include/fmt/xchar.h",
|
"include/fmt/xchar.h",
|
||||||
],
|
],
|
||||||
includes = [
|
includes = [
|
||||||
"include",
|
"include",
|
||||||
"src",
|
|
||||||
],
|
],
|
||||||
strip_include_prefix = "include",
|
strip_include_prefix = "include",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
# C++14 feature support detection
|
# C++14 feature support detection
|
||||||
|
|
||||||
include(CheckCXXSourceCompiles)
|
|
||||||
include(CheckCXXCompilerFlag)
|
include(CheckCXXCompilerFlag)
|
||||||
|
function (fmt_check_cxx_compiler_flag flag result)
|
||||||
|
if (NOT MSVC)
|
||||||
|
check_cxx_compiler_flag("${flag}" ${result})
|
||||||
|
endif ()
|
||||||
|
endfunction ()
|
||||||
|
|
||||||
if (NOT CMAKE_CXX_STANDARD)
|
if (NOT CMAKE_CXX_STANDARD)
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
@ -9,35 +13,38 @@ endif()
|
|||||||
message(STATUS "CXX_STANDARD: ${CMAKE_CXX_STANDARD}")
|
message(STATUS "CXX_STANDARD: ${CMAKE_CXX_STANDARD}")
|
||||||
|
|
||||||
if (CMAKE_CXX_STANDARD EQUAL 20)
|
if (CMAKE_CXX_STANDARD EQUAL 20)
|
||||||
check_cxx_compiler_flag(-std=c++20 has_std_20_flag)
|
fmt_check_cxx_compiler_flag(-std=c++20 has_std_20_flag)
|
||||||
check_cxx_compiler_flag(-std=c++2a has_std_2a_flag)
|
fmt_check_cxx_compiler_flag(-std=c++2a has_std_2a_flag)
|
||||||
|
|
||||||
if (has_std_20_flag)
|
if (has_std_20_flag)
|
||||||
set(CXX_STANDARD_FLAG -std=c++20)
|
set(CXX_STANDARD_FLAG -std=c++20)
|
||||||
elseif (has_std_2a_flag)
|
elseif (has_std_2a_flag)
|
||||||
set(CXX_STANDARD_FLAG -std=c++2a)
|
set(CXX_STANDARD_FLAG -std=c++2a)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
elseif (CMAKE_CXX_STANDARD EQUAL 17)
|
elseif (CMAKE_CXX_STANDARD EQUAL 17)
|
||||||
check_cxx_compiler_flag(-std=c++17 has_std_17_flag)
|
fmt_check_cxx_compiler_flag(-std=c++17 has_std_17_flag)
|
||||||
check_cxx_compiler_flag(-std=c++1z has_std_1z_flag)
|
fmt_check_cxx_compiler_flag(-std=c++1z has_std_1z_flag)
|
||||||
|
|
||||||
if (has_std_17_flag)
|
if (has_std_17_flag)
|
||||||
set(CXX_STANDARD_FLAG -std=c++17)
|
set(CXX_STANDARD_FLAG -std=c++17)
|
||||||
elseif (has_std_1z_flag)
|
elseif (has_std_1z_flag)
|
||||||
set(CXX_STANDARD_FLAG -std=c++1z)
|
set(CXX_STANDARD_FLAG -std=c++1z)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
elseif (CMAKE_CXX_STANDARD EQUAL 14)
|
elseif (CMAKE_CXX_STANDARD EQUAL 14)
|
||||||
check_cxx_compiler_flag(-std=c++14 has_std_14_flag)
|
fmt_check_cxx_compiler_flag(-std=c++14 has_std_14_flag)
|
||||||
check_cxx_compiler_flag(-std=c++1y has_std_1y_flag)
|
fmt_check_cxx_compiler_flag(-std=c++1y has_std_1y_flag)
|
||||||
|
|
||||||
if (has_std_14_flag)
|
if (has_std_14_flag)
|
||||||
set(CXX_STANDARD_FLAG -std=c++14)
|
set(CXX_STANDARD_FLAG -std=c++14)
|
||||||
elseif (has_std_1y_flag)
|
elseif (has_std_1y_flag)
|
||||||
set(CXX_STANDARD_FLAG -std=c++1y)
|
set(CXX_STANDARD_FLAG -std=c++1y)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
elseif (CMAKE_CXX_STANDARD EQUAL 11)
|
elseif (CMAKE_CXX_STANDARD EQUAL 11)
|
||||||
check_cxx_compiler_flag(-std=c++11 has_std_11_flag)
|
fmt_check_cxx_compiler_flag(-std=c++11 has_std_11_flag)
|
||||||
check_cxx_compiler_flag(-std=c++0x has_std_0x_flag)
|
fmt_check_cxx_compiler_flag(-std=c++0x has_std_0x_flag)
|
||||||
|
|
||||||
if (has_std_11_flag)
|
if (has_std_11_flag)
|
||||||
set(CXX_STANDARD_FLAG -std=c++11)
|
set(CXX_STANDARD_FLAG -std=c++11)
|
||||||
@ -45,26 +52,3 @@ elseif (CMAKE_CXX_STANDARD EQUAL 11)
|
|||||||
set(CXX_STANDARD_FLAG -std=c++0x)
|
set(CXX_STANDARD_FLAG -std=c++0x)
|
||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG})
|
|
||||||
|
|
||||||
# Check if user-defined literals are available
|
|
||||||
check_cxx_source_compiles("
|
|
||||||
void operator\"\" _udl(long double);
|
|
||||||
int main() {}"
|
|
||||||
SUPPORTS_USER_DEFINED_LITERALS)
|
|
||||||
if (NOT SUPPORTS_USER_DEFINED_LITERALS)
|
|
||||||
set (SUPPORTS_USER_DEFINED_LITERALS OFF)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
# Check if <variant> is available
|
|
||||||
set(CMAKE_REQUIRED_FLAGS -std=c++1z)
|
|
||||||
check_cxx_source_compiles("
|
|
||||||
#include <variant>
|
|
||||||
int main() {}"
|
|
||||||
FMT_HAS_VARIANT)
|
|
||||||
if (NOT FMT_HAS_VARIANT)
|
|
||||||
set (FMT_HAS_VARIANT OFF)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_FLAGS )
|
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
@PACKAGE_INIT@
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
include(${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake)
|
if (NOT TARGET fmt::fmt)
|
||||||
|
include(${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake)
|
||||||
|
endif ()
|
||||||
|
|
||||||
check_required_components(fmt)
|
check_required_components(fmt)
|
||||||
|
@ -171,7 +171,7 @@ def main():
|
|||||||
normal1 = compress_normal(normal1)
|
normal1 = compress_normal(normal1)
|
||||||
|
|
||||||
print("""\
|
print("""\
|
||||||
inline auto is_printable(uint32_t cp) -> bool {\
|
FMT_FUNC auto is_printable(uint32_t cp) -> bool {\
|
||||||
""")
|
""")
|
||||||
print_singletons(singletons0u, singletons0l, 'singletons0', 'singletons0_lower')
|
print_singletons(singletons0u, singletons0l, 'singletons0', 'singletons0_lower')
|
||||||
print_singletons(singletons1u, singletons1l, 'singletons1', 'singletons1_lower')
|
print_singletons(singletons1u, singletons1l, 'singletons1', 'singletons1_lower')
|
||||||
|
@ -4,9 +4,7 @@ set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc)
|
|||||||
add_library(test-main STATIC ${TEST_MAIN_SRC})
|
add_library(test-main STATIC ${TEST_MAIN_SRC})
|
||||||
target_include_directories(test-main PUBLIC
|
target_include_directories(test-main PUBLIC
|
||||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
|
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
|
||||||
target_link_libraries(test-main gtest)
|
target_link_libraries(test-main gtest fmt)
|
||||||
|
|
||||||
include(CheckCXXCompilerFlag)
|
|
||||||
|
|
||||||
function(add_fmt_executable name)
|
function(add_fmt_executable name)
|
||||||
add_executable(${name} ${ARGN})
|
add_executable(${name} ${ARGN})
|
||||||
@ -79,6 +77,15 @@ endif()
|
|||||||
add_fmt_test(printf-test)
|
add_fmt_test(printf-test)
|
||||||
add_fmt_test(ranges-test ranges-odr-test.cc)
|
add_fmt_test(ranges-test ranges-odr-test.cc)
|
||||||
add_fmt_test(scan-test)
|
add_fmt_test(scan-test)
|
||||||
|
add_fmt_test(std-test)
|
||||||
|
try_compile(compile_result_unused
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
SOURCES ${CMAKE_CURRENT_LIST_DIR}/detect-stdfs.cc
|
||||||
|
OUTPUT_VARIABLE RAWOUTPUT)
|
||||||
|
string(REGEX REPLACE ".*libfound \"([^\"]*)\".*" "\\1" STDLIBFS "${RAWOUTPUT}")
|
||||||
|
if (STDLIBFS)
|
||||||
|
target_link_libraries(std-test ${STDLIBFS})
|
||||||
|
endif ()
|
||||||
add_fmt_test(unicode-test HEADER_ONLY)
|
add_fmt_test(unicode-test HEADER_ONLY)
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
target_compile_options(unicode-test PRIVATE /utf-8)
|
target_compile_options(unicode-test PRIVATE /utf-8)
|
||||||
@ -128,9 +135,6 @@ if (NOT MSVC_STATIC_RUNTIME)
|
|||||||
if (FMT_PEDANTIC)
|
if (FMT_PEDANTIC)
|
||||||
target_compile_options(posix-mock-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
|
target_compile_options(posix-mock-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
|
||||||
endif ()
|
endif ()
|
||||||
if (HAVE_STRTOD_L)
|
|
||||||
target_compile_definitions(posix-mock-test PRIVATE FMT_LOCALE)
|
|
||||||
endif ()
|
|
||||||
add_test(NAME posix-mock-test COMMAND posix-mock-test)
|
add_test(NAME posix-mock-test COMMAND posix-mock-test)
|
||||||
add_fmt_test(os-test)
|
add_fmt_test(os-test)
|
||||||
endif ()
|
endif ()
|
||||||
@ -148,9 +152,7 @@ if (FMT_PEDANTIC)
|
|||||||
target_include_directories(
|
target_include_directories(
|
||||||
noexception-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
|
noexception-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
|
||||||
target_compile_options(noexception-test PRIVATE -fno-exceptions)
|
target_compile_options(noexception-test PRIVATE -fno-exceptions)
|
||||||
if (FMT_PEDANTIC)
|
target_compile_options(noexception-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
|
||||||
target_compile_options(noexception-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
|
|
||||||
endif ()
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# Test that the library compiles without locale.
|
# Test that the library compiles without locale.
|
||||||
@ -174,8 +176,8 @@ if (FMT_PEDANTIC AND NOT WIN32)
|
|||||||
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
||||||
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
|
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
|
||||||
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
|
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
|
||||||
"-DFMT_DIR=${CMAKE_SOURCE_DIR}"
|
"-DCXX_STANDARD_FLAG=${CXX_STANDARD_FLAG}"
|
||||||
"-DSUPPORTS_USER_DEFINED_LITERALS=${SUPPORTS_USER_DEFINED_LITERALS}")
|
"-DFMT_DIR=${CMAKE_SOURCE_DIR}")
|
||||||
|
|
||||||
# Test if the targets are found from the build directory.
|
# Test if the targets are found from the build directory.
|
||||||
add_test(find-package-test ${CMAKE_CTEST_COMMAND}
|
add_test(find-package-test ${CMAKE_CTEST_COMMAND}
|
||||||
|
@ -557,6 +557,9 @@ TEST(chrono_test, special_durations) {
|
|||||||
"03:33");
|
"03:33");
|
||||||
EXPECT_EQ(fmt::format("{:%T}", std::chrono::duration<char, std::mega>{2}),
|
EXPECT_EQ(fmt::format("{:%T}", std::chrono::duration<char, std::mega>{2}),
|
||||||
"03:33:20");
|
"03:33:20");
|
||||||
|
EXPECT_EQ("44.000000000000",
|
||||||
|
fmt::format("{:%S}", std::chrono::duration<float, std::pico>(
|
||||||
|
1.54213895E+26)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(chrono_test, unsigned_duration) {
|
TEST(chrono_test, unsigned_duration) {
|
||||||
@ -620,6 +623,10 @@ TEST(chrono_test, cpp20_duration_subsecond_support) {
|
|||||||
// fixed precision, and print zeros even if there is no fractional part.
|
// fixed precision, and print zeros even if there is no fractional part.
|
||||||
EXPECT_EQ(fmt::format("{:%S}", std::chrono::microseconds{7000000}),
|
EXPECT_EQ(fmt::format("{:%S}", std::chrono::microseconds{7000000}),
|
||||||
"07.000000");
|
"07.000000");
|
||||||
|
EXPECT_EQ(fmt::format("{:%S}", std::chrono::duration<long long, std::ratio<1, 3>>(1)),
|
||||||
|
"00.333333");
|
||||||
|
EXPECT_EQ(fmt::format("{:%S}", std::chrono::duration<long long, std::ratio<1, 7>>(1)),
|
||||||
|
"00.142857");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FMT_STATIC_THOUSANDS_SEPARATOR
|
#endif // FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
|
@ -50,6 +50,12 @@ TEST(color_test, format) {
|
|||||||
"\x1b[105mtbmagenta\x1b[0m");
|
"\x1b[105mtbmagenta\x1b[0m");
|
||||||
EXPECT_EQ(fmt::format(fg(fmt::terminal_color::red), "{}", "foo"),
|
EXPECT_EQ(fmt::format(fg(fmt::terminal_color::red), "{}", "foo"),
|
||||||
"\x1b[31mfoo\x1b[0m");
|
"\x1b[31mfoo\x1b[0m");
|
||||||
|
EXPECT_EQ(fmt::format("{}{}", fmt::styled("red", fg(fmt::color::red)),
|
||||||
|
fmt::styled("bold", fmt::emphasis::bold)),
|
||||||
|
"\x1b[38;2;255;000;000mred\x1b[0m\x1b[1mbold\x1b[0m");
|
||||||
|
EXPECT_EQ(fmt::format("{}", fmt::styled("bar", fg(fmt::color::blue) |
|
||||||
|
fmt::emphasis::underline)),
|
||||||
|
"\x1b[4m\x1b[38;2;000;000;255mbar\x1b[0m");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(color_test, format_to) {
|
TEST(color_test, format_to) {
|
||||||
|
@ -6,6 +6,8 @@ project(compile-error-test CXX)
|
|||||||
set(fmt_headers "
|
set(fmt_headers "
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <fmt/xchar.h>
|
#include <fmt/xchar.h>
|
||||||
|
#include <fmt/ostream.h>
|
||||||
|
#include <iostream>
|
||||||
")
|
")
|
||||||
|
|
||||||
set(error_test_names "")
|
set(error_test_names "")
|
||||||
@ -154,6 +156,28 @@ expect_compile(format-function-error "
|
|||||||
fmt::format(\"{}\", f);
|
fmt::format(\"{}\", f);
|
||||||
" ERROR)
|
" ERROR)
|
||||||
|
|
||||||
|
# Formatting an unformattable argument should always be a compile time error
|
||||||
|
expect_compile(format-lots-of-arguments-with-unformattable "
|
||||||
|
struct E {};
|
||||||
|
fmt::format(\"\", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, E());
|
||||||
|
" ERROR)
|
||||||
|
expect_compile(format-lots-of-arguments-with-function "
|
||||||
|
void (*f)();
|
||||||
|
fmt::format(\"\", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, f);
|
||||||
|
" ERROR)
|
||||||
|
|
||||||
|
# Check if user-defined literals are available
|
||||||
|
include(CheckCXXSourceCompiles)
|
||||||
|
set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG})
|
||||||
|
check_cxx_source_compiles("
|
||||||
|
void operator\"\" _udl(long double);
|
||||||
|
int main() {}"
|
||||||
|
SUPPORTS_USER_DEFINED_LITERALS)
|
||||||
|
set(CMAKE_REQUIRED_FLAGS )
|
||||||
|
if (NOT SUPPORTS_USER_DEFINED_LITERALS)
|
||||||
|
set (SUPPORTS_USER_DEFINED_LITERALS OFF)
|
||||||
|
endif ()
|
||||||
|
|
||||||
# Make sure that compiler features detected in the header
|
# Make sure that compiler features detected in the header
|
||||||
# match the features detected in CMake.
|
# match the features detected in CMake.
|
||||||
if (SUPPORTS_USER_DEFINED_LITERALS)
|
if (SUPPORTS_USER_DEFINED_LITERALS)
|
||||||
@ -181,16 +205,30 @@ if (CMAKE_CXX_STANDARD GREATER_EQUAL 20)
|
|||||||
#error
|
#error
|
||||||
#endif
|
#endif
|
||||||
" ERROR)
|
" ERROR)
|
||||||
|
expect_compile(print-string-number-spec-error "
|
||||||
|
#ifdef FMT_HAS_CONSTEVAL
|
||||||
|
fmt::print(\"{:d}\", \"I am not a number\");
|
||||||
|
#else
|
||||||
|
#error
|
||||||
|
#endif
|
||||||
|
" ERROR)
|
||||||
|
expect_compile(print-stream-string-number-spec-error "
|
||||||
|
#ifdef FMT_HAS_CONSTEVAL
|
||||||
|
fmt::print(std::cout, \"{:d}\", \"I am not a number\");
|
||||||
|
#else
|
||||||
|
#error
|
||||||
|
#endif
|
||||||
|
" ERROR)
|
||||||
|
|
||||||
# Compile-time argument name check
|
# Compile-time argument name check
|
||||||
expect_compile(format-string-name "
|
expect_compile(format-string-name "
|
||||||
#if defined(FMT_HAS_CONSTEVAL) && FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
#if defined(FMT_HAS_CONSTEVAL) && FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||||
using namespace fmt::literals;
|
using namespace fmt::literals;
|
||||||
fmt::print(\"{foo}\", \"foo\"_a=42);
|
fmt::print(\"{foo}\", \"foo\"_a=42);
|
||||||
#endif
|
#endif
|
||||||
")
|
")
|
||||||
expect_compile(format-string-name-error "
|
expect_compile(format-string-name-error "
|
||||||
#if defined(FMT_HAS_CONSTEVAL) && FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
#if defined(FMT_HAS_CONSTEVAL) && FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||||
using namespace fmt::literals;
|
using namespace fmt::literals;
|
||||||
fmt::print(\"{foo}\", \"bar\"_a=42);
|
fmt::print(\"{foo}\", \"bar\"_a=42);
|
||||||
#else
|
#else
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806 && \
|
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806 && \
|
||||||
defined(__cpp_constexpr) && __cpp_constexpr >= 201907 && \
|
defined(__cpp_constexpr) && __cpp_constexpr >= 201907 && \
|
||||||
defined(__cpp_constexpr_dynamic_alloc) && \
|
defined(__cpp_constexpr_dynamic_alloc) && \
|
||||||
__cpp_constexpr_dynamic_alloc >= 201907 && __cplusplus >= 202002L
|
__cpp_constexpr_dynamic_alloc >= 201907 && FMT_CPLUSPLUS >= 202002L
|
||||||
template <size_t max_string_length, typename Char = char> struct test_string {
|
template <size_t max_string_length, typename Char = char> struct test_string {
|
||||||
template <typename T> constexpr bool operator==(const T& rhs) const noexcept {
|
template <typename T> constexpr bool operator==(const T& rhs) const noexcept {
|
||||||
return fmt::basic_string_view<Char>(rhs).compare(buffer) == 0;
|
return fmt::basic_string_view<Char>(rhs).compare(buffer) == 0;
|
||||||
|
@ -187,7 +187,7 @@ TEST(compile_test, named) {
|
|||||||
EXPECT_THROW(fmt::format(FMT_COMPILE("{invalid}"), fmt::arg("valid", 42)),
|
EXPECT_THROW(fmt::format(FMT_COMPILE("{invalid}"), fmt::arg("valid", 42)),
|
||||||
fmt::format_error);
|
fmt::format_error);
|
||||||
|
|
||||||
# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
# if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||||
using namespace fmt::literals;
|
using namespace fmt::literals;
|
||||||
auto statically_named_field_compiled =
|
auto statically_named_field_compiled =
|
||||||
fmt::detail::compile<decltype("arg"_a = 42)>(FMT_COMPILE("{arg}"));
|
fmt::detail::compile<decltype("arg"_a = 42)>(FMT_COMPILE("{arg}"));
|
||||||
@ -201,6 +201,11 @@ TEST(compile_test, named) {
|
|||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(compile_test, join) {
|
||||||
|
unsigned char data[] = {0x1, 0x2, 0xaf};
|
||||||
|
EXPECT_EQ("0102af", fmt::format(FMT_COMPILE("{:02x}"), fmt::join(data, "")));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(compile_test, format_to) {
|
TEST(compile_test, format_to) {
|
||||||
char buf[8];
|
char buf[8];
|
||||||
auto end = fmt::format_to(buf, FMT_COMPILE("{}"), 42);
|
auto end = fmt::format_to(buf, FMT_COMPILE("{}"), 42);
|
||||||
@ -280,7 +285,7 @@ TEST(compile_test, print) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||||
TEST(compile_test, compile_format_string_literal) {
|
TEST(compile_test, compile_format_string_literal) {
|
||||||
using namespace fmt::literals;
|
using namespace fmt::literals;
|
||||||
EXPECT_EQ("", fmt::format(""_cf));
|
EXPECT_EQ("", fmt::format(""_cf));
|
||||||
@ -289,8 +294,15 @@ TEST(compile_test, compile_format_string_literal) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __cplusplus >= 202002L || \
|
// MSVS 2019 19.29.30145.0 - Support C++20 and OK.
|
||||||
(__cplusplus >= 201709L && FMT_GCC_VERSION >= 1002)
|
// MSVS 2022 19.32.31332.0 - compile-test.cc(362,3): fatal error C1001: Internal
|
||||||
|
// compiler error.
|
||||||
|
// (compiler file
|
||||||
|
// 'D:\a\_work\1\s\src\vctools\Compiler\CxxFE\sl\p1\c\constexpr\constexpr.cpp',
|
||||||
|
// line 8635)
|
||||||
|
#if ((FMT_CPLUSPLUS >= 202002L) && \
|
||||||
|
(!FMT_MSC_VERSION || FMT_MSC_VERSION < 1930)) || \
|
||||||
|
(FMT_CPLUSPLUS >= 201709L && FMT_GCC_VERSION >= 1002)
|
||||||
template <size_t max_string_length, typename Char = char> struct test_string {
|
template <size_t max_string_length, typename Char = char> struct test_string {
|
||||||
template <typename T> constexpr bool operator==(const T& rhs) const noexcept {
|
template <typename T> constexpr bool operator==(const T& rhs) const noexcept {
|
||||||
return fmt::basic_string_view<Char>(rhs).compare(buffer) == 0;
|
return fmt::basic_string_view<Char>(rhs).compare(buffer) == 0;
|
||||||
|
@ -128,7 +128,7 @@ TEST(core_test, buffer_appender) {
|
|||||||
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470
|
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470
|
||||||
TEST(buffer_test, noncopyable) {
|
TEST(buffer_test, noncopyable) {
|
||||||
EXPECT_FALSE(std::is_copy_constructible<buffer<char>>::value);
|
EXPECT_FALSE(std::is_copy_constructible<buffer<char>>::value);
|
||||||
# if !FMT_MSC_VER
|
# if !FMT_MSC_VERSION
|
||||||
// std::is_copy_assignable is broken in MSVC2013.
|
// std::is_copy_assignable is broken in MSVC2013.
|
||||||
EXPECT_FALSE(std::is_copy_assignable<buffer<char>>::value);
|
EXPECT_FALSE(std::is_copy_assignable<buffer<char>>::value);
|
||||||
# endif
|
# endif
|
||||||
@ -136,7 +136,7 @@ TEST(buffer_test, noncopyable) {
|
|||||||
|
|
||||||
TEST(buffer_test, nonmoveable) {
|
TEST(buffer_test, nonmoveable) {
|
||||||
EXPECT_FALSE(std::is_move_constructible<buffer<char>>::value);
|
EXPECT_FALSE(std::is_move_constructible<buffer<char>>::value);
|
||||||
# if !FMT_MSC_VER
|
# if !FMT_MSC_VERSION
|
||||||
// std::is_move_assignable is broken in MSVC2013.
|
// std::is_move_assignable is broken in MSVC2013.
|
||||||
EXPECT_FALSE(std::is_move_assignable<buffer<char>>::value);
|
EXPECT_FALSE(std::is_move_assignable<buffer<char>>::value);
|
||||||
# endif
|
# endif
|
||||||
@ -385,11 +385,11 @@ VISIT_TYPE(unsigned long, unsigned long long);
|
|||||||
|
|
||||||
template <typename T> class numeric_arg_test : public testing::Test {};
|
template <typename T> class numeric_arg_test : public testing::Test {};
|
||||||
|
|
||||||
using types =
|
using test_types =
|
||||||
testing::Types<bool, signed char, unsigned char, short, unsigned short, int,
|
testing::Types<bool, signed char, unsigned char, short, unsigned short, int,
|
||||||
unsigned, long, unsigned long, long long, unsigned long long,
|
unsigned, long, unsigned long, long long, unsigned long long,
|
||||||
float, double, long double>;
|
float, double, long double>;
|
||||||
TYPED_TEST_SUITE(numeric_arg_test, types);
|
TYPED_TEST_SUITE(numeric_arg_test, test_types);
|
||||||
|
|
||||||
template <typename T, fmt::enable_if_t<std::is_integral<T>::value, int> = 0>
|
template <typename T, fmt::enable_if_t<std::is_integral<T>::value, int> = 0>
|
||||||
T test_value() {
|
T test_value() {
|
||||||
@ -679,6 +679,7 @@ TEST(format_test, constexpr_parse_format_string) {
|
|||||||
#endif // FMT_USE_CONSTEXPR
|
#endif // FMT_USE_CONSTEXPR
|
||||||
|
|
||||||
struct enabled_formatter {};
|
struct enabled_formatter {};
|
||||||
|
struct enabled_ptr_formatter {};
|
||||||
struct disabled_formatter {};
|
struct disabled_formatter {};
|
||||||
struct disabled_formatter_convertible {
|
struct disabled_formatter_convertible {
|
||||||
operator int() const { return 42; }
|
operator int() const { return 42; }
|
||||||
@ -693,6 +694,16 @@ template <> struct formatter<enabled_formatter> {
|
|||||||
return ctx.out();
|
return ctx.out();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <> struct formatter<enabled_ptr_formatter*> {
|
||||||
|
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
auto format(enabled_ptr_formatter*, format_context& ctx)
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
return ctx.out();
|
||||||
|
}
|
||||||
|
};
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
TEST(core_test, has_formatter) {
|
TEST(core_test, has_formatter) {
|
||||||
@ -737,7 +748,34 @@ struct convertible_to_pointer {
|
|||||||
operator const int*() const { return nullptr; }
|
operator const int*() const { return nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class test_scoped_enum {};
|
struct convertible_to_pointer_formattable {
|
||||||
|
operator const int*() const { return nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
template <> struct formatter<convertible_to_pointer_formattable> {
|
||||||
|
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto format(convertible_to_pointer_formattable, format_context& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
auto test = string_view("test");
|
||||||
|
return std::copy_n(test.data(), test.size(), ctx.out());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
enum class unformattable_scoped_enum {};
|
||||||
|
|
||||||
|
namespace test {
|
||||||
|
enum class formattable_scoped_enum {};
|
||||||
|
auto format_as(formattable_scoped_enum) -> int { return 42; }
|
||||||
|
|
||||||
|
struct convertible_to_enum {
|
||||||
|
operator formattable_scoped_enum() const { return {}; }
|
||||||
|
};
|
||||||
|
} // namespace test
|
||||||
|
|
||||||
TEST(core_test, is_formattable) {
|
TEST(core_test, is_formattable) {
|
||||||
#if 0
|
#if 0
|
||||||
@ -758,6 +796,7 @@ TEST(core_test, is_formattable) {
|
|||||||
static_assert(!fmt::is_formattable<fmt::basic_string_view<wchar_t>>::value,
|
static_assert(!fmt::is_formattable<fmt::basic_string_view<wchar_t>>::value,
|
||||||
"");
|
"");
|
||||||
static_assert(fmt::is_formattable<enabled_formatter>::value, "");
|
static_assert(fmt::is_formattable<enabled_formatter>::value, "");
|
||||||
|
static_assert(!fmt::is_formattable<enabled_ptr_formatter*>::value, "");
|
||||||
static_assert(!fmt::is_formattable<disabled_formatter>::value, "");
|
static_assert(!fmt::is_formattable<disabled_formatter>::value, "");
|
||||||
static_assert(fmt::is_formattable<disabled_formatter_convertible>::value, "");
|
static_assert(fmt::is_formattable<disabled_formatter_convertible>::value, "");
|
||||||
|
|
||||||
@ -765,19 +804,22 @@ TEST(core_test, is_formattable) {
|
|||||||
static_assert(fmt::is_formattable<const const_formattable&>::value, "");
|
static_assert(fmt::is_formattable<const const_formattable&>::value, "");
|
||||||
|
|
||||||
static_assert(fmt::is_formattable<nonconst_formattable&>::value, "");
|
static_assert(fmt::is_formattable<nonconst_formattable&>::value, "");
|
||||||
#if !FMT_MSC_VER || FMT_MSC_VER >= 1910
|
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
|
||||||
static_assert(!fmt::is_formattable<const nonconst_formattable&>::value, "");
|
static_assert(!fmt::is_formattable<const nonconst_formattable&>::value, "");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static_assert(!fmt::is_formattable<convertible_to_pointer>::value, "");
|
static_assert(!fmt::is_formattable<convertible_to_pointer>::value, "");
|
||||||
|
const auto f = convertible_to_pointer_formattable();
|
||||||
|
EXPECT_EQ(fmt::format("{}", f), "test");
|
||||||
|
|
||||||
static_assert(!fmt::is_formattable<void (*)()>::value, "");
|
static_assert(!fmt::is_formattable<void (*)()>::value, "");
|
||||||
|
|
||||||
struct s;
|
struct s;
|
||||||
|
|
||||||
static_assert(!fmt::is_formattable<int(s::*)>::value, "");
|
static_assert(!fmt::is_formattable<int(s::*)>::value, "");
|
||||||
static_assert(!fmt::is_formattable<int (s::*)()>::value, "");
|
static_assert(!fmt::is_formattable<int (s::*)()>::value, "");
|
||||||
static_assert(!fmt::is_formattable<test_scoped_enum>::value, "");
|
static_assert(!fmt::is_formattable<unformattable_scoped_enum>::value, "");
|
||||||
|
static_assert(fmt::is_formattable<test::formattable_scoped_enum>::value, "");
|
||||||
|
static_assert(!fmt::is_formattable<test::convertible_to_enum>::value, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(core_test, format) { EXPECT_EQ(fmt::format("{}", 42), "42"); }
|
TEST(core_test, format) { EXPECT_EQ(fmt::format("{}", 42), "42"); }
|
||||||
@ -788,6 +830,10 @@ TEST(core_test, format_to) {
|
|||||||
EXPECT_EQ(s, "42");
|
EXPECT_EQ(s, "42");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(core_test, format_as) {
|
||||||
|
EXPECT_EQ(fmt::format("{}", test::formattable_scoped_enum()), "42");
|
||||||
|
}
|
||||||
|
|
||||||
struct convertible_to_int {
|
struct convertible_to_int {
|
||||||
operator int() const { return 42; }
|
operator int() const { return 42; }
|
||||||
};
|
};
|
||||||
@ -850,13 +896,16 @@ TEST(core_test, format_implicitly_convertible_to_string_view) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// std::is_constructible is broken in MSVC until version 2015.
|
// std::is_constructible is broken in MSVC until version 2015.
|
||||||
#if !FMT_MSC_VER || FMT_MSC_VER >= 1900
|
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1900
|
||||||
struct explicitly_convertible_to_string_view {
|
struct explicitly_convertible_to_string_view {
|
||||||
explicit operator fmt::string_view() const { return "foo"; }
|
explicit operator fmt::string_view() const { return "foo"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(core_test, format_explicitly_convertible_to_string_view) {
|
TEST(core_test, format_explicitly_convertible_to_string_view) {
|
||||||
EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_view()));
|
// Types explicitly convertible to string_view are not formattable by
|
||||||
|
// default because it may introduce ODR violations.
|
||||||
|
static_assert(
|
||||||
|
!fmt::is_formattable<explicitly_convertible_to_string_view>::value, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
# ifdef FMT_USE_STRING_VIEW
|
# ifdef FMT_USE_STRING_VIEW
|
||||||
@ -865,8 +914,11 @@ struct explicitly_convertible_to_std_string_view {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TEST(core_test, format_explicitly_convertible_to_std_string_view) {
|
TEST(core_test, format_explicitly_convertible_to_std_string_view) {
|
||||||
EXPECT_EQ("foo",
|
// Types explicitly convertible to string_view are not formattable by
|
||||||
fmt::format("{}", explicitly_convertible_to_std_string_view()));
|
// default because it may introduce ODR violations.
|
||||||
|
static_assert(
|
||||||
|
!fmt::is_formattable<explicitly_convertible_to_std_string_view>::value,
|
||||||
|
"");
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
18
externals/dynarmic/externals/fmt/test/detect-stdfs.cc
vendored
Executable file
18
externals/dynarmic/externals/fmt/test/detect-stdfs.cc
vendored
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
// Formatting library for C++ - tests of formatters for standard library types
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#include <exception> // _GLIBCXX_RELEASE & _LIBCPP_VERSION
|
||||||
|
|
||||||
|
#if defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8
|
||||||
|
# error libfound "stdc++fs"
|
||||||
|
#elif !defined(__apple_build_version__) && defined(_LIBCPP_VERSION) && \
|
||||||
|
_LIBCPP_VERSION >= 7000 && _LIBCPP_VERSION < 9000
|
||||||
|
# error libfound "c++fs"
|
||||||
|
#else
|
||||||
|
// none if std::filesystem does not require additional libraries
|
||||||
|
# error libfound ""
|
||||||
|
#endif
|
@ -24,9 +24,9 @@ static_assert(!std::is_copy_constructible<bigint>::value, "");
|
|||||||
static_assert(!std::is_copy_assignable<bigint>::value, "");
|
static_assert(!std::is_copy_assignable<bigint>::value, "");
|
||||||
|
|
||||||
TEST(bigint_test, construct) {
|
TEST(bigint_test, construct) {
|
||||||
EXPECT_EQ("", fmt::format("{}", bigint()));
|
EXPECT_EQ(fmt::to_string(bigint()), "");
|
||||||
EXPECT_EQ("42", fmt::format("{}", bigint(0x42)));
|
EXPECT_EQ(fmt::to_string(bigint(0x42)), "42");
|
||||||
EXPECT_EQ("123456789abcedf0", fmt::format("{}", bigint(0x123456789abcedf0)));
|
EXPECT_EQ(fmt::to_string(bigint(0x123456789abcedf0)), "123456789abcedf0");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(bigint_test, compare) {
|
TEST(bigint_test, compare) {
|
||||||
@ -72,63 +72,56 @@ TEST(bigint_test, add_compare) {
|
|||||||
TEST(bigint_test, shift_left) {
|
TEST(bigint_test, shift_left) {
|
||||||
bigint n(0x42);
|
bigint n(0x42);
|
||||||
n <<= 0;
|
n <<= 0;
|
||||||
EXPECT_EQ("42", fmt::format("{}", n));
|
EXPECT_EQ(fmt::to_string(n), "42");
|
||||||
n <<= 1;
|
n <<= 1;
|
||||||
EXPECT_EQ("84", fmt::format("{}", n));
|
EXPECT_EQ(fmt::to_string(n), "84");
|
||||||
n <<= 25;
|
n <<= 25;
|
||||||
EXPECT_EQ("108000000", fmt::format("{}", n));
|
EXPECT_EQ(fmt::to_string(n), "108000000");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(bigint_test, multiply) {
|
TEST(bigint_test, multiply) {
|
||||||
bigint n(0x42);
|
bigint n(0x42);
|
||||||
EXPECT_THROW(n *= 0, assertion_failure);
|
EXPECT_THROW(n *= 0, assertion_failure);
|
||||||
n *= 1;
|
n *= 1;
|
||||||
EXPECT_EQ("42", fmt::format("{}", n));
|
EXPECT_EQ(fmt::to_string(n), "42");
|
||||||
|
|
||||||
n *= 2;
|
n *= 2;
|
||||||
EXPECT_EQ("84", fmt::format("{}", n));
|
EXPECT_EQ(fmt::to_string(n), "84");
|
||||||
n *= 0x12345678;
|
n *= 0x12345678;
|
||||||
EXPECT_EQ("962fc95e0", fmt::format("{}", n));
|
EXPECT_EQ(fmt::to_string(n), "962fc95e0");
|
||||||
|
|
||||||
bigint bigmax(max_value<uint32_t>());
|
bigint bigmax(max_value<uint32_t>());
|
||||||
bigmax *= max_value<uint32_t>();
|
bigmax *= max_value<uint32_t>();
|
||||||
EXPECT_EQ("fffffffe00000001", fmt::format("{}", bigmax));
|
EXPECT_EQ(fmt::to_string(bigmax), "fffffffe00000001");
|
||||||
bigmax.assign(max_value<uint64_t>());
|
|
||||||
bigmax *= max_value<uint64_t>();
|
|
||||||
EXPECT_EQ("fffffffffffffffe0000000000000001", fmt::format("{}", bigmax));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(bigint_test, accumulator) {
|
const auto max64 = max_value<uint64_t>();
|
||||||
fmt::detail::accumulator acc;
|
bigmax = max64;
|
||||||
EXPECT_EQ(acc.lower, 0);
|
bigmax *= max64;
|
||||||
EXPECT_EQ(acc.upper, 0);
|
EXPECT_EQ(fmt::to_string(bigmax), "fffffffffffffffe0000000000000001");
|
||||||
acc.upper = 12;
|
|
||||||
acc.lower = 34;
|
const auto max128 = (fmt::detail::uint128_t(max64) << 64) | max64;
|
||||||
EXPECT_EQ(static_cast<uint32_t>(acc), 34);
|
bigmax = max128;
|
||||||
acc += 56;
|
bigmax *= max128;
|
||||||
EXPECT_EQ(acc.lower, 90);
|
EXPECT_EQ(fmt::to_string(bigmax),
|
||||||
acc += max_value<uint64_t>();
|
"fffffffffffffffffffffffffffffffe00000000000000000000000000000001");
|
||||||
EXPECT_EQ(acc.upper, 13);
|
|
||||||
EXPECT_EQ(acc.lower, 89);
|
|
||||||
acc >>= 32;
|
|
||||||
EXPECT_EQ(acc.upper, 0);
|
|
||||||
EXPECT_EQ(acc.lower, 13 * 0x100000000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(bigint_test, square) {
|
TEST(bigint_test, square) {
|
||||||
bigint n0(0);
|
bigint n0(0);
|
||||||
n0.square();
|
n0.square();
|
||||||
EXPECT_EQ("0", fmt::format("{}", n0));
|
EXPECT_EQ(fmt::to_string(n0), "0");
|
||||||
bigint n1(0x100);
|
bigint n1(0x100);
|
||||||
n1.square();
|
n1.square();
|
||||||
EXPECT_EQ("10000", fmt::format("{}", n1));
|
EXPECT_EQ(fmt::to_string(n1), "10000");
|
||||||
bigint n2(0xfffffffff);
|
bigint n2(0xfffffffff);
|
||||||
n2.square();
|
n2.square();
|
||||||
EXPECT_EQ("ffffffffe000000001", fmt::format("{}", n2));
|
EXPECT_EQ(fmt::to_string(n2), "ffffffffe000000001");
|
||||||
bigint n3(max_value<uint64_t>());
|
bigint n3(max_value<uint64_t>());
|
||||||
n3.square();
|
n3.square();
|
||||||
EXPECT_EQ("fffffffffffffffe0000000000000001", fmt::format("{}", n3));
|
EXPECT_EQ(fmt::to_string(n3), "fffffffffffffffe0000000000000001");
|
||||||
bigint n4;
|
bigint n4;
|
||||||
n4.assign_pow10(10);
|
n4.assign_pow10(10);
|
||||||
EXPECT_EQ("2540be400", fmt::format("{}", n4));
|
EXPECT_EQ(fmt::to_string(n4), "2540be400");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(bigint_test, divmod_assign_zero_divisor) {
|
TEST(bigint_test, divmod_assign_zero_divisor) {
|
||||||
@ -150,8 +143,8 @@ TEST(bigint_test, divmod_assign_unaligned) {
|
|||||||
n2.assign_pow10(100);
|
n2.assign_pow10(100);
|
||||||
int result = n1.divmod_assign(n2);
|
int result = n1.divmod_assign(n2);
|
||||||
EXPECT_EQ(result, 9406);
|
EXPECT_EQ(result, 9406);
|
||||||
EXPECT_EQ("10f8353019583bfc29ffc8f564e1b9f9d819dbb4cf783e4507eca1539220p96",
|
EXPECT_EQ(fmt::to_string(n1),
|
||||||
fmt::format("{}", n1));
|
"10f8353019583bfc29ffc8f564e1b9f9d819dbb4cf783e4507eca1539220p96");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(bigint_test, divmod_assign) {
|
TEST(bigint_test, divmod_assign) {
|
||||||
@ -159,19 +152,19 @@ TEST(bigint_test, divmod_assign) {
|
|||||||
bigint n1(100);
|
bigint n1(100);
|
||||||
int result = n1.divmod_assign(bigint(10));
|
int result = n1.divmod_assign(bigint(10));
|
||||||
EXPECT_EQ(result, 10);
|
EXPECT_EQ(result, 10);
|
||||||
EXPECT_EQ("0", fmt::format("{}", n1));
|
EXPECT_EQ(fmt::to_string(n1), "0");
|
||||||
// pow(10, 100) / (42 << 320):
|
// pow(10, 100) / (42 << 320):
|
||||||
n1.assign_pow10(100);
|
n1.assign_pow10(100);
|
||||||
result = n1.divmod_assign(bigint(42) <<= 320);
|
result = n1.divmod_assign(bigint(42) <<= 320);
|
||||||
EXPECT_EQ(result, 111);
|
EXPECT_EQ(result, 111);
|
||||||
EXPECT_EQ("13ad2594c37ceb0b2784c4ce0bf38ace408e211a7caab24308a82e8f10p96",
|
EXPECT_EQ(fmt::to_string(n1),
|
||||||
fmt::format("{}", n1));
|
"13ad2594c37ceb0b2784c4ce0bf38ace408e211a7caab24308a82e8f10p96");
|
||||||
// 42 / 100:
|
// 42 / 100:
|
||||||
bigint n2(42);
|
bigint n2(42);
|
||||||
n1.assign_pow10(2);
|
n1.assign_pow10(2);
|
||||||
result = n2.divmod_assign(n1);
|
result = n2.divmod_assign(n1);
|
||||||
EXPECT_EQ(result, 0);
|
EXPECT_EQ(result, 0);
|
||||||
EXPECT_EQ("2a", fmt::format("{}", n2));
|
EXPECT_EQ(fmt::to_string(n2), "2a");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool is_iec559> void run_double_tests() {
|
template <bool is_iec559> void run_double_tests() {
|
||||||
@ -190,8 +183,8 @@ TEST(fp_test, double_tests) {
|
|||||||
TEST(fp_test, normalize) {
|
TEST(fp_test, normalize) {
|
||||||
const auto v = fp(0xbeef, 42);
|
const auto v = fp(0xbeef, 42);
|
||||||
auto normalized = normalize(v);
|
auto normalized = normalize(v);
|
||||||
EXPECT_EQ(0xbeef000000000000, normalized.f);
|
EXPECT_EQ(normalized.f, 0xbeef000000000000);
|
||||||
EXPECT_EQ(-6, normalized.e);
|
EXPECT_EQ(normalized.e, -6);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(fp_test, multiply) {
|
TEST(fp_test, multiply) {
|
||||||
@ -207,18 +200,18 @@ TEST(fp_test, get_cached_power) {
|
|||||||
using limits = std::numeric_limits<double>;
|
using limits = std::numeric_limits<double>;
|
||||||
for (auto exp = limits::min_exponent; exp <= limits::max_exponent; ++exp) {
|
for (auto exp = limits::min_exponent; exp <= limits::max_exponent; ++exp) {
|
||||||
int dec_exp = 0;
|
int dec_exp = 0;
|
||||||
auto fp = fmt::detail::get_cached_power(exp, dec_exp);
|
auto power = fmt::detail::get_cached_power(exp, dec_exp);
|
||||||
bigint exact, cache(fp.f);
|
bigint exact, cache(power.f);
|
||||||
if (dec_exp >= 0) {
|
if (dec_exp >= 0) {
|
||||||
exact.assign_pow10(dec_exp);
|
exact.assign_pow10(dec_exp);
|
||||||
if (fp.e <= 0)
|
if (power.e <= 0)
|
||||||
exact <<= -fp.e;
|
exact <<= -power.e;
|
||||||
else
|
else
|
||||||
cache <<= fp.e;
|
cache <<= power.e;
|
||||||
exact.align(cache);
|
exact.align(cache);
|
||||||
cache.align(exact);
|
cache.align(exact);
|
||||||
auto exact_str = fmt::format("{}", exact);
|
auto exact_str = fmt::to_string(exact);
|
||||||
auto cache_str = fmt::format("{}", cache);
|
auto cache_str = fmt::to_string(cache);
|
||||||
EXPECT_EQ(exact_str.size(), cache_str.size());
|
EXPECT_EQ(exact_str.size(), cache_str.size());
|
||||||
EXPECT_EQ(exact_str.substr(0, 15), cache_str.substr(0, 15));
|
EXPECT_EQ(exact_str.substr(0, 15), cache_str.substr(0, 15));
|
||||||
int diff = cache_str[15] - exact_str[15];
|
int diff = cache_str[15] - exact_str[15];
|
||||||
@ -228,12 +221,12 @@ TEST(fp_test, get_cached_power) {
|
|||||||
EXPECT_EQ(diff, 0);
|
EXPECT_EQ(diff, 0);
|
||||||
} else {
|
} else {
|
||||||
cache.assign_pow10(-dec_exp);
|
cache.assign_pow10(-dec_exp);
|
||||||
cache *= fp.f + 1; // Inexact check.
|
cache *= power.f + 1; // Inexact check.
|
||||||
exact.assign(1);
|
exact = 1;
|
||||||
exact <<= -fp.e;
|
exact <<= -power.e;
|
||||||
exact.align(cache);
|
exact.align(cache);
|
||||||
auto exact_str = fmt::format("{}", exact);
|
auto exact_str = fmt::to_string(exact);
|
||||||
auto cache_str = fmt::format("{}", cache);
|
auto cache_str = fmt::to_string(cache);
|
||||||
EXPECT_EQ(exact_str.size(), cache_str.size());
|
EXPECT_EQ(exact_str.size(), cache_str.size());
|
||||||
EXPECT_EQ(exact_str.substr(0, 16), cache_str.substr(0, 16));
|
EXPECT_EQ(exact_str.substr(0, 16), cache_str.substr(0, 16));
|
||||||
}
|
}
|
||||||
@ -243,38 +236,41 @@ TEST(fp_test, get_cached_power) {
|
|||||||
TEST(fp_test, dragonbox_max_k) {
|
TEST(fp_test, dragonbox_max_k) {
|
||||||
using fmt::detail::dragonbox::floor_log10_pow2;
|
using fmt::detail::dragonbox::floor_log10_pow2;
|
||||||
using float_info = fmt::detail::dragonbox::float_info<float>;
|
using float_info = fmt::detail::dragonbox::float_info<float>;
|
||||||
EXPECT_EQ(fmt::detail::const_check(float_info::max_k),
|
EXPECT_EQ(
|
||||||
float_info::kappa - floor_log10_pow2(float_info::min_exponent -
|
fmt::detail::const_check(float_info::max_k),
|
||||||
float_info::significand_bits));
|
float_info::kappa -
|
||||||
|
floor_log10_pow2(std::numeric_limits<float>::min_exponent -
|
||||||
|
fmt::detail::num_significand_bits<float>() - 1));
|
||||||
using double_info = fmt::detail::dragonbox::float_info<double>;
|
using double_info = fmt::detail::dragonbox::float_info<double>;
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
fmt::detail::const_check(double_info::max_k),
|
fmt::detail::const_check(double_info::max_k),
|
||||||
double_info::kappa - floor_log10_pow2(double_info::min_exponent -
|
double_info::kappa -
|
||||||
double_info::significand_bits));
|
floor_log10_pow2(std::numeric_limits<double>::min_exponent -
|
||||||
|
fmt::detail::num_significand_bits<double>() - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(fp_test, get_round_direction) {
|
TEST(fp_test, get_round_direction) {
|
||||||
using fmt::detail::get_round_direction;
|
using fmt::detail::get_round_direction;
|
||||||
using fmt::detail::round_direction;
|
using fmt::detail::round_direction;
|
||||||
EXPECT_EQ(round_direction::down, get_round_direction(100, 50, 0));
|
EXPECT_EQ(get_round_direction(100, 50, 0), round_direction::down);
|
||||||
EXPECT_EQ(round_direction::up, get_round_direction(100, 51, 0));
|
EXPECT_EQ(get_round_direction(100, 51, 0), round_direction::up);
|
||||||
EXPECT_EQ(round_direction::down, get_round_direction(100, 40, 10));
|
EXPECT_EQ(get_round_direction(100, 40, 10), round_direction::down);
|
||||||
EXPECT_EQ(round_direction::up, get_round_direction(100, 60, 10));
|
EXPECT_EQ(get_round_direction(100, 60, 10), round_direction::up);
|
||||||
for (size_t i = 41; i < 60; ++i)
|
for (size_t i = 41; i < 60; ++i)
|
||||||
EXPECT_EQ(round_direction::unknown, get_round_direction(100, i, 10));
|
EXPECT_EQ(get_round_direction(100, i, 10), round_direction::unknown);
|
||||||
uint64_t max = max_value<uint64_t>();
|
uint64_t max = max_value<uint64_t>();
|
||||||
EXPECT_THROW(get_round_direction(100, 100, 0), assertion_failure);
|
EXPECT_THROW(get_round_direction(100, 100, 0), assertion_failure);
|
||||||
EXPECT_THROW(get_round_direction(100, 0, 100), assertion_failure);
|
EXPECT_THROW(get_round_direction(100, 0, 100), assertion_failure);
|
||||||
EXPECT_THROW(get_round_direction(100, 0, 50), assertion_failure);
|
EXPECT_THROW(get_round_direction(100, 0, 50), assertion_failure);
|
||||||
// Check that remainder + error doesn't overflow.
|
// Check that remainder + error doesn't overflow.
|
||||||
EXPECT_EQ(round_direction::up, get_round_direction(max, max - 1, 2));
|
EXPECT_EQ(get_round_direction(max, max - 1, 2), round_direction::up);
|
||||||
// Check that 2 * (remainder + error) doesn't overflow.
|
// Check that 2 * (remainder + error) doesn't overflow.
|
||||||
EXPECT_EQ(round_direction::unknown,
|
EXPECT_EQ(get_round_direction(max, max / 2 + 1, max / 2),
|
||||||
get_round_direction(max, max / 2 + 1, max / 2));
|
round_direction::unknown);
|
||||||
// Check that remainder - error doesn't overflow.
|
// Check that remainder - error doesn't overflow.
|
||||||
EXPECT_EQ(round_direction::unknown, get_round_direction(100, 40, 41));
|
EXPECT_EQ(get_round_direction(100, 40, 41), round_direction::unknown);
|
||||||
// Check that 2 * (remainder - error) doesn't overflow.
|
// Check that 2 * (remainder - error) doesn't overflow.
|
||||||
EXPECT_EQ(round_direction::up, get_round_direction(max, max - 1, 1));
|
EXPECT_EQ(get_round_direction(max, max - 1, 1), round_direction::up);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(fp_test, fixed_handler) {
|
TEST(fp_test, fixed_handler) {
|
||||||
@ -297,20 +293,20 @@ TEST(fp_test, fixed_handler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(fp_test, grisu_format_compiles_with_on_ieee_double) {
|
TEST(fp_test, grisu_format_compiles_with_on_ieee_double) {
|
||||||
fmt::memory_buffer buf;
|
auto buf = fmt::memory_buffer();
|
||||||
format_float(0.42, -1, fmt::detail::float_specs(), buf);
|
format_float(0.42, -1, fmt::detail::float_specs(), buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_impl_test, format_error_code) {
|
TEST(format_impl_test, format_error_code) {
|
||||||
std::string msg = "error 42", sep = ": ";
|
std::string msg = "error 42", sep = ": ";
|
||||||
{
|
{
|
||||||
fmt::memory_buffer buffer;
|
auto buffer = fmt::memory_buffer();
|
||||||
format_to(fmt::appender(buffer), "garbage");
|
format_to(fmt::appender(buffer), "garbage");
|
||||||
fmt::detail::format_error_code(buffer, 42, "test");
|
fmt::detail::format_error_code(buffer, 42, "test");
|
||||||
EXPECT_EQ("test: " + msg, to_string(buffer));
|
EXPECT_EQ(to_string(buffer), "test: " + msg);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
fmt::memory_buffer buffer;
|
auto buffer = fmt::memory_buffer();
|
||||||
auto prefix =
|
auto prefix =
|
||||||
std::string(fmt::inline_buffer_size - msg.size() - sep.size() + 1, 'x');
|
std::string(fmt::inline_buffer_size - msg.size() - sep.size() + 1, 'x');
|
||||||
fmt::detail::format_error_code(buffer, 42, prefix);
|
fmt::detail::format_error_code(buffer, 42, prefix);
|
||||||
@ -331,7 +327,7 @@ TEST(format_impl_test, format_error_code) {
|
|||||||
// Test with a message that doesn't fit into the buffer.
|
// Test with a message that doesn't fit into the buffer.
|
||||||
prefix += 'x';
|
prefix += 'x';
|
||||||
fmt::detail::format_error_code(buffer, codes[i], prefix);
|
fmt::detail::format_error_code(buffer, codes[i], prefix);
|
||||||
EXPECT_EQ(msg, to_string(buffer));
|
EXPECT_EQ(to_string(buffer), msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,8 +343,8 @@ template <typename Int> void test_count_digits() {
|
|||||||
for (Int i = 0; i < 10; ++i) EXPECT_EQ(1u, fmt::detail::count_digits(i));
|
for (Int i = 0; i < 10; ++i) EXPECT_EQ(1u, fmt::detail::count_digits(i));
|
||||||
for (Int i = 1, n = 1, end = max_value<Int>() / 10; n <= end; ++i) {
|
for (Int i = 1, n = 1, end = max_value<Int>() / 10; n <= end; ++i) {
|
||||||
n *= 10;
|
n *= 10;
|
||||||
EXPECT_EQ(i, fmt::detail::count_digits(n - 1));
|
EXPECT_EQ(fmt::detail::count_digits(n - 1), i);
|
||||||
EXPECT_EQ(i + 1, fmt::detail::count_digits(n));
|
EXPECT_EQ(fmt::detail::count_digits(n), i + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,21 +353,51 @@ TEST(format_impl_test, count_digits) {
|
|||||||
test_count_digits<uint64_t>();
|
test_count_digits<uint64_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_impl_test, write_fallback_uintptr) {
|
#if FMT_USE_FLOAT128
|
||||||
std::string s;
|
TEST(format_impl_test, write_float128) {
|
||||||
fmt::detail::write_ptr<char>(
|
auto s = std::string();
|
||||||
std::back_inserter(s),
|
fmt::detail::write<char>(std::back_inserter(s), __float128(42));
|
||||||
fmt::detail::fallback_uintptr(reinterpret_cast<void*>(0xface)), nullptr);
|
EXPECT_EQ(s, "42");
|
||||||
EXPECT_EQ(s, "0xface");
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct double_double {
|
||||||
|
double a;
|
||||||
|
double b;
|
||||||
|
|
||||||
|
explicit constexpr double_double(double a_val = 0, double b_val = 0)
|
||||||
|
: a(a_val), b(b_val) {}
|
||||||
|
|
||||||
|
operator double() const { return a + b; }
|
||||||
|
auto operator-() const -> double_double { return double_double(-a, -b); }
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator>=(const double_double& lhs, const double_double& rhs) {
|
||||||
|
return lhs.a + lhs.b >= rhs.a + rhs.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template <> struct is_floating_point<double_double> : std::true_type {};
|
||||||
|
template <> struct numeric_limits<double_double> {
|
||||||
|
// is_iec559 is true for double-double in libstdc++.
|
||||||
|
static constexpr bool is_iec559 = true;
|
||||||
|
static constexpr int digits = 106;
|
||||||
|
};
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
TEST(format_impl_test, write_double_double) {
|
||||||
|
auto s = std::string();
|
||||||
|
fmt::detail::write<char>(std::back_inserter(s), double_double(42), {});
|
||||||
|
#ifndef _MSC_VER // MSVC has an issue with specializing is_floating_point.
|
||||||
|
EXPECT_EQ(s, "42");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
TEST(format_impl_test, write_console_signature) {
|
TEST(format_impl_test, write_console_signature) {
|
||||||
decltype(WriteConsoleW)* p = fmt::detail::WriteConsoleW;
|
decltype(::WriteConsoleW)* p = fmt::detail::WriteConsoleW;
|
||||||
(void)p;
|
(void)p;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
257
externals/dynarmic/externals/fmt/test/format-test.cc
vendored
257
externals/dynarmic/externals/fmt/test/format-test.cc
vendored
@ -33,12 +33,98 @@ using fmt::memory_buffer;
|
|||||||
using fmt::runtime;
|
using fmt::runtime;
|
||||||
using fmt::string_view;
|
using fmt::string_view;
|
||||||
using fmt::detail::max_value;
|
using fmt::detail::max_value;
|
||||||
|
using fmt::detail::uint128_fallback;
|
||||||
|
|
||||||
using testing::Return;
|
using testing::Return;
|
||||||
using testing::StrictMock;
|
using testing::StrictMock;
|
||||||
|
|
||||||
enum { buffer_size = 256 };
|
enum { buffer_size = 256 };
|
||||||
|
|
||||||
|
TEST(uint128_test, ctor) {
|
||||||
|
auto n = uint128_fallback();
|
||||||
|
EXPECT_EQ(n, 0);
|
||||||
|
n = uint128_fallback(42);
|
||||||
|
EXPECT_EQ(n, 42);
|
||||||
|
EXPECT_EQ(static_cast<uint64_t>(n), 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(uint128_test, shift) {
|
||||||
|
auto n = uint128_fallback(42);
|
||||||
|
n = n << 64;
|
||||||
|
EXPECT_EQ(static_cast<uint64_t>(n), 0);
|
||||||
|
n = n >> 64;
|
||||||
|
EXPECT_EQ(static_cast<uint64_t>(n), 42);
|
||||||
|
n = n << 62;
|
||||||
|
EXPECT_EQ(static_cast<uint64_t>(n >> 64), 0xa);
|
||||||
|
EXPECT_EQ(static_cast<uint64_t>(n), 0x8000000000000000);
|
||||||
|
n = n >> 62;
|
||||||
|
EXPECT_EQ(static_cast<uint64_t>(n), 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(uint128_test, minus) {
|
||||||
|
auto n = uint128_fallback(42);
|
||||||
|
EXPECT_EQ(n - 2, 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(uint128_test, plus_assign) {
|
||||||
|
auto n = uint128_fallback(32);
|
||||||
|
n += uint128_fallback(10);
|
||||||
|
EXPECT_EQ(n, 42);
|
||||||
|
n = uint128_fallback(max_value<uint64_t>());
|
||||||
|
n += uint128_fallback(1);
|
||||||
|
EXPECT_EQ(n, uint128_fallback(1) << 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(uint128_test, multiply) {
|
||||||
|
auto n = uint128_fallback(2251799813685247);
|
||||||
|
n = n * 3611864890;
|
||||||
|
EXPECT_EQ(static_cast<uint64_t>(n >> 64), 440901);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Float> void check_isfinite() {
|
||||||
|
using fmt::detail::isfinite;
|
||||||
|
EXPECT_TRUE(isfinite(Float(0.0)));
|
||||||
|
EXPECT_TRUE(isfinite(Float(42.0)));
|
||||||
|
EXPECT_TRUE(isfinite(Float(-42.0)));
|
||||||
|
EXPECT_TRUE(isfinite(Float(fmt::detail::max_value<double>())));
|
||||||
|
// Use double because std::numeric_limits is broken for __float128.
|
||||||
|
using limits = std::numeric_limits<double>;
|
||||||
|
FMT_CONSTEXPR20 auto result = isfinite(Float(limits::infinity()));
|
||||||
|
EXPECT_FALSE(result);
|
||||||
|
EXPECT_FALSE(isfinite(Float(limits::infinity())));
|
||||||
|
EXPECT_FALSE(isfinite(Float(-limits::infinity())));
|
||||||
|
EXPECT_FALSE(isfinite(Float(limits::quiet_NaN())));
|
||||||
|
EXPECT_FALSE(isfinite(Float(-limits::quiet_NaN())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(float_test, isfinite) {
|
||||||
|
check_isfinite<double>();
|
||||||
|
#ifdef __SIZEOF_FLOAT128__
|
||||||
|
check_isfinite<fmt::detail::float128>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Float> void check_isnan() {
|
||||||
|
using fmt::detail::isnan;
|
||||||
|
EXPECT_FALSE(isnan(Float(0.0)));
|
||||||
|
EXPECT_FALSE(isnan(Float(42.0)));
|
||||||
|
EXPECT_FALSE(isnan(Float(-42.0)));
|
||||||
|
EXPECT_FALSE(isnan(Float(fmt::detail::max_value<double>())));
|
||||||
|
// Use double because std::numeric_limits is broken for __float128.
|
||||||
|
using limits = std::numeric_limits<double>;
|
||||||
|
EXPECT_FALSE(isnan(Float(limits::infinity())));
|
||||||
|
EXPECT_FALSE(isnan(Float(-limits::infinity())));
|
||||||
|
EXPECT_TRUE(isnan(Float(limits::quiet_NaN())));
|
||||||
|
EXPECT_TRUE(isnan(Float(-limits::quiet_NaN())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(float_test, isnan) {
|
||||||
|
check_isnan<double>();
|
||||||
|
#ifdef __SIZEOF_FLOAT128__
|
||||||
|
check_isnan<fmt::detail::float128>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
struct uint32_pair {
|
struct uint32_pair {
|
||||||
uint32_t u[2];
|
uint32_t u[2];
|
||||||
};
|
};
|
||||||
@ -223,8 +309,9 @@ TEST(memory_buffer_test, move_ctor_dynamic_buffer) {
|
|||||||
buffer.push_back('a');
|
buffer.push_back('a');
|
||||||
basic_memory_buffer<char, 4, std_allocator> buffer2(std::move(buffer));
|
basic_memory_buffer<char, 4, std_allocator> buffer2(std::move(buffer));
|
||||||
// Move should rip the guts of the first buffer.
|
// Move should rip the guts of the first buffer.
|
||||||
EXPECT_EQ(inline_buffer_ptr, &buffer[0]);
|
EXPECT_EQ(&buffer[0], inline_buffer_ptr);
|
||||||
EXPECT_EQ("testa", std::string(&buffer2[0], buffer2.size()));
|
EXPECT_EQ(buffer.size(), 0);
|
||||||
|
EXPECT_EQ(std::string(&buffer2[0], buffer2.size()), "testa");
|
||||||
EXPECT_GT(buffer2.capacity(), 4u);
|
EXPECT_GT(buffer2.capacity(), 4u);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,7 +412,7 @@ template <typename Allocator, size_t MaxSize>
|
|||||||
class max_size_allocator : public Allocator {
|
class max_size_allocator : public Allocator {
|
||||||
public:
|
public:
|
||||||
using typename Allocator::value_type;
|
using typename Allocator::value_type;
|
||||||
size_t max_size() const FMT_NOEXCEPT { return MaxSize; }
|
size_t max_size() const noexcept { return MaxSize; }
|
||||||
value_type* allocate(size_t n) {
|
value_type* allocate(size_t n) {
|
||||||
if (n > max_size()) {
|
if (n > max_size()) {
|
||||||
throw std::length_error("size > max_size");
|
throw std::length_error("size > max_size");
|
||||||
@ -570,6 +657,9 @@ TEST(format_test, plus_sign) {
|
|||||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), 42ul), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), 42ul), format_error,
|
||||||
"format specifier requires signed argument");
|
"format specifier requires signed argument");
|
||||||
EXPECT_EQ("+42", fmt::format("{0:+}", 42ll));
|
EXPECT_EQ("+42", fmt::format("{0:+}", 42ll));
|
||||||
|
#if FMT_USE_INT128
|
||||||
|
EXPECT_EQ("+42", fmt::format("{0:+}", __int128_t(42)));
|
||||||
|
#endif
|
||||||
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), 42ull), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), 42ull), format_error,
|
||||||
"format specifier requires signed argument");
|
"format specifier requires signed argument");
|
||||||
EXPECT_EQ("+42", fmt::format("{0:+}", 42.0));
|
EXPECT_EQ("+42", fmt::format("{0:+}", 42.0));
|
||||||
@ -918,6 +1008,14 @@ TEST(format_test, precision) {
|
|||||||
EXPECT_THAT(outputs,
|
EXPECT_THAT(outputs,
|
||||||
testing::Contains(fmt::format("{:.838A}", -2.14001164E+38)));
|
testing::Contains(fmt::format("{:.838A}", -2.14001164E+38)));
|
||||||
|
|
||||||
|
if (std::numeric_limits<long double>::digits == 64) {
|
||||||
|
auto ld = (std::numeric_limits<long double>::min)();
|
||||||
|
EXPECT_EQ(fmt::format("{:.0}", ld), "3e-4932");
|
||||||
|
EXPECT_EQ(
|
||||||
|
fmt::format("{:0g}", std::numeric_limits<long double>::denorm_min()),
|
||||||
|
"3.6452e-4951");
|
||||||
|
}
|
||||||
|
|
||||||
EXPECT_EQ("123.", fmt::format("{:#.0f}", 123.0));
|
EXPECT_EQ("123.", fmt::format("{:#.0f}", 123.0));
|
||||||
EXPECT_EQ("1.23", fmt::format("{:.02f}", 1.234));
|
EXPECT_EQ("1.23", fmt::format("{:.02f}", 1.234));
|
||||||
EXPECT_EQ("0.001", fmt::format("{:.1g}", 0.001));
|
EXPECT_EQ("0.001", fmt::format("{:.1g}", 0.001));
|
||||||
@ -939,6 +1037,7 @@ TEST(format_test, precision) {
|
|||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
|
|
||||||
EXPECT_EQ("st", fmt::format("{0:.2}", "str"));
|
EXPECT_EQ("st", fmt::format("{0:.2}", "str"));
|
||||||
|
EXPECT_EQ("вожык", fmt::format("{0:.5}", "вожыкі"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, runtime_precision) {
|
TEST(format_test, runtime_precision) {
|
||||||
@ -1060,7 +1159,7 @@ TEST(format_test, format_short) {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
void check_unknown_types(const T& value, const char* types, const char*) {
|
void check_unknown_types(const T& value, const char* types, const char*) {
|
||||||
char format_str[buffer_size];
|
char format_str[buffer_size];
|
||||||
const char* special = ".0123456789L}";
|
const char* special = ".0123456789L?}";
|
||||||
for (int i = CHAR_MIN; i <= CHAR_MAX; ++i) {
|
for (int i = CHAR_MIN; i <= CHAR_MAX; ++i) {
|
||||||
char c = static_cast<char>(i);
|
char c = static_cast<char>(i);
|
||||||
if (std::strchr(types, c) || std::strchr(special, c) || !c) continue;
|
if (std::strchr(types, c) || std::strchr(special, c) || !c) continue;
|
||||||
@ -1229,32 +1328,30 @@ TEST(format_test, format_float) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, format_double) {
|
TEST(format_test, format_double) {
|
||||||
EXPECT_EQ("0", fmt::format("{}", 0.0));
|
EXPECT_EQ(fmt::format("{}", 0.0), "0");
|
||||||
check_unknown_types(1.2, "eEfFgGaAnL%", "double");
|
check_unknown_types(1.2, "eEfFgGaAnL%", "double");
|
||||||
EXPECT_EQ("0", fmt::format("{:}", 0.0));
|
EXPECT_EQ(fmt::format("{:}", 0.0), "0");
|
||||||
EXPECT_EQ("0.000000", fmt::format("{:f}", 0.0));
|
EXPECT_EQ(fmt::format("{:f}", 0.0), "0.000000");
|
||||||
EXPECT_EQ("0", fmt::format("{:g}", 0.0));
|
EXPECT_EQ(fmt::format("{:g}", 0.0), "0");
|
||||||
EXPECT_EQ("392.65", fmt::format("{:}", 392.65));
|
EXPECT_EQ(fmt::format("{:}", 392.65), "392.65");
|
||||||
EXPECT_EQ("392.65", fmt::format("{:g}", 392.65));
|
EXPECT_EQ(fmt::format("{:g}", 392.65), "392.65");
|
||||||
EXPECT_EQ("392.65", fmt::format("{:G}", 392.65));
|
EXPECT_EQ(fmt::format("{:G}", 392.65), "392.65");
|
||||||
EXPECT_EQ("4.9014e+06", fmt::format("{:g}", 4.9014e6));
|
EXPECT_EQ(fmt::format("{:g}", 4.9014e6), "4.9014e+06");
|
||||||
EXPECT_EQ("392.650000", fmt::format("{:f}", 392.65));
|
EXPECT_EQ(fmt::format("{:f}", 392.65), "392.650000");
|
||||||
EXPECT_EQ("392.650000", fmt::format("{:F}", 392.65));
|
EXPECT_EQ(fmt::format("{:F}", 392.65), "392.650000");
|
||||||
EXPECT_EQ("42", fmt::format("{:L}", 42.0));
|
EXPECT_EQ(fmt::format("{:L}", 42.0), "42");
|
||||||
EXPECT_EQ(" 0x1.0cccccccccccdp+2", fmt::format("{:24a}", 4.2));
|
EXPECT_EQ(fmt::format("{:24a}", 4.2), " 0x1.0cccccccccccdp+2");
|
||||||
EXPECT_EQ("0x1.0cccccccccccdp+2 ", fmt::format("{:<24a}", 4.2));
|
EXPECT_EQ(fmt::format("{:<24a}", 4.2), "0x1.0cccccccccccdp+2 ");
|
||||||
|
EXPECT_EQ(fmt::format("{0:e}", 392.65), "3.926500e+02");
|
||||||
|
EXPECT_EQ(fmt::format("{0:E}", 392.65), "3.926500E+02");
|
||||||
|
EXPECT_EQ(fmt::format("{0:+010.4g}", 392.65), "+0000392.6");
|
||||||
char buffer[buffer_size];
|
char buffer[buffer_size];
|
||||||
safe_sprintf(buffer, "%e", 392.65);
|
|
||||||
EXPECT_EQ(buffer, fmt::format("{0:e}", 392.65));
|
|
||||||
safe_sprintf(buffer, "%E", 392.65);
|
|
||||||
EXPECT_EQ(buffer, fmt::format("{0:E}", 392.65));
|
|
||||||
EXPECT_EQ("+0000392.6", fmt::format("{0:+010.4g}", 392.65));
|
|
||||||
safe_sprintf(buffer, "%a", -42.0);
|
safe_sprintf(buffer, "%a", -42.0);
|
||||||
EXPECT_EQ(buffer, fmt::format("{:a}", -42.0));
|
EXPECT_EQ(fmt::format("{:a}", -42.0), buffer);
|
||||||
safe_sprintf(buffer, "%A", -42.0);
|
safe_sprintf(buffer, "%A", -42.0);
|
||||||
EXPECT_EQ(buffer, fmt::format("{:A}", -42.0));
|
EXPECT_EQ(fmt::format("{:A}", -42.0), buffer);
|
||||||
EXPECT_EQ("9223372036854775808.000000",
|
EXPECT_EQ(fmt::format("{:f}", 9223372036854775807.0),
|
||||||
fmt::format("{:f}", 9223372036854775807.0));
|
"9223372036854775808.000000");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, precision_rounding) {
|
TEST(format_test, precision_rounding) {
|
||||||
@ -1363,6 +1460,9 @@ TEST(format_test, format_char) {
|
|||||||
<< format_str;
|
<< format_str;
|
||||||
}
|
}
|
||||||
EXPECT_EQ(fmt::format("{:02X}", n), fmt::format("{:02X}", 'x'));
|
EXPECT_EQ(fmt::format("{:02X}", n), fmt::format("{:02X}", 'x'));
|
||||||
|
|
||||||
|
EXPECT_EQ("\n", fmt::format("{}", '\n'));
|
||||||
|
EXPECT_EQ("'\\n'", fmt::format("{:?}", '\n'));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, format_volatile_char) {
|
TEST(format_test, format_volatile_char) {
|
||||||
@ -1393,7 +1493,11 @@ TEST(format_test, format_pointer) {
|
|||||||
EXPECT_EQ("0x0", fmt::format("{0}", static_cast<void*>(nullptr)));
|
EXPECT_EQ("0x0", fmt::format("{0}", static_cast<void*>(nullptr)));
|
||||||
EXPECT_EQ("0x1234", fmt::format("{0}", reinterpret_cast<void*>(0x1234)));
|
EXPECT_EQ("0x1234", fmt::format("{0}", reinterpret_cast<void*>(0x1234)));
|
||||||
EXPECT_EQ("0x1234", fmt::format("{0:p}", reinterpret_cast<void*>(0x1234)));
|
EXPECT_EQ("0x1234", fmt::format("{0:p}", reinterpret_cast<void*>(0x1234)));
|
||||||
EXPECT_EQ("0x" + std::string(sizeof(void*) * CHAR_BIT / 4, 'f'),
|
// On CHERI (or other fat-pointer) systems, the size of a pointer is greater
|
||||||
|
// than the size an integer that can hold a virtual address. There is no
|
||||||
|
// portable address-as-an-integer type (yet) in C++, so we use `size_t` as
|
||||||
|
// the closest equivalent for now.
|
||||||
|
EXPECT_EQ("0x" + std::string(sizeof(size_t) * CHAR_BIT / 4, 'f'),
|
||||||
fmt::format("{0}", reinterpret_cast<void*>(~uintptr_t())));
|
fmt::format("{0}", reinterpret_cast<void*>(~uintptr_t())));
|
||||||
EXPECT_EQ("0x1234",
|
EXPECT_EQ("0x1234",
|
||||||
fmt::format("{}", fmt::ptr(reinterpret_cast<int*>(0x1234))));
|
fmt::format("{}", fmt::ptr(reinterpret_cast<int*>(0x1234))));
|
||||||
@ -1409,14 +1513,43 @@ TEST(format_test, format_pointer) {
|
|||||||
EXPECT_EQ("0x0", fmt::format("{}", nullptr));
|
EXPECT_EQ("0x0", fmt::format("{}", nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(format_test, write_uintptr_fallback) {
|
||||||
|
// Test that formatting a pointer by converting it to uint128_fallback works.
|
||||||
|
// This is needed to support systems without uintptr_t.
|
||||||
|
auto s = std::string();
|
||||||
|
fmt::detail::write_ptr<char>(
|
||||||
|
std::back_inserter(s),
|
||||||
|
fmt::detail::bit_cast<fmt::detail::uint128_fallback>(
|
||||||
|
reinterpret_cast<void*>(0xface)),
|
||||||
|
nullptr);
|
||||||
|
EXPECT_EQ(s, "0xface");
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class color { red, green, blue };
|
||||||
|
|
||||||
|
namespace test_ns {
|
||||||
|
enum class color { red, green, blue };
|
||||||
|
using fmt::enums::format_as;
|
||||||
|
} // namespace test_ns
|
||||||
|
|
||||||
|
TEST(format_test, format_enum_class) {
|
||||||
|
EXPECT_EQ(fmt::format("{}", fmt::underlying(color::red)), "0");
|
||||||
|
EXPECT_EQ(fmt::format("{}", test_ns::color::red), "0");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(format_test, format_string) {
|
TEST(format_test, format_string) {
|
||||||
EXPECT_EQ("test", fmt::format("{0}", std::string("test")));
|
EXPECT_EQ(fmt::format("{0}", std::string("test")), "test");
|
||||||
|
EXPECT_EQ(fmt::format("{0}", std::string("test")), "test");
|
||||||
|
EXPECT_EQ(fmt::format("{:?}", std::string("test")), "\"test\"");
|
||||||
|
EXPECT_EQ(fmt::format("{:*^10?}", std::string("test")), "**\"test\"**");
|
||||||
|
EXPECT_EQ(fmt::format("{:?}", std::string("\test")), "\"\\test\"");
|
||||||
EXPECT_THROW((void)fmt::format(fmt::runtime("{:x}"), std::string("test")),
|
EXPECT_THROW((void)fmt::format(fmt::runtime("{:x}"), std::string("test")),
|
||||||
fmt::format_error);
|
fmt::format_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, format_string_view) {
|
TEST(format_test, format_string_view) {
|
||||||
EXPECT_EQ("test", fmt::format("{}", string_view("test")));
|
EXPECT_EQ("test", fmt::format("{}", string_view("test")));
|
||||||
|
EXPECT_EQ("\"t\\nst\"", fmt::format("{:?}", string_view("t\nst")));
|
||||||
EXPECT_EQ("", fmt::format("{}", string_view()));
|
EXPECT_EQ("", fmt::format("{}", string_view()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1623,6 +1756,7 @@ TEST(format_test, group_digits_view) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum test_enum { foo, bar };
|
enum test_enum { foo, bar };
|
||||||
|
auto format_as(test_enum e) -> int { return e; }
|
||||||
|
|
||||||
TEST(format_test, join) {
|
TEST(format_test, join) {
|
||||||
using fmt::join;
|
using fmt::join;
|
||||||
@ -1652,9 +1786,15 @@ TEST(format_test, join) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cpp_lib_byte
|
#ifdef __cpp_lib_byte
|
||||||
|
TEST(format_test, format_byte) {
|
||||||
|
using arg_mapper = fmt::detail::arg_mapper<fmt::format_context>;
|
||||||
|
EXPECT_EQ(arg_mapper().map(std::byte(42)), 42);
|
||||||
|
EXPECT_EQ(fmt::format("{}", std::byte(42)), "42");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(format_test, join_bytes) {
|
TEST(format_test, join_bytes) {
|
||||||
auto v = std::vector<std::byte>{std::byte(1), std::byte(2), std::byte(3)};
|
auto v = std::vector<std::byte>{std::byte(1), std::byte(2), std::byte(3)};
|
||||||
EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join(v, ", ")));
|
EXPECT_EQ(fmt::format("{}", fmt::join(v, ", ")), "1, 2, 3");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1694,20 +1834,21 @@ fmt::string_view to_string_view(string_like) { return "foo"; }
|
|||||||
|
|
||||||
constexpr char with_null[3] = {'{', '}', '\0'};
|
constexpr char with_null[3] = {'{', '}', '\0'};
|
||||||
constexpr char no_null[2] = {'{', '}'};
|
constexpr char no_null[2] = {'{', '}'};
|
||||||
static FMT_CONSTEXPR_DECL const char static_with_null[3] = {'{', '}', '\0'};
|
static constexpr const char static_with_null[3] = {'{', '}', '\0'};
|
||||||
static FMT_CONSTEXPR_DECL const char static_no_null[2] = {'{', '}'};
|
static constexpr const char static_no_null[2] = {'{', '}'};
|
||||||
|
|
||||||
TEST(format_test, compile_time_string) {
|
TEST(format_test, compile_time_string) {
|
||||||
EXPECT_EQ("foo", fmt::format(FMT_STRING("foo")));
|
EXPECT_EQ("foo", fmt::format(FMT_STRING("foo")));
|
||||||
EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), 42));
|
EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), 42));
|
||||||
EXPECT_EQ("foo", fmt::format(FMT_STRING("{}"), string_like()));
|
EXPECT_EQ("foo", fmt::format(FMT_STRING("{}"), string_like()));
|
||||||
|
|
||||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||||
using namespace fmt::literals;
|
using namespace fmt::literals;
|
||||||
EXPECT_EQ("foobar", fmt::format(FMT_STRING("{foo}{bar}"), "bar"_a = "bar",
|
EXPECT_EQ("foobar", fmt::format(FMT_STRING("{foo}{bar}"), "bar"_a = "bar",
|
||||||
"foo"_a = "foo"));
|
"foo"_a = "foo"));
|
||||||
EXPECT_EQ("", fmt::format(FMT_STRING("")));
|
EXPECT_EQ("", fmt::format(FMT_STRING("")));
|
||||||
EXPECT_EQ("", fmt::format(FMT_STRING(""), "arg"_a = 42));
|
EXPECT_EQ("", fmt::format(FMT_STRING(""), "arg"_a = 42));
|
||||||
|
EXPECT_EQ("42", fmt::format(FMT_STRING("{answer}"), "answer"_a = Answer()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
(void)static_with_null;
|
(void)static_with_null;
|
||||||
@ -1719,11 +1860,11 @@ TEST(format_test, compile_time_string) {
|
|||||||
|
|
||||||
(void)with_null;
|
(void)with_null;
|
||||||
(void)no_null;
|
(void)no_null;
|
||||||
#if __cplusplus >= 201703L
|
#if FMT_CPLUSPLUS >= 201703L
|
||||||
EXPECT_EQ("42", fmt::format(FMT_STRING(with_null), 42));
|
EXPECT_EQ("42", fmt::format(FMT_STRING(with_null), 42));
|
||||||
EXPECT_EQ("42", fmt::format(FMT_STRING(no_null), 42));
|
EXPECT_EQ("42", fmt::format(FMT_STRING(no_null), 42));
|
||||||
#endif
|
#endif
|
||||||
#if defined(FMT_USE_STRING_VIEW) && __cplusplus >= 201703L
|
#if defined(FMT_USE_STRING_VIEW) && FMT_CPLUSPLUS >= 201703L
|
||||||
EXPECT_EQ("42", fmt::format(FMT_STRING(std::string_view("{}")), 42));
|
EXPECT_EQ("42", fmt::format(FMT_STRING(std::string_view("{}")), 42));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -1739,44 +1880,16 @@ TEST(format_test, custom_format_compile_time_string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_USE_USER_DEFINED_LITERALS
|
#if FMT_USE_USER_DEFINED_LITERALS
|
||||||
// Passing user-defined literals directly to EXPECT_EQ causes problems
|
|
||||||
// with macro argument stringification (#) on some versions of GCC.
|
|
||||||
// Workaround: Assing the UDL result to a variable before the macro.
|
|
||||||
|
|
||||||
using namespace fmt::literals;
|
|
||||||
|
|
||||||
# if FMT_GCC_VERSION
|
|
||||||
# define FMT_CHECK_DEPRECATED_UDL_FORMAT 1
|
|
||||||
# elif FMT_CLANG_VERSION && defined(__has_warning)
|
|
||||||
# if __has_warning("-Wdeprecated-declarations")
|
|
||||||
# define FMT_CHECK_DEPRECATED_UDL_FORMAT 1
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
# ifndef FMT_CHECK_DEPRECATED_UDL_FORMAT
|
|
||||||
# define FMT_CHECK_DEPRECATED_UDL_FORMAT 0
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# if FMT_CHECK_DEPRECATED_UDL_FORMAT
|
|
||||||
# pragma GCC diagnostic push
|
|
||||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
||||||
|
|
||||||
TEST(format_test, format_udl) {
|
|
||||||
EXPECT_EQ("{}c{}"_format("ab", 1), fmt::format("{}c{}", "ab", 1));
|
|
||||||
EXPECT_EQ("foo"_format(), "foo");
|
|
||||||
EXPECT_EQ("{0:10}"_format(42), " 42");
|
|
||||||
EXPECT_EQ("{}"_format(date(2015, 10, 21)), "2015-10-21");
|
|
||||||
}
|
|
||||||
|
|
||||||
# pragma GCC diagnostic pop
|
|
||||||
# endif
|
|
||||||
|
|
||||||
TEST(format_test, named_arg_udl) {
|
TEST(format_test, named_arg_udl) {
|
||||||
|
using namespace fmt::literals;
|
||||||
auto udl_a = fmt::format("{first}{second}{first}{third}", "first"_a = "abra",
|
auto udl_a = fmt::format("{first}{second}{first}{third}", "first"_a = "abra",
|
||||||
"second"_a = "cad", "third"_a = 99);
|
"second"_a = "cad", "third"_a = 99);
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
fmt::format("{first}{second}{first}{third}", fmt::arg("first", "abra"),
|
fmt::format("{first}{second}{first}{third}", fmt::arg("first", "abra"),
|
||||||
fmt::arg("second", "cad"), fmt::arg("third", 99)),
|
fmt::arg("second", "cad"), fmt::arg("third", 99)),
|
||||||
udl_a);
|
udl_a);
|
||||||
|
|
||||||
|
EXPECT_EQ("42", fmt::format("{answer}", "answer"_a = Answer()));
|
||||||
}
|
}
|
||||||
#endif // FMT_USE_USER_DEFINED_LITERALS
|
#endif // FMT_USE_USER_DEFINED_LITERALS
|
||||||
|
|
||||||
@ -1790,6 +1903,7 @@ TEST(format_test, formatter_not_specialized) {
|
|||||||
|
|
||||||
#if FMT_HAS_FEATURE(cxx_strong_enums)
|
#if FMT_HAS_FEATURE(cxx_strong_enums)
|
||||||
enum big_enum : unsigned long long { big_enum_value = 5000000000ULL };
|
enum big_enum : unsigned long long { big_enum_value = 5000000000ULL };
|
||||||
|
auto format_as(big_enum e) -> unsigned long long { return e; }
|
||||||
|
|
||||||
TEST(format_test, strong_enum) {
|
TEST(format_test, strong_enum) {
|
||||||
EXPECT_EQ("5000000000", fmt::format("{}", big_enum_value));
|
EXPECT_EQ("5000000000", fmt::format("{}", big_enum_value));
|
||||||
@ -1871,9 +1985,11 @@ TEST(format_test, to_string) {
|
|||||||
EXPECT_EQ(fmt::to_string(reinterpret_cast<void*>(0x1234)), "0x1234");
|
EXPECT_EQ(fmt::to_string(reinterpret_cast<void*>(0x1234)), "0x1234");
|
||||||
EXPECT_EQ(fmt::to_string(adl_test::fmt::detail::foo()), "foo");
|
EXPECT_EQ(fmt::to_string(adl_test::fmt::detail::foo()), "foo");
|
||||||
EXPECT_EQ(fmt::to_string(convertible_to_int()), "42");
|
EXPECT_EQ(fmt::to_string(convertible_to_int()), "42");
|
||||||
|
EXPECT_EQ(fmt::to_string(foo), "0");
|
||||||
|
|
||||||
enum foo : unsigned char { zero };
|
#if FMT_USE_FLOAT128
|
||||||
EXPECT_EQ(fmt::to_string(zero), "0");
|
EXPECT_EQ(fmt::to_string(__float128(0.5)), "0.5");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, output_iterators) {
|
TEST(format_test, output_iterators) {
|
||||||
@ -2038,7 +2154,7 @@ TEST(format_test, format_string_errors) {
|
|||||||
EXPECT_ERROR_NOARGS("foo", nullptr);
|
EXPECT_ERROR_NOARGS("foo", nullptr);
|
||||||
EXPECT_ERROR_NOARGS("}", "unmatched '}' in format string");
|
EXPECT_ERROR_NOARGS("}", "unmatched '}' in format string");
|
||||||
EXPECT_ERROR("{0:s", "unknown format specifier", date);
|
EXPECT_ERROR("{0:s", "unknown format specifier", date);
|
||||||
# if !FMT_MSC_VER || FMT_MSC_VER >= 1916
|
# if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1916
|
||||||
// This causes an detail compiler error in MSVC2017.
|
// This causes an detail compiler error in MSVC2017.
|
||||||
EXPECT_ERROR("{:{<}", "invalid fill character '{'", int);
|
EXPECT_ERROR("{:{<}", "invalid fill character '{'", int);
|
||||||
EXPECT_ERROR("{:10000000000}", "number is too big", int);
|
EXPECT_ERROR("{:10000000000}", "number is too big", int);
|
||||||
@ -2070,7 +2186,8 @@ TEST(format_test, format_string_errors) {
|
|||||||
# else
|
# else
|
||||||
fmt::print("warning: constexpr is broken in this version of MSVC\n");
|
fmt::print("warning: constexpr is broken in this version of MSVC\n");
|
||||||
# endif
|
# endif
|
||||||
# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
# if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||||
|
using namespace fmt::literals;
|
||||||
EXPECT_ERROR("{foo}", "named argument is not found", decltype("bar"_a = 42));
|
EXPECT_ERROR("{foo}", "named argument is not found", decltype("bar"_a = 42));
|
||||||
EXPECT_ERROR("{foo}", "named argument is not found",
|
EXPECT_ERROR("{foo}", "named argument is not found",
|
||||||
decltype(fmt::arg("foo", 42)));
|
decltype(fmt::arg("foo", 42)));
|
||||||
@ -2116,7 +2233,7 @@ TEST(format_test, char_traits_is_not_ambiguous) {
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
auto c = char_traits<char>::char_type();
|
auto c = char_traits<char>::char_type();
|
||||||
(void)c;
|
(void)c;
|
||||||
#if __cplusplus >= 201103L
|
#if FMT_CPLUSPLUS >= 201103L
|
||||||
auto s = std::string();
|
auto s = std::string();
|
||||||
auto lval = begin(s);
|
auto lval = begin(s);
|
||||||
(void)lval;
|
(void)lval;
|
||||||
|
@ -30,8 +30,8 @@ void invoke_fmt(const uint8_t* data, size_t size) {
|
|||||||
#if FMT_FUZZ_FORMAT_TO_STRING
|
#if FMT_FUZZ_FORMAT_TO_STRING
|
||||||
std::string message = fmt::format(format_str.get(), *value);
|
std::string message = fmt::format(format_str.get(), *value);
|
||||||
#else
|
#else
|
||||||
fmt::memory_buffer message;
|
auto buf = fmt::memory_buffer();
|
||||||
fmt::format_to(message, format_str.get(), *value);
|
fmt::format_to(std::back_inserter(buf), format_str.get(), *value);
|
||||||
#endif
|
#endif
|
||||||
} catch (std::exception&) {
|
} catch (std::exception&) {
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,8 @@ void invoke_fmt(const uint8_t* data, size_t size) {
|
|||||||
#if FMT_FUZZ_FORMAT_TO_STRING
|
#if FMT_FUZZ_FORMAT_TO_STRING
|
||||||
std::string message = fmt::format(format_str, item1, item2);
|
std::string message = fmt::format(format_str, item1, item2);
|
||||||
#else
|
#else
|
||||||
fmt::memory_buffer message;
|
auto buf = fmt::memory_buffer();
|
||||||
fmt::format_to(message, format_str, item1, item2);
|
fmt::format_to(std::back_inserter(buf), format_str, item1, item2);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +347,7 @@ TEST(output_redirect_test, flush_error_in_ctor) {
|
|||||||
|
|
||||||
TEST(output_redirect_test, dup_error_in_ctor) {
|
TEST(output_redirect_test, dup_error_in_ctor) {
|
||||||
buffered_file f = open_buffered_file();
|
buffered_file f = open_buffered_file();
|
||||||
int fd = (f.fileno)();
|
int fd = (f.descriptor)();
|
||||||
file copy = file::dup(fd);
|
file copy = file::dup(fd);
|
||||||
FMT_POSIX(close(fd));
|
FMT_POSIX(close(fd));
|
||||||
std::unique_ptr<output_redirect> redir{nullptr};
|
std::unique_ptr<output_redirect> redir{nullptr};
|
||||||
|
@ -23,7 +23,7 @@ output_redirect::output_redirect(FILE* f) : file_(f) {
|
|||||||
write_end.dup2(fd);
|
write_end.dup2(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
output_redirect::~output_redirect() FMT_NOEXCEPT {
|
output_redirect::~output_redirect() noexcept {
|
||||||
try {
|
try {
|
||||||
restore();
|
restore();
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
|
@ -83,7 +83,7 @@ class output_redirect {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit output_redirect(FILE* file);
|
explicit output_redirect(FILE* file);
|
||||||
~output_redirect() FMT_NOEXCEPT;
|
~output_redirect() noexcept;
|
||||||
|
|
||||||
output_redirect(const output_redirect&) = delete;
|
output_redirect(const output_redirect&) = delete;
|
||||||
void operator=(const output_redirect&) = delete;
|
void operator=(const output_redirect&) = delete;
|
||||||
|
@ -18,7 +18,7 @@ else ()
|
|||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# Workaround GTest bug https://github.com/google/googletest/issues/705.
|
# Workaround GTest bug https://github.com/google/googletest/issues/705.
|
||||||
check_cxx_compiler_flag(
|
fmt_check_cxx_compiler_flag(
|
||||||
-fno-delete-null-pointer-checks HAVE_FNO_DELETE_NULL_POINTER_CHECKS)
|
-fno-delete-null-pointer-checks HAVE_FNO_DELETE_NULL_POINTER_CHECKS)
|
||||||
if (HAVE_FNO_DELETE_NULL_POINTER_CHECKS)
|
if (HAVE_FNO_DELETE_NULL_POINTER_CHECKS)
|
||||||
target_compile_options(gtest PUBLIC -fno-delete-null-pointer-checks)
|
target_compile_options(gtest PUBLIC -fno-delete-null-pointer-checks)
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
#else
|
#else
|
||||||
# define FMT_USE_FCNTL 0
|
# define FMT_USE_FCNTL 0
|
||||||
#endif
|
#endif
|
||||||
#define FMT_NOEXCEPT noexcept
|
|
||||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||||
# define FMT_POSIX(call) _##call
|
# define FMT_POSIX(call) _##call
|
||||||
#else
|
#else
|
||||||
@ -196,13 +195,6 @@ TEST(module_test, wformat_args) {
|
|||||||
EXPECT_TRUE(args.get(0));
|
EXPECT_TRUE(args.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(module_test, checked_format_args) {
|
|
||||||
fmt::basic_format_args args = fmt::make_args_checked<int>("{}", 42);
|
|
||||||
EXPECT_TRUE(args.get(0));
|
|
||||||
fmt::basic_format_args wargs = fmt::make_args_checked<int>(L"{}", 42);
|
|
||||||
EXPECT_TRUE(wargs.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(module_test, dynamic_format_args) {
|
TEST(module_test, dynamic_format_args) {
|
||||||
fmt::dynamic_format_arg_store<fmt::format_context> dyn_store;
|
fmt::dynamic_format_arg_store<fmt::format_context> dyn_store;
|
||||||
dyn_store.push_back(fmt::arg("a42", 42));
|
dyn_store.push_back(fmt::arg("a42", 42));
|
||||||
|
22
externals/dynarmic/externals/fmt/test/os-test.cc
vendored
22
externals/dynarmic/externals/fmt/test/os-test.cc
vendored
@ -14,10 +14,6 @@
|
|||||||
#include "gtest-extra.h"
|
#include "gtest-extra.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#ifdef fileno
|
|
||||||
# undef fileno
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using fmt::buffered_file;
|
using fmt::buffered_file;
|
||||||
using testing::HasSubstr;
|
using testing::HasSubstr;
|
||||||
using wstring_view = fmt::basic_string_view<wchar_t>;
|
using wstring_view = fmt::basic_string_view<wchar_t>;
|
||||||
@ -205,7 +201,7 @@ TEST(buffered_file_test, move_assignment) {
|
|||||||
TEST(buffered_file_test, move_assignment_closes_file) {
|
TEST(buffered_file_test, move_assignment_closes_file) {
|
||||||
buffered_file bf = open_buffered_file();
|
buffered_file bf = open_buffered_file();
|
||||||
buffered_file bf2 = open_buffered_file();
|
buffered_file bf2 = open_buffered_file();
|
||||||
int old_fd = bf2.fileno();
|
int old_fd = bf2.descriptor();
|
||||||
bf2 = std::move(bf);
|
bf2 = std::move(bf);
|
||||||
EXPECT_TRUE(isclosed(old_fd));
|
EXPECT_TRUE(isclosed(old_fd));
|
||||||
}
|
}
|
||||||
@ -225,7 +221,7 @@ TEST(buffered_file_test, move_from_temporary_in_assignment) {
|
|||||||
|
|
||||||
TEST(buffered_file_test, move_from_temporary_in_assignment_closes_file) {
|
TEST(buffered_file_test, move_from_temporary_in_assignment_closes_file) {
|
||||||
buffered_file f = open_buffered_file();
|
buffered_file f = open_buffered_file();
|
||||||
int old_fd = f.fileno();
|
int old_fd = f.descriptor();
|
||||||
f = open_buffered_file();
|
f = open_buffered_file();
|
||||||
EXPECT_TRUE(isclosed(old_fd));
|
EXPECT_TRUE(isclosed(old_fd));
|
||||||
}
|
}
|
||||||
@ -234,7 +230,7 @@ TEST(buffered_file_test, close_file_in_dtor) {
|
|||||||
int fd = 0;
|
int fd = 0;
|
||||||
{
|
{
|
||||||
buffered_file f = open_buffered_file();
|
buffered_file f = open_buffered_file();
|
||||||
fd = f.fileno();
|
fd = f.descriptor();
|
||||||
}
|
}
|
||||||
EXPECT_TRUE(isclosed(fd));
|
EXPECT_TRUE(isclosed(fd));
|
||||||
}
|
}
|
||||||
@ -249,7 +245,7 @@ TEST(buffered_file_test, close_error_in_dtor) {
|
|||||||
// otherwise the system may recycle closed file descriptor when
|
// otherwise the system may recycle closed file descriptor when
|
||||||
// redirecting the output in EXPECT_STDERR and the second close
|
// redirecting the output in EXPECT_STDERR and the second close
|
||||||
// will break output redirection.
|
// will break output redirection.
|
||||||
FMT_POSIX(close(f->fileno()));
|
FMT_POSIX(close(f->descriptor()));
|
||||||
SUPPRESS_ASSERT(f.reset(nullptr));
|
SUPPRESS_ASSERT(f.reset(nullptr));
|
||||||
},
|
},
|
||||||
system_error_message(EBADF, "cannot close file") + "\n");
|
system_error_message(EBADF, "cannot close file") + "\n");
|
||||||
@ -257,7 +253,7 @@ TEST(buffered_file_test, close_error_in_dtor) {
|
|||||||
|
|
||||||
TEST(buffered_file_test, close) {
|
TEST(buffered_file_test, close) {
|
||||||
buffered_file f = open_buffered_file();
|
buffered_file f = open_buffered_file();
|
||||||
int fd = f.fileno();
|
int fd = f.descriptor();
|
||||||
f.close();
|
f.close();
|
||||||
EXPECT_TRUE(f.get() == nullptr);
|
EXPECT_TRUE(f.get() == nullptr);
|
||||||
EXPECT_TRUE(isclosed(fd));
|
EXPECT_TRUE(isclosed(fd));
|
||||||
@ -265,15 +261,15 @@ TEST(buffered_file_test, close) {
|
|||||||
|
|
||||||
TEST(buffered_file_test, close_error) {
|
TEST(buffered_file_test, close_error) {
|
||||||
buffered_file f = open_buffered_file();
|
buffered_file f = open_buffered_file();
|
||||||
FMT_POSIX(close(f.fileno()));
|
FMT_POSIX(close(f.descriptor()));
|
||||||
EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
|
EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
|
||||||
EXPECT_TRUE(f.get() == nullptr);
|
EXPECT_TRUE(f.get() == nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(buffered_file_test, fileno) {
|
TEST(buffered_file_test, descriptor) {
|
||||||
auto f = open_buffered_file();
|
auto f = open_buffered_file();
|
||||||
EXPECT_TRUE(f.fileno() != -1);
|
EXPECT_TRUE(f.descriptor() != -1);
|
||||||
file copy = file::dup(f.fileno());
|
file copy = file::dup(f.descriptor());
|
||||||
EXPECT_READ(copy, file_content);
|
EXPECT_READ(copy, file_content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
//
|
//
|
||||||
// For the license information refer to format.h.
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
|
|
||||||
using fmt::runtime;
|
using fmt::runtime;
|
||||||
@ -30,12 +32,12 @@ template <> struct formatter<test> : formatter<int> {
|
|||||||
#include "gtest-extra.h"
|
#include "gtest-extra.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const date& d) {
|
auto operator<<(std::ostream& os, const date& d) -> std::ostream& {
|
||||||
os << d.year() << '-' << d.month() << '-' << d.day();
|
os << d.year() << '-' << d.month() << '-' << d.day();
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wostream& operator<<(std::wostream& os, const date& d) {
|
auto operator<<(std::wostream& os, const date& d) -> std::wostream& {
|
||||||
os << d.year() << L'-' << d.month() << L'-' << d.day();
|
os << d.year() << L'-' << d.month() << L'-' << d.day();
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
@ -47,11 +49,24 @@ template <typename T> type_with_comma_op operator<<(T&, const date&);
|
|||||||
|
|
||||||
enum streamable_enum {};
|
enum streamable_enum {};
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, streamable_enum) {
|
auto operator<<(std::ostream& os, streamable_enum) -> std::ostream& {
|
||||||
return os << "streamable_enum";
|
return os << "streamable_enum";
|
||||||
}
|
}
|
||||||
|
|
||||||
enum unstreamable_enum {};
|
enum unstreamable_enum {};
|
||||||
|
auto format_as(unstreamable_enum e) -> int { return e; }
|
||||||
|
|
||||||
|
struct empty_test {};
|
||||||
|
auto operator<<(std::ostream& os, empty_test) -> std::ostream& {
|
||||||
|
return os << "";
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
template <> struct formatter<test_string> : ostream_formatter {};
|
||||||
|
template <> struct formatter<date> : ostream_formatter {};
|
||||||
|
template <> struct formatter<streamable_enum> : ostream_formatter {};
|
||||||
|
template <> struct formatter<empty_test> : ostream_formatter {};
|
||||||
|
} // namespace fmt
|
||||||
|
|
||||||
TEST(ostream_test, enum) {
|
TEST(ostream_test, enum) {
|
||||||
EXPECT_EQ("streamable_enum", fmt::format("{}", streamable_enum()));
|
EXPECT_EQ("streamable_enum", fmt::format("{}", streamable_enum()));
|
||||||
@ -86,9 +101,6 @@ TEST(ostream_test, format_specs) {
|
|||||||
EXPECT_EQ("te", fmt::format("{0:.{1}}", test_string("test"), 2));
|
EXPECT_EQ("te", fmt::format("{0:.{1}}", test_string("test"), 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct empty_test {};
|
|
||||||
std::ostream& operator<<(std::ostream& os, empty_test) { return os << ""; }
|
|
||||||
|
|
||||||
TEST(ostream_test, empty_custom_output) {
|
TEST(ostream_test, empty_custom_output) {
|
||||||
EXPECT_EQ("", fmt::format("{}", empty_test()));
|
EXPECT_EQ("", fmt::format("{}", empty_test()));
|
||||||
}
|
}
|
||||||
@ -121,7 +133,7 @@ TEST(ostream_test, write_to_ostream_max_size) {
|
|||||||
|
|
||||||
struct mock_streambuf : std::streambuf {
|
struct mock_streambuf : std::streambuf {
|
||||||
MOCK_METHOD2(xsputn, std::streamsize(const void* s, std::streamsize n));
|
MOCK_METHOD2(xsputn, std::streamsize(const void* s, std::streamsize n));
|
||||||
std::streamsize xsputn(const char* s, std::streamsize n) override {
|
auto xsputn(const char* s, std::streamsize n) -> std::streamsize override {
|
||||||
const void* v = s;
|
const void* v = s;
|
||||||
return xsputn(v, n);
|
return xsputn(v, n);
|
||||||
}
|
}
|
||||||
@ -158,15 +170,16 @@ TEST(ostream_test, join_fallback_formatter) {
|
|||||||
|
|
||||||
#if FMT_USE_CONSTEXPR
|
#if FMT_USE_CONSTEXPR
|
||||||
TEST(ostream_test, constexpr_string) {
|
TEST(ostream_test, constexpr_string) {
|
||||||
EXPECT_EQ("42", format(FMT_STRING("{}"), std::string("42")));
|
EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), std::string("42")));
|
||||||
EXPECT_EQ("a string", format(FMT_STRING("{0}"), test_string("a string")));
|
EXPECT_EQ("a string",
|
||||||
|
fmt::format(FMT_STRING("{0}"), test_string("a string")));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace fmt_test {
|
namespace fmt_test {
|
||||||
struct abc {};
|
struct abc {};
|
||||||
|
|
||||||
template <typename Output> Output& operator<<(Output& out, abc) {
|
template <typename Output> auto operator<<(Output& out, abc) -> Output& {
|
||||||
return out << "abc";
|
return out << "abc";
|
||||||
}
|
}
|
||||||
} // namespace fmt_test
|
} // namespace fmt_test
|
||||||
@ -174,7 +187,7 @@ template <typename Output> Output& operator<<(Output& out, abc) {
|
|||||||
template <typename T> struct test_template {};
|
template <typename T> struct test_template {};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::ostream& operator<<(std::ostream& os, test_template<T>) {
|
auto operator<<(std::ostream& os, test_template<T>) -> std::ostream& {
|
||||||
return os << 1;
|
return os << 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,6 +197,8 @@ template <typename T> struct formatter<test_template<T>> : formatter<int> {
|
|||||||
return formatter<int>::format(2, ctx);
|
return formatter<int>::format(2, ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <> struct formatter<fmt_test::abc> : ostream_formatter {};
|
||||||
} // namespace fmt
|
} // namespace fmt
|
||||||
|
|
||||||
TEST(ostream_test, template) {
|
TEST(ostream_test, template) {
|
||||||
@ -214,41 +229,6 @@ TEST(ostream_test, disable_builtin_ostream_operators) {
|
|||||||
EXPECT_EQ("foo", fmt::format("{}", convertible<const char*>("foo")));
|
EXPECT_EQ("foo", fmt::format("{}", convertible<const char*>("foo")));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct explicitly_convertible_to_string_like {
|
|
||||||
template <typename String,
|
|
||||||
typename = typename std::enable_if<std::is_constructible<
|
|
||||||
String, const char*, size_t>::value>::type>
|
|
||||||
explicit operator String() const {
|
|
||||||
return String("foo", 3u);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os,
|
|
||||||
explicitly_convertible_to_string_like) {
|
|
||||||
return os << "bar";
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ostream_test, format_explicitly_convertible_to_string_like) {
|
|
||||||
EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef FMT_USE_STRING_VIEW
|
|
||||||
struct explicitly_convertible_to_std_string_view {
|
|
||||||
explicit operator fmt::detail::std_string_view<char>() const {
|
|
||||||
return {"foo", 3u};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os,
|
|
||||||
explicitly_convertible_to_std_string_view) {
|
|
||||||
return os << "bar";
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ostream_test, format_explicitly_convertible_to_std_string_view) {
|
|
||||||
EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like()));
|
|
||||||
}
|
|
||||||
#endif // FMT_USE_STRING_VIEW
|
|
||||||
|
|
||||||
struct streamable_and_convertible_to_bool {
|
struct streamable_and_convertible_to_bool {
|
||||||
operator bool() const { return true; }
|
operator bool() const { return true; }
|
||||||
};
|
};
|
||||||
@ -262,6 +242,21 @@ TEST(ostream_test, format_convertible_to_bool) {
|
|||||||
EXPECT_EQ(fmt::format("{}", streamable_and_convertible_to_bool()), "true");
|
EXPECT_EQ(fmt::format("{}", streamable_and_convertible_to_bool()), "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct streamable_and_convertible_to_string_view {
|
||||||
|
operator fmt::string_view() const { return "foo"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os,
|
||||||
|
streamable_and_convertible_to_string_view) {
|
||||||
|
return os << "bar";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ostream_test, format_convertible_to_string_vew) {
|
||||||
|
// operator<< is intentionally not used because of potential ODR violations.
|
||||||
|
EXPECT_EQ(fmt::format("{}", streamable_and_convertible_to_string_view()),
|
||||||
|
"foo");
|
||||||
|
}
|
||||||
|
|
||||||
struct copyfmt_test {};
|
struct copyfmt_test {};
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, copyfmt_test) {
|
std::ostream& operator<<(std::ostream& os, copyfmt_test) {
|
||||||
@ -270,6 +265,10 @@ std::ostream& operator<<(std::ostream& os, copyfmt_test) {
|
|||||||
return os << "foo";
|
return os << "foo";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
template <> struct formatter<copyfmt_test> : ostream_formatter {};
|
||||||
|
} // namespace fmt
|
||||||
|
|
||||||
TEST(ostream_test, copyfmt) {
|
TEST(ostream_test, copyfmt) {
|
||||||
EXPECT_EQ("foo", fmt::format("{}", copyfmt_test()));
|
EXPECT_EQ("foo", fmt::format("{}", copyfmt_test()));
|
||||||
}
|
}
|
||||||
@ -286,11 +285,15 @@ TEST(ostream_test, range) {
|
|||||||
struct abstract {
|
struct abstract {
|
||||||
virtual ~abstract() = default;
|
virtual ~abstract() = default;
|
||||||
virtual void f() = 0;
|
virtual void f() = 0;
|
||||||
friend std::ostream& operator<<(std::ostream& os, const abstract&) {
|
friend auto operator<<(std::ostream& os, const abstract&) -> std::ostream& {
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
template <> struct formatter<abstract> : ostream_formatter {};
|
||||||
|
} // namespace fmt
|
||||||
|
|
||||||
void format_abstract_compiles(const abstract& a) {
|
void format_abstract_compiles(const abstract& a) {
|
||||||
fmt::format(FMT_COMPILE("{}"), a);
|
fmt::format(FMT_COMPILE("{}"), a);
|
||||||
}
|
}
|
||||||
@ -299,3 +302,21 @@ TEST(ostream_test, is_formattable) {
|
|||||||
EXPECT_TRUE(fmt::is_formattable<std::string>());
|
EXPECT_TRUE(fmt::is_formattable<std::string>());
|
||||||
EXPECT_TRUE(fmt::is_formattable<fmt::detail::std_string_view<char>>());
|
EXPECT_TRUE(fmt::is_formattable<fmt::detail::std_string_view<char>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct streamable_and_unformattable {};
|
||||||
|
|
||||||
|
auto operator<<(std::ostream& os, streamable_and_unformattable)
|
||||||
|
-> std::ostream& {
|
||||||
|
return os << "foo";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ostream_test, streamed) {
|
||||||
|
EXPECT_FALSE(fmt::is_formattable<streamable_and_unformattable>());
|
||||||
|
EXPECT_EQ(fmt::format("{}", fmt::streamed(streamable_and_unformattable())),
|
||||||
|
"foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ostream_test, closed_ofstream) {
|
||||||
|
std::ofstream ofs;
|
||||||
|
fmt::print(ofs, "discard");
|
||||||
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
// For the license information refer to format.h.
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
// Disable bogus MSVC warnings.
|
// Disable bogus MSVC warnings.
|
||||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
|
||||||
# define _CRT_SECURE_NO_WARNINGS
|
# define _CRT_SECURE_NO_WARNINGS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -438,7 +438,7 @@ TEST(buffered_file_test, fileno_no_retry) {
|
|||||||
file::pipe(read_end, write_end);
|
file::pipe(read_end, write_end);
|
||||||
buffered_file f = read_end.fdopen("r");
|
buffered_file f = read_end.fdopen("r");
|
||||||
fileno_count = 1;
|
fileno_count = 1;
|
||||||
EXPECT_SYSTEM_ERROR((f.fileno)(), EINTR, "cannot get file descriptor");
|
EXPECT_SYSTEM_ERROR((f.descriptor)(), EINTR, "cannot get file descriptor");
|
||||||
EXPECT_EQ(2, fileno_count);
|
EXPECT_EQ(2, fileno_count);
|
||||||
fileno_count = 0;
|
fileno_count = 0;
|
||||||
}
|
}
|
||||||
@ -457,84 +457,3 @@ TEST(scoped_mock, scope) {
|
|||||||
}
|
}
|
||||||
EXPECT_EQ(nullptr, test_mock::instance);
|
EXPECT_EQ(nullptr, test_mock::instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FMT_LOCALE
|
|
||||||
|
|
||||||
using locale_type = fmt::locale::type;
|
|
||||||
|
|
||||||
struct locale_mock {
|
|
||||||
static locale_mock* instance;
|
|
||||||
MOCK_METHOD3(newlocale, locale_type(int category_mask, const char* locale,
|
|
||||||
locale_type base));
|
|
||||||
MOCK_METHOD1(freelocale, void(locale_type locale));
|
|
||||||
} * locale_mock::instance;
|
|
||||||
|
|
||||||
# ifdef _MSC_VER
|
|
||||||
# pragma warning(push)
|
|
||||||
# pragma warning(disable : 4273)
|
|
||||||
# ifdef __clang__
|
|
||||||
# pragma clang diagnostic push
|
|
||||||
# pragma clang diagnostic ignored "-Winconsistent-dllimport"
|
|
||||||
# endif
|
|
||||||
|
|
||||||
_locale_t _create_locale(int category, const char* locale) {
|
|
||||||
return locale_mock::instance->newlocale(category, locale, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _free_locale(_locale_t locale) {
|
|
||||||
locale_mock::instance->freelocale(locale);
|
|
||||||
}
|
|
||||||
# ifdef __clang__
|
|
||||||
# pragma clang diagnostic pop
|
|
||||||
# endif
|
|
||||||
# pragma warning(pop)
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# if defined(__THROW) && \
|
|
||||||
((FMT_GCC_VERSION > 0 && FMT_GCC_VERSION <= 408) || defined(__e2k__))
|
|
||||||
# define FMT_LOCALE_THROW __THROW
|
|
||||||
# else
|
|
||||||
# define FMT_LOCALE_THROW
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# if defined(__APPLE__) || \
|
|
||||||
(defined(__FreeBSD__) && __FreeBSD_version < 1200002)
|
|
||||||
typedef int FreeLocaleResult;
|
|
||||||
# else
|
|
||||||
typedef void FreeLocaleResult;
|
|
||||||
# endif
|
|
||||||
|
|
||||||
FreeLocaleResult freelocale(locale_type locale) FMT_LOCALE_THROW {
|
|
||||||
locale_mock::instance->freelocale(locale);
|
|
||||||
return FreeLocaleResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
# undef FMT_LOCALE_THROW
|
|
||||||
|
|
||||||
# ifndef _WIN32
|
|
||||||
locale_t test::newlocale(int category_mask, const char* locale, locale_t base) {
|
|
||||||
return locale_mock::instance->newlocale(category_mask, locale, base);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(locale_test, locale_mock) {
|
|
||||||
scoped_mock<locale_mock> mock;
|
|
||||||
auto locale = reinterpret_cast<locale_type>(11);
|
|
||||||
EXPECT_CALL(mock, newlocale(222, StrEq("foo"), locale));
|
|
||||||
FMT_SYSTEM(newlocale(222, "foo", locale));
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
TEST(locale_test, locale) {
|
|
||||||
# ifndef LC_NUMERIC_MASK
|
|
||||||
enum { LC_NUMERIC_MASK = LC_NUMERIC };
|
|
||||||
# endif
|
|
||||||
scoped_mock<locale_mock> mock;
|
|
||||||
auto impl = reinterpret_cast<locale_type>(42);
|
|
||||||
EXPECT_CALL(mock, newlocale(LC_NUMERIC_MASK, StrEq("C"), nullptr))
|
|
||||||
.WillOnce(Return(impl));
|
|
||||||
EXPECT_CALL(mock, freelocale(impl));
|
|
||||||
fmt::locale loc;
|
|
||||||
EXPECT_EQ(impl, loc.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // FMT_LOCALE
|
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
#include <climits>
|
#include <climits>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "fmt/ostream.h"
|
|
||||||
#include "fmt/xchar.h"
|
#include "fmt/xchar.h"
|
||||||
#include "gtest-extra.h"
|
#include "gtest-extra.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -505,6 +504,7 @@ TEST(printf_test, pointer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum test_enum { answer = 42 };
|
enum test_enum { answer = 42 };
|
||||||
|
auto format_as(test_enum e) -> int { return e; }
|
||||||
|
|
||||||
TEST(printf_test, enum) {
|
TEST(printf_test, enum) {
|
||||||
EXPECT_PRINTF("42", "%d", answer);
|
EXPECT_PRINTF("42", "%d", answer);
|
||||||
@ -533,10 +533,6 @@ TEST(printf_test, wide_string) {
|
|||||||
EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc"));
|
EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(printf_test, printf_custom) {
|
|
||||||
EXPECT_EQ("abc", test_sprintf("%s", test_string("abc")));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(printf_test, vprintf) {
|
TEST(printf_test, vprintf) {
|
||||||
fmt::format_arg_store<fmt::printf_context, int> as{42};
|
fmt::format_arg_store<fmt::printf_context, int> as{42};
|
||||||
fmt::basic_format_args<fmt::printf_context> args(as);
|
fmt::basic_format_args<fmt::printf_context> args(as);
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
# define FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY
|
# define FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !FMT_MSC_VER || FMT_MSC_VER > 1910
|
#if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1910
|
||||||
# define FMT_RANGES_TEST_ENABLE_JOIN
|
# define FMT_RANGES_TEST_ENABLE_JOIN
|
||||||
# define FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT
|
# define FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT
|
||||||
#endif
|
#endif
|
||||||
@ -46,11 +46,13 @@ TEST(ranges_test, format_array_of_literals) {
|
|||||||
TEST(ranges_test, format_vector) {
|
TEST(ranges_test, format_vector) {
|
||||||
auto v = std::vector<int>{1, 2, 3, 5, 7, 11};
|
auto v = std::vector<int>{1, 2, 3, 5, 7, 11};
|
||||||
EXPECT_EQ(fmt::format("{}", v), "[1, 2, 3, 5, 7, 11]");
|
EXPECT_EQ(fmt::format("{}", v), "[1, 2, 3, 5, 7, 11]");
|
||||||
|
EXPECT_EQ(fmt::format("{::#x}", v), "[0x1, 0x2, 0x3, 0x5, 0x7, 0xb]");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ranges_test, format_vector2) {
|
TEST(ranges_test, format_vector2) {
|
||||||
auto v = std::vector<std::vector<int>>{{1, 2}, {3, 5}, {7, 11}};
|
auto v = std::vector<std::vector<int>>{{1, 2}, {3, 5}, {7, 11}};
|
||||||
EXPECT_EQ(fmt::format("{}", v), "[[1, 2], [3, 5], [7, 11]]");
|
EXPECT_EQ(fmt::format("{}", v), "[[1, 2], [3, 5], [7, 11]]");
|
||||||
|
EXPECT_EQ(fmt::format("{:::#x}", v), "[[0x1, 0x2], [0x3, 0x5], [0x7, 0xb]]");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ranges_test, format_map) {
|
TEST(ranges_test, format_map) {
|
||||||
@ -63,16 +65,42 @@ TEST(ranges_test, format_set) {
|
|||||||
"{\"one\", \"two\"}");
|
"{\"one\", \"two\"}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace adl {
|
||||||
|
struct box {
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto begin(const box& b) -> const int* { return &b.value; }
|
||||||
|
|
||||||
|
auto end(const box& b) -> const int* { return &b.value + 1; }
|
||||||
|
} // namespace adl
|
||||||
|
|
||||||
|
TEST(ranges_test, format_adl_begin_end) {
|
||||||
|
auto b = adl::box{42};
|
||||||
|
EXPECT_EQ(fmt::format("{}", b), "[42]");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ranges_test, format_pair) {
|
TEST(ranges_test, format_pair) {
|
||||||
auto p = std::pair<int, float>(42, 1.5f);
|
auto p = std::pair<int, float>(42, 1.5f);
|
||||||
EXPECT_EQ(fmt::format("{}", p), "(42, 1.5)");
|
EXPECT_EQ(fmt::format("{}", p), "(42, 1.5)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct unformattable {};
|
||||||
|
|
||||||
TEST(ranges_test, format_tuple) {
|
TEST(ranges_test, format_tuple) {
|
||||||
auto t =
|
auto t =
|
||||||
std::tuple<int, float, std::string, char>(42, 1.5f, "this is tuple", 'i');
|
std::tuple<int, float, std::string, char>(42, 1.5f, "this is tuple", 'i');
|
||||||
EXPECT_EQ(fmt::format("{}", t), "(42, 1.5, \"this is tuple\", 'i')");
|
EXPECT_EQ(fmt::format("{}", t), "(42, 1.5, \"this is tuple\", 'i')");
|
||||||
EXPECT_EQ(fmt::format("{}", std::tuple<>()), "()");
|
EXPECT_EQ(fmt::format("{}", std::tuple<>()), "()");
|
||||||
|
|
||||||
|
EXPECT_TRUE((fmt::is_formattable<std::tuple<>>::value));
|
||||||
|
EXPECT_FALSE((fmt::is_formattable<unformattable>::value));
|
||||||
|
EXPECT_FALSE((fmt::is_formattable<std::tuple<unformattable>>::value));
|
||||||
|
EXPECT_FALSE((fmt::is_formattable<std::tuple<unformattable, int>>::value));
|
||||||
|
EXPECT_FALSE((fmt::is_formattable<std::tuple<int, unformattable>>::value));
|
||||||
|
EXPECT_FALSE(
|
||||||
|
(fmt::is_formattable<std::tuple<unformattable, unformattable>>::value));
|
||||||
|
EXPECT_TRUE((fmt::is_formattable<std::tuple<int, float>>::value));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT
|
#ifdef FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT
|
||||||
@ -131,8 +159,8 @@ TEST(ranges_test, path_like) {
|
|||||||
struct string_like {
|
struct string_like {
|
||||||
const char* begin();
|
const char* begin();
|
||||||
const char* end();
|
const char* end();
|
||||||
explicit operator fmt::string_view() const { return "foo"; }
|
operator fmt::string_view() const { return "foo"; }
|
||||||
explicit operator std::string_view() const { return "foo"; }
|
operator std::string_view() const { return "foo"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(ranges_test, format_string_like) {
|
TEST(ranges_test, format_string_like) {
|
||||||
@ -196,14 +224,14 @@ TEST(ranges_test, range) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum test_enum { foo };
|
enum test_enum { foo };
|
||||||
|
auto format_as(test_enum e) -> int { return e; }
|
||||||
|
|
||||||
TEST(ranges_test, enum_range) {
|
TEST(ranges_test, enum_range) {
|
||||||
auto v = std::vector<test_enum>{test_enum::foo};
|
auto v = std::vector<test_enum>{test_enum::foo};
|
||||||
EXPECT_EQ(fmt::format("{}", v), "[0]");
|
EXPECT_EQ(fmt::format("{}", v), "[0]");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !FMT_MSC_VER
|
#if !FMT_MSC_VERSION
|
||||||
struct unformattable {};
|
|
||||||
|
|
||||||
TEST(ranges_test, unformattable_range) {
|
TEST(ranges_test, unformattable_range) {
|
||||||
EXPECT_FALSE((fmt::has_formatter<std::vector<unformattable>,
|
EXPECT_FALSE((fmt::has_formatter<std::vector<unformattable>,
|
||||||
@ -296,6 +324,7 @@ static_assert(std::input_iterator<cpp20_only_range::iterator>);
|
|||||||
TEST(ranges_test, join_sentinel) {
|
TEST(ranges_test, join_sentinel) {
|
||||||
auto hello = zstring{"hello"};
|
auto hello = zstring{"hello"};
|
||||||
EXPECT_EQ(fmt::format("{}", hello), "['h', 'e', 'l', 'l', 'o']");
|
EXPECT_EQ(fmt::format("{}", hello), "['h', 'e', 'l', 'l', 'o']");
|
||||||
|
EXPECT_EQ(fmt::format("{::}", hello), "[h, e, l, l, o]");
|
||||||
EXPECT_EQ(fmt::format("{}", fmt::join(hello, "_")), "h_e_l_l_o");
|
EXPECT_EQ(fmt::format("{}", fmt::join(hello, "_")), "h_e_l_l_o");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,6 +377,7 @@ TEST(ranges_test, escape_string) {
|
|||||||
EXPECT_EQ(fmt::format("{}", vec{"\xf0\xaa\x9b\x9e"}), "[\"\\U0002a6de\"]");
|
EXPECT_EQ(fmt::format("{}", vec{"\xf0\xaa\x9b\x9e"}), "[\"\\U0002a6de\"]");
|
||||||
EXPECT_EQ(fmt::format("{}", vec{"\xf4\x8f\xbf\xc0"}),
|
EXPECT_EQ(fmt::format("{}", vec{"\xf4\x8f\xbf\xc0"}),
|
||||||
"[\"\\xf4\\x8f\\xbf\\xc0\"]");
|
"[\"\\xf4\\x8f\\xbf\\xc0\"]");
|
||||||
|
EXPECT_EQ(fmt::format("{}", vec{"понедельник"}), "[\"понедельник\"]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,3 +391,18 @@ TEST(ranges_test, escape_convertible_to_string_view) {
|
|||||||
"[\"foo\"]");
|
"[\"foo\"]");
|
||||||
}
|
}
|
||||||
#endif // FMT_USE_STRING_VIEW
|
#endif // FMT_USE_STRING_VIEW
|
||||||
|
|
||||||
|
template <typename R> struct fmt_ref_view {
|
||||||
|
R* r;
|
||||||
|
|
||||||
|
auto begin() const -> decltype(r->begin()) { return r->begin(); }
|
||||||
|
auto end() const -> decltype(r->end()) { return r->end(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(ranges_test, range_of_range_of_mixed_const) {
|
||||||
|
std::vector<std::vector<int>> v = {{1, 2, 3}, {4, 5}};
|
||||||
|
EXPECT_EQ(fmt::format("{}", v), "[[1, 2, 3], [4, 5]]");
|
||||||
|
|
||||||
|
fmt_ref_view<decltype(v)> r{&v};
|
||||||
|
EXPECT_EQ(fmt::format("{}", r), "[[1, 2, 3], [4, 5]]");
|
||||||
|
}
|
||||||
|
84
externals/dynarmic/externals/fmt/test/std-test.cc
vendored
Executable file
84
externals/dynarmic/externals/fmt/test/std-test.cc
vendored
Executable file
@ -0,0 +1,84 @@
|
|||||||
|
// Formatting library for C++ - tests of formatters for standard library types
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#include "fmt/std.h"
|
||||||
|
#include "fmt/ranges.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
TEST(std_test, path) {
|
||||||
|
// Test ambiguity problem described in #2954. We need to exclude compilers
|
||||||
|
// where the ambiguity problem cannot be solved for now.
|
||||||
|
#if defined(__cpp_lib_filesystem) && \
|
||||||
|
(!FMT_MSC_VERSION || FMT_MSC_VERSION >= 1920)
|
||||||
|
EXPECT_EQ(fmt::format("{:8}", std::filesystem::path("foo")), "\"foo\" ");
|
||||||
|
EXPECT_EQ(fmt::format("{}", std::filesystem::path("foo\"bar.txt")),
|
||||||
|
"\"foo\\\"bar.txt\"");
|
||||||
|
|
||||||
|
# ifdef _WIN32
|
||||||
|
// File.txt in Russian.
|
||||||
|
const wchar_t unicode_path[] = {0x424, 0x430, 0x439, 0x43b, 0x2e,
|
||||||
|
0x74, 0x78, 0x74, 0};
|
||||||
|
const char unicode_u8path[] = {'"', char(0xd0), char(0xa4), char(0xd0),
|
||||||
|
char(0xb0), char(0xd0), char(0xb9), char(0xd0),
|
||||||
|
char(0xbb), '.', 't', 'x',
|
||||||
|
't', '"', '\0'};
|
||||||
|
EXPECT_EQ(fmt::format("{}", std::filesystem::path(unicode_path)),
|
||||||
|
unicode_u8path);
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ranges_std_test, format_vector_path) {
|
||||||
|
// Test ambiguity problem described in #2954. We need to exclude compilers
|
||||||
|
// where the ambiguity problem cannot be solved for now.
|
||||||
|
#if defined(__cpp_lib_filesystem) && \
|
||||||
|
(!FMT_MSC_VERSION || FMT_MSC_VERSION >= 1920)
|
||||||
|
auto p = std::filesystem::path("foo/bar.txt");
|
||||||
|
auto c = std::vector<std::string>{"abc", "def"};
|
||||||
|
EXPECT_EQ(fmt::format("path={}, range={}", p, c),
|
||||||
|
"path=\"foo/bar.txt\", range=[\"abc\", \"def\"]");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(std_test, thread_id) {
|
||||||
|
EXPECT_FALSE(fmt::format("{}", std::this_thread::get_id()).empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(std_test, variant) {
|
||||||
|
#ifdef __cpp_lib_variant
|
||||||
|
EXPECT_EQ(fmt::format("{}", std::monostate{}), "monostate");
|
||||||
|
using V0 = std::variant<int, float, std::string, char>;
|
||||||
|
V0 v0(42);
|
||||||
|
V0 v1(1.5f);
|
||||||
|
V0 v2("hello");
|
||||||
|
V0 v3('i');
|
||||||
|
EXPECT_EQ(fmt::format("{}", v0), "variant(42)");
|
||||||
|
EXPECT_EQ(fmt::format("{}", v1), "variant(1.5)");
|
||||||
|
EXPECT_EQ(fmt::format("{}", v2), "variant(\"hello\")");
|
||||||
|
EXPECT_EQ(fmt::format("{}", v3), "variant('i')");
|
||||||
|
|
||||||
|
struct unformattable {};
|
||||||
|
EXPECT_FALSE((fmt::is_formattable<unformattable>::value));
|
||||||
|
EXPECT_FALSE((fmt::is_formattable<std::variant<unformattable>>::value));
|
||||||
|
EXPECT_FALSE((fmt::is_formattable<std::variant<unformattable, int>>::value));
|
||||||
|
EXPECT_FALSE((fmt::is_formattable<std::variant<int, unformattable>>::value));
|
||||||
|
EXPECT_FALSE(
|
||||||
|
(fmt::is_formattable<std::variant<unformattable, unformattable>>::value));
|
||||||
|
EXPECT_TRUE((fmt::is_formattable<std::variant<int, float>>::value));
|
||||||
|
|
||||||
|
using V1 = std::variant<std::monostate, std::string, std::string>;
|
||||||
|
V1 v4{};
|
||||||
|
V1 v5{std::in_place_index<1>, "yes, this is variant"};
|
||||||
|
|
||||||
|
EXPECT_EQ(fmt::format("{}", v4), "variant(monostate)");
|
||||||
|
EXPECT_EQ(fmt::format("{}", v5), "variant(\"yes, this is variant\")");
|
||||||
|
#endif
|
||||||
|
}
|
@ -15,9 +15,6 @@
|
|||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# include <crtdbg.h>
|
# include <crtdbg.h>
|
||||||
#else
|
|
||||||
# define _CrtSetReportFile(a, b)
|
|
||||||
# define _CrtSetReportMode(a, b)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
@ -28,11 +25,13 @@ int main(int argc, char** argv) {
|
|||||||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
|
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
|
||||||
SEM_NOOPENFILEERRORBOX);
|
SEM_NOOPENFILEERRORBOX);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _MSC_VER
|
||||||
// Disable message boxes on assertion failures.
|
// Disable message boxes on assertion failures.
|
||||||
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
|
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
|
||||||
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
|
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
|
||||||
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
|
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
|
||||||
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
|
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
|
||||||
|
#endif
|
||||||
try {
|
try {
|
||||||
testing::InitGoogleTest(&argc, argv);
|
testing::InitGoogleTest(&argc, argv);
|
||||||
testing::FLAGS_gtest_death_test_style = "threadsafe";
|
testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||||
|
@ -66,14 +66,16 @@ TYPED_TEST(is_string_test, is_string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// std::is_constructible is broken in MSVC until version 2015.
|
// std::is_constructible is broken in MSVC until version 2015.
|
||||||
#if !FMT_MSC_VER || FMT_MSC_VER >= 1900
|
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1900
|
||||||
struct explicitly_convertible_to_wstring_view {
|
struct explicitly_convertible_to_wstring_view {
|
||||||
explicit operator fmt::wstring_view() const { return L"foo"; }
|
explicit operator fmt::wstring_view() const { return L"foo"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(xchar_test, format_explicitly_convertible_to_wstring_view) {
|
TEST(xchar_test, format_explicitly_convertible_to_wstring_view) {
|
||||||
EXPECT_EQ(L"foo",
|
// Types explicitly convertible to wstring_view are not formattable by
|
||||||
fmt::format(L"{}", explicitly_convertible_to_wstring_view()));
|
// default because it may introduce ODR violations.
|
||||||
|
static_assert(
|
||||||
|
!fmt::is_formattable<explicitly_convertible_to_wstring_view>::value, "");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -96,12 +98,12 @@ TEST(xchar_test, is_formattable) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(xchar_test, compile_time_string) {
|
TEST(xchar_test, compile_time_string) {
|
||||||
#if defined(FMT_USE_STRING_VIEW) && __cplusplus >= 201703L
|
#if defined(FMT_USE_STRING_VIEW) && FMT_CPLUSPLUS >= 201703L
|
||||||
EXPECT_EQ(L"42", fmt::format(FMT_STRING(std::wstring_view(L"{}")), 42));
|
EXPECT_EQ(L"42", fmt::format(FMT_STRING(std::wstring_view(L"{}")), 42));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __cplusplus > 201103L
|
#if FMT_CPLUSPLUS > 201103L
|
||||||
struct custom_char {
|
struct custom_char {
|
||||||
int value;
|
int value;
|
||||||
custom_char() = default;
|
custom_char() = default;
|
||||||
@ -183,11 +185,6 @@ TEST(format_test, wide_format_to_n) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_USE_USER_DEFINED_LITERALS
|
#if FMT_USE_USER_DEFINED_LITERALS
|
||||||
TEST(xchar_test, format_udl) {
|
|
||||||
using namespace fmt::literals;
|
|
||||||
EXPECT_EQ(L"{}c{}"_format(L"ab", 1), fmt::format(L"{}c{}", L"ab", 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(xchar_test, named_arg_udl) {
|
TEST(xchar_test, named_arg_udl) {
|
||||||
using namespace fmt::literals;
|
using namespace fmt::literals;
|
||||||
auto udl_a =
|
auto udl_a =
|
||||||
@ -218,7 +215,14 @@ std::wostream& operator<<(std::wostream& os, streamable_enum) {
|
|||||||
return os << L"streamable_enum";
|
return os << L"streamable_enum";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
template <>
|
||||||
|
struct formatter<streamable_enum, wchar_t> : basic_ostream_formatter<wchar_t> {
|
||||||
|
};
|
||||||
|
} // namespace fmt
|
||||||
|
|
||||||
enum unstreamable_enum {};
|
enum unstreamable_enum {};
|
||||||
|
auto format_as(unstreamable_enum e) -> int { return e; }
|
||||||
|
|
||||||
TEST(xchar_test, enum) {
|
TEST(xchar_test, enum) {
|
||||||
EXPECT_EQ(L"streamable_enum", fmt::format(L"{}", streamable_enum()));
|
EXPECT_EQ(L"streamable_enum", fmt::format(L"{}", streamable_enum()));
|
||||||
@ -232,28 +236,6 @@ TEST(xchar_test, sign_not_truncated) {
|
|||||||
EXPECT_THROW(fmt::format(format_str, 42), fmt::format_error);
|
EXPECT_THROW(fmt::format(format_str, 42), fmt::format_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace fake_qt {
|
|
||||||
class QString {
|
|
||||||
public:
|
|
||||||
QString(const wchar_t* s) : s_(s) {}
|
|
||||||
const wchar_t* utf16() const FMT_NOEXCEPT { return s_.data(); }
|
|
||||||
int size() const FMT_NOEXCEPT { return static_cast<int>(s_.size()); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::wstring s_;
|
|
||||||
};
|
|
||||||
|
|
||||||
fmt::basic_string_view<wchar_t> to_string_view(const QString& s) FMT_NOEXCEPT {
|
|
||||||
return {s.utf16(), static_cast<size_t>(s.size())};
|
|
||||||
}
|
|
||||||
} // namespace fake_qt
|
|
||||||
|
|
||||||
TEST(format_test, format_foreign_strings) {
|
|
||||||
using fake_qt::QString;
|
|
||||||
EXPECT_EQ(fmt::format(QString(L"{}"), 42), L"42");
|
|
||||||
EXPECT_EQ(fmt::format(QString(L"{}"), QString(L"42")), L"42");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(xchar_test, chrono) {
|
TEST(xchar_test, chrono) {
|
||||||
auto tm = std::tm();
|
auto tm = std::tm();
|
||||||
tm.tm_year = 116;
|
tm.tm_year = 116;
|
||||||
@ -322,9 +304,22 @@ TEST(xchar_test, color) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(xchar_test, ostream) {
|
TEST(xchar_test, ostream) {
|
||||||
|
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 409
|
||||||
std::wostringstream wos;
|
std::wostringstream wos;
|
||||||
fmt::print(wos, L"Don't {}!", L"panic");
|
fmt::print(wos, L"Don't {}!", L"panic");
|
||||||
EXPECT_EQ(L"Don't panic!", wos.str());
|
EXPECT_EQ(wos.str(), L"Don't panic!");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(xchar_test, format_map) {
|
||||||
|
auto m = std::map<std::wstring, int>{{L"one", 1}, {L"t\"wo", 2}};
|
||||||
|
EXPECT_EQ(fmt::format(L"{}", m), L"{\"one\": 1, \"t\\\"wo\": 2}");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(xchar_test, escape_string) {
|
||||||
|
using vec = std::vector<std::wstring>;
|
||||||
|
EXPECT_EQ(fmt::format(L"{}", vec{L"\n\r\t\"\\"}), L"[\"\\n\\r\\t\\\"\\\\\"]");
|
||||||
|
EXPECT_EQ(fmt::format(L"{}", vec{L"понедельник"}), L"[\"понедельник\"]");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(xchar_test, to_wstring) { EXPECT_EQ(L"42", fmt::to_wstring(42)); }
|
TEST(xchar_test, to_wstring) { EXPECT_EQ(L"42", fmt::to_wstring(42)); }
|
||||||
@ -360,10 +355,11 @@ template <typename Char> struct small_grouping : std::numpunct<Char> {
|
|||||||
|
|
||||||
TEST(locale_test, localized_double) {
|
TEST(locale_test, localized_double) {
|
||||||
auto loc = std::locale(std::locale(), new numpunct<char>());
|
auto loc = std::locale(std::locale(), new numpunct<char>());
|
||||||
EXPECT_EQ("1?23", fmt::format(loc, "{:L}", 1.23));
|
EXPECT_EQ(fmt::format(loc, "{:L}", 1.23), "1?23");
|
||||||
EXPECT_EQ("1?230000", fmt::format(loc, "{:Lf}", 1.23));
|
EXPECT_EQ(fmt::format(loc, "{:Lf}", 1.23), "1?230000");
|
||||||
EXPECT_EQ("1~234?5", fmt::format(loc, "{:L}", 1234.5));
|
EXPECT_EQ(fmt::format(loc, "{:L}", 1234.5), "1~234?5");
|
||||||
EXPECT_EQ("12~000", fmt::format(loc, "{:L}", 12000.0));
|
EXPECT_EQ(fmt::format(loc, "{:L}", 12000.0), "12~000");
|
||||||
|
EXPECT_EQ(fmt::format(loc, "{:8L}", 1230.0), " 1~230");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(locale_test, format) {
|
TEST(locale_test, format) {
|
||||||
|
@ -384,7 +384,7 @@ void A32EmitX64::EmitA32GetCpsr(A32EmitContext& ctx, IR::Inst* inst) {
|
|||||||
code.pdep(result, result, tmp);
|
code.pdep(result, result, tmp);
|
||||||
} else {
|
} else {
|
||||||
code.mov(result, dword[r15 + offsetof(A32JitState, upper_location_descriptor)]);
|
code.mov(result, dword[r15 + offsetof(A32JitState, upper_location_descriptor)]);
|
||||||
code.imul(result, result, 0x12);
|
code.imul(result, result, 0x120);
|
||||||
code.and_(result, 0x00000220);
|
code.and_(result, 0x00000220);
|
||||||
|
|
||||||
code.mov(tmp, dword[r15 + offsetof(A32JitState, cpsr_ge)]);
|
code.mov(tmp, dword[r15 + offsetof(A32JitState, cpsr_ge)]);
|
||||||
@ -541,6 +541,48 @@ void A32EmitX64::EmitA32SetCpsrNZCVQ(A32EmitContext& ctx, IR::Inst* inst) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void A32EmitX64::EmitA32SetCpsrNZ(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
|
const Xbyak::Reg32 nz = ctx.reg_alloc.UseGpr(args[0]).cvt32();
|
||||||
|
const Xbyak::Reg32 tmp = ctx.reg_alloc.ScratchGpr().cvt32();
|
||||||
|
|
||||||
|
code.movzx(tmp, code.byte[r15 + offsetof(A32JitState, cpsr_nzcv) + 1]);
|
||||||
|
code.and_(tmp, 1);
|
||||||
|
code.or_(tmp, nz);
|
||||||
|
code.mov(code.byte[r15 + offsetof(A32JitState, cpsr_nzcv) + 1], tmp.cvt8());
|
||||||
|
}
|
||||||
|
|
||||||
|
void A32EmitX64::EmitA32SetCpsrNZC(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
|
if (args[0].IsImmediate()) {
|
||||||
|
if (args[1].IsImmediate()) {
|
||||||
|
const bool c = args[1].GetImmediateU1();
|
||||||
|
|
||||||
|
code.mov(code.byte[r15 + offsetof(A32JitState, cpsr_nzcv) + 1], c);
|
||||||
|
} else {
|
||||||
|
const Xbyak::Reg8 c = ctx.reg_alloc.UseGpr(args[1]).cvt8();
|
||||||
|
|
||||||
|
code.mov(code.byte[r15 + offsetof(A32JitState, cpsr_nzcv) + 1], c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const Xbyak::Reg32 nz = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
|
||||||
|
|
||||||
|
if (args[1].IsImmediate()) {
|
||||||
|
const bool c = args[1].GetImmediateU1();
|
||||||
|
|
||||||
|
code.or_(nz, c);
|
||||||
|
code.mov(code.byte[r15 + offsetof(A32JitState, cpsr_nzcv) + 1], nz.cvt8());
|
||||||
|
} else {
|
||||||
|
const Xbyak::Reg32 c = ctx.reg_alloc.UseGpr(args[1]).cvt32();
|
||||||
|
|
||||||
|
code.or_(nz, c);
|
||||||
|
code.mov(code.byte[r15 + offsetof(A32JitState, cpsr_nzcv) + 1], nz.cvt8());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void EmitGetFlag(BlockOfCode& code, A32EmitContext& ctx, IR::Inst* inst, size_t flag_bit) {
|
static void EmitGetFlag(BlockOfCode& code, A32EmitContext& ctx, IR::Inst* inst, size_t flag_bit) {
|
||||||
const Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32();
|
const Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32();
|
||||||
code.mov(result, dword[r15 + offsetof(A32JitState, cpsr_nzcv)]);
|
code.mov(result, dword[r15 + offsetof(A32JitState, cpsr_nzcv)]);
|
||||||
@ -551,48 +593,10 @@ static void EmitGetFlag(BlockOfCode& code, A32EmitContext& ctx, IR::Inst* inst,
|
|||||||
ctx.reg_alloc.DefineValue(inst, result);
|
ctx.reg_alloc.DefineValue(inst, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EmitSetFlag(BlockOfCode& code, A32EmitContext& ctx, IR::Inst* inst, size_t flag_bit) {
|
|
||||||
const u32 flag_mask = 1u << flag_bit;
|
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
|
||||||
if (args[0].IsImmediate()) {
|
|
||||||
if (args[0].GetImmediateU1()) {
|
|
||||||
code.or_(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], flag_mask);
|
|
||||||
} else {
|
|
||||||
code.and_(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], ~flag_mask);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const Xbyak::Reg32 to_store = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
|
|
||||||
|
|
||||||
if (flag_bit != 0) {
|
|
||||||
code.shl(to_store, static_cast<int>(flag_bit));
|
|
||||||
code.and_(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], ~flag_mask);
|
|
||||||
code.or_(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], to_store);
|
|
||||||
} else {
|
|
||||||
code.mov(code.byte[r15 + offsetof(A32JitState, cpsr_nzcv)], to_store.cvt8());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void A32EmitX64::EmitA32SetNFlag(A32EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
EmitSetFlag(code, ctx, inst, NZCV::x64_n_flag_bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
void A32EmitX64::EmitA32SetZFlag(A32EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
EmitSetFlag(code, ctx, inst, NZCV::x64_z_flag_bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
void A32EmitX64::EmitA32GetCFlag(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitX64::EmitA32GetCFlag(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitGetFlag(code, ctx, inst, NZCV::x64_c_flag_bit);
|
EmitGetFlag(code, ctx, inst, NZCV::x64_c_flag_bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32EmitX64::EmitA32SetCFlag(A32EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
EmitSetFlag(code, ctx, inst, NZCV::x64_c_flag_bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
void A32EmitX64::EmitA32SetVFlag(A32EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
EmitSetFlag(code, ctx, inst, NZCV::x64_v_flag_bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
void A32EmitX64::EmitA32OrQFlag(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitX64::EmitA32OrQFlag(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
if (args[0].IsImmediate()) {
|
if (args[0].IsImmediate()) {
|
||||||
|
@ -174,7 +174,7 @@ private:
|
|||||||
IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
IR::Block ir_block = A32::Translate(A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
||||||
Optimization::PolyfillPass(ir_block, polyfill_options);
|
Optimization::PolyfillPass(ir_block, polyfill_options);
|
||||||
if (conf.HasOptimization(OptimizationFlag::GetSetElimination) && !conf.check_halt_on_memory_access) {
|
if (conf.HasOptimization(OptimizationFlag::GetSetElimination) && !conf.check_halt_on_memory_access) {
|
||||||
Optimization::A32GetSetElimination(ir_block);
|
Optimization::A32GetSetElimination(ir_block, {.convert_nz_to_nzc = true});
|
||||||
Optimization::DeadCodeElimination(ir_block);
|
Optimization::DeadCodeElimination(ir_block);
|
||||||
}
|
}
|
||||||
if (conf.HasOptimization(OptimizationFlag::ConstProp)) {
|
if (conf.HasOptimization(OptimizationFlag::ConstProp)) {
|
||||||
|
@ -134,6 +134,34 @@ void EmitX64::EmitGetLowerFromOp(EmitContext&, IR::Inst*) {
|
|||||||
ASSERT_MSG(false, "should never happen");
|
ASSERT_MSG(false, "should never happen");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitGetNZFromOp(EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
|
const int bitsize = [&] {
|
||||||
|
switch (args[0].GetType()) {
|
||||||
|
case IR::Type::U8:
|
||||||
|
return 8;
|
||||||
|
case IR::Type::U16:
|
||||||
|
return 16;
|
||||||
|
case IR::Type::U32:
|
||||||
|
return 32;
|
||||||
|
case IR::Type::U64:
|
||||||
|
return 64;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
const Xbyak::Reg64 nz = ctx.reg_alloc.ScratchGpr(HostLoc::RAX);
|
||||||
|
const Xbyak::Reg value = ctx.reg_alloc.UseGpr(args[0]).changeBit(bitsize);
|
||||||
|
code.cmp(value, 0);
|
||||||
|
code.lahf();
|
||||||
|
code.db(0x0f);
|
||||||
|
code.db(0xb6);
|
||||||
|
code.db(0xc4);
|
||||||
|
ctx.reg_alloc.DefineValue(inst, nz);
|
||||||
|
}
|
||||||
|
|
||||||
void EmitX64::EmitGetNZCVFromOp(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitGetNZCVFromOp(EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
@ -160,6 +188,22 @@ void EmitX64::EmitGetNZCVFromOp(EmitContext& ctx, IR::Inst* inst) {
|
|||||||
ctx.reg_alloc.DefineValue(inst, nzcv);
|
ctx.reg_alloc.DefineValue(inst, nzcv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitGetCFlagFromNZCV(EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
|
if (args[0].IsImmediate()) {
|
||||||
|
const Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32();
|
||||||
|
const u32 value = (args[0].GetImmediateU32() >> 8) & 1;
|
||||||
|
code.mov(result, value);
|
||||||
|
ctx.reg_alloc.DefineValue(inst, result);
|
||||||
|
} else {
|
||||||
|
const Xbyak::Reg32 result = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
|
||||||
|
code.shr(result, 8);
|
||||||
|
code.and_(result, 1);
|
||||||
|
ctx.reg_alloc.DefineValue(inst, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EmitX64::EmitNZCVFromPackedFlags(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitNZCVFromPackedFlags(EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
|
@ -3829,29 +3829,29 @@ void EmitX64::EmitVectorSignedSaturatedDoublingMultiply16(EmitContext& ctx, IR::
|
|||||||
ctx.EraseInstruction(lower_inst);
|
ctx.EraseInstruction(lower_inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Xbyak::Xmm upper_result = ctx.reg_alloc.ScratchXmm();
|
||||||
|
|
||||||
|
if (code.HasHostFeature(HostFeature::AVX)) {
|
||||||
|
code.vpsrlw(lower_tmp, lower_tmp, 15);
|
||||||
|
code.vpaddw(upper_tmp, upper_tmp, upper_tmp);
|
||||||
|
code.vpor(upper_result, upper_tmp, lower_tmp);
|
||||||
|
code.vpcmpeqw(upper_tmp, upper_result, code.XmmBConst<16>(xword, 0x8000));
|
||||||
|
code.vpxor(upper_result, upper_result, upper_tmp);
|
||||||
|
} else {
|
||||||
|
code.paddw(upper_tmp, upper_tmp);
|
||||||
|
code.psrlw(lower_tmp, 15);
|
||||||
|
code.movdqa(upper_result, upper_tmp);
|
||||||
|
code.por(upper_result, lower_tmp);
|
||||||
|
code.movdqa(upper_tmp, code.XmmBConst<16>(xword, 0x8000));
|
||||||
|
code.pcmpeqw(upper_tmp, upper_result);
|
||||||
|
code.pxor(upper_result, upper_tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Xbyak::Reg32 bit = ctx.reg_alloc.ScratchGpr().cvt32();
|
||||||
|
code.pmovmskb(bit, upper_tmp);
|
||||||
|
code.or_(code.dword[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], bit);
|
||||||
|
|
||||||
if (upper_inst) {
|
if (upper_inst) {
|
||||||
const Xbyak::Xmm upper_result = ctx.reg_alloc.ScratchXmm();
|
|
||||||
|
|
||||||
if (code.HasHostFeature(HostFeature::AVX)) {
|
|
||||||
code.vpsrlw(lower_tmp, lower_tmp, 15);
|
|
||||||
code.vpaddw(upper_tmp, upper_tmp, upper_tmp);
|
|
||||||
code.vpor(upper_result, upper_tmp, lower_tmp);
|
|
||||||
code.vpcmpeqw(upper_tmp, upper_result, code.XmmBConst<16>(xword, 0x8000));
|
|
||||||
code.vpxor(upper_result, upper_result, upper_tmp);
|
|
||||||
} else {
|
|
||||||
code.paddw(upper_tmp, upper_tmp);
|
|
||||||
code.psrlw(lower_tmp, 15);
|
|
||||||
code.movdqa(upper_result, upper_tmp);
|
|
||||||
code.por(upper_result, lower_tmp);
|
|
||||||
code.movdqa(upper_tmp, code.XmmBConst<16>(xword, 0x8000));
|
|
||||||
code.pcmpeqw(upper_tmp, upper_result);
|
|
||||||
code.pxor(upper_result, upper_tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Xbyak::Reg32 bit = ctx.reg_alloc.ScratchGpr().cvt32();
|
|
||||||
code.pmovmskb(bit, upper_tmp);
|
|
||||||
code.or_(code.dword[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], bit);
|
|
||||||
|
|
||||||
ctx.reg_alloc.DefineValue(upper_inst, upper_result);
|
ctx.reg_alloc.DefineValue(upper_inst, upper_result);
|
||||||
ctx.EraseInstruction(upper_inst);
|
ctx.EraseInstruction(upper_inst);
|
||||||
}
|
}
|
||||||
@ -3880,23 +3880,23 @@ void EmitX64::EmitVectorSignedSaturatedDoublingMultiply32(EmitContext& ctx, IR::
|
|||||||
code.vpaddq(odds, odds, odds);
|
code.vpaddq(odds, odds, odds);
|
||||||
code.vpaddq(even, even, even);
|
code.vpaddq(even, even, even);
|
||||||
|
|
||||||
|
const Xbyak::Xmm upper_result = ctx.reg_alloc.ScratchXmm();
|
||||||
|
|
||||||
|
code.vpsrlq(upper_result, odds, 32);
|
||||||
|
code.vblendps(upper_result, upper_result, even, 0b1010);
|
||||||
|
|
||||||
|
const Xbyak::Xmm mask = ctx.reg_alloc.ScratchXmm();
|
||||||
|
const Xbyak::Reg32 bit = ctx.reg_alloc.ScratchGpr().cvt32();
|
||||||
|
|
||||||
|
code.vpcmpeqd(mask, upper_result, code.XmmBConst<32>(xword, 0x80000000));
|
||||||
|
code.vpxor(upper_result, upper_result, mask);
|
||||||
|
code.pmovmskb(bit, mask);
|
||||||
|
code.or_(code.dword[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], bit);
|
||||||
|
|
||||||
|
ctx.reg_alloc.Release(mask);
|
||||||
|
ctx.reg_alloc.Release(bit);
|
||||||
|
|
||||||
if (upper_inst) {
|
if (upper_inst) {
|
||||||
const Xbyak::Xmm upper_result = ctx.reg_alloc.ScratchXmm();
|
|
||||||
|
|
||||||
code.vpsrlq(upper_result, odds, 32);
|
|
||||||
code.vblendps(upper_result, upper_result, even, 0b1010);
|
|
||||||
|
|
||||||
const Xbyak::Xmm mask = ctx.reg_alloc.ScratchXmm();
|
|
||||||
const Xbyak::Reg32 bit = ctx.reg_alloc.ScratchGpr().cvt32();
|
|
||||||
|
|
||||||
code.vpcmpeqd(mask, upper_result, code.XmmBConst<32>(xword, 0x80000000));
|
|
||||||
code.vpxor(upper_result, upper_result, mask);
|
|
||||||
code.pmovmskb(bit, mask);
|
|
||||||
code.or_(code.dword[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], bit);
|
|
||||||
|
|
||||||
ctx.reg_alloc.Release(mask);
|
|
||||||
ctx.reg_alloc.Release(bit);
|
|
||||||
|
|
||||||
ctx.reg_alloc.DefineValue(upper_inst, upper_result);
|
ctx.reg_alloc.DefineValue(upper_inst, upper_result);
|
||||||
ctx.EraseInstruction(upper_inst);
|
ctx.EraseInstruction(upper_inst);
|
||||||
}
|
}
|
||||||
@ -3955,15 +3955,15 @@ void EmitX64::EmitVectorSignedSaturatedDoublingMultiply32(EmitContext& ctx, IR::
|
|||||||
code.por(lower_result, x);
|
code.por(lower_result, x);
|
||||||
code.psubd(upper_result, sign_correction);
|
code.psubd(upper_result, sign_correction);
|
||||||
|
|
||||||
|
const Xbyak::Reg32 bit = ctx.reg_alloc.ScratchGpr().cvt32();
|
||||||
|
|
||||||
|
code.movdqa(tmp, code.XmmBConst<32>(xword, 0x80000000));
|
||||||
|
code.pcmpeqd(tmp, upper_result);
|
||||||
|
code.pxor(upper_result, tmp);
|
||||||
|
code.pmovmskb(bit, tmp);
|
||||||
|
code.or_(code.dword[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], bit);
|
||||||
|
|
||||||
if (upper_inst) {
|
if (upper_inst) {
|
||||||
const Xbyak::Reg32 bit = ctx.reg_alloc.ScratchGpr().cvt32();
|
|
||||||
|
|
||||||
code.movdqa(tmp, code.XmmBConst<32>(xword, 0x80000000));
|
|
||||||
code.pcmpeqd(tmp, upper_result);
|
|
||||||
code.pxor(upper_result, tmp);
|
|
||||||
code.pmovmskb(bit, tmp);
|
|
||||||
code.or_(code.dword[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], bit);
|
|
||||||
|
|
||||||
ctx.reg_alloc.DefineValue(upper_inst, upper_result);
|
ctx.reg_alloc.DefineValue(upper_inst, upper_result);
|
||||||
ctx.EraseInstruction(upper_inst);
|
ctx.EraseInstruction(upper_inst);
|
||||||
}
|
}
|
||||||
|
@ -166,22 +166,6 @@ IR::U1 IREmitter::GetCFlag() {
|
|||||||
return Inst<IR::U1>(Opcode::A32GetCFlag);
|
return Inst<IR::U1>(Opcode::A32GetCFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetNFlag(const IR::U1& value) {
|
|
||||||
Inst(Opcode::A32SetNFlag, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IREmitter::SetZFlag(const IR::U1& value) {
|
|
||||||
Inst(Opcode::A32SetZFlag, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IREmitter::SetCFlag(const IR::U1& value) {
|
|
||||||
Inst(Opcode::A32SetCFlag, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IREmitter::SetVFlag(const IR::U1& value) {
|
|
||||||
Inst(Opcode::A32SetVFlag, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IREmitter::OrQFlag(const IR::U1& value) {
|
void IREmitter::OrQFlag(const IR::U1& value) {
|
||||||
Inst(Opcode::A32OrQFlag, value);
|
Inst(Opcode::A32OrQFlag, value);
|
||||||
}
|
}
|
||||||
@ -198,6 +182,18 @@ void IREmitter::SetGEFlagsCompressed(const IR::U32& value) {
|
|||||||
Inst(Opcode::A32SetGEFlagsCompressed, value);
|
Inst(Opcode::A32SetGEFlagsCompressed, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IR::NZCV IREmitter::NZFrom(const IR::Value& value) {
|
||||||
|
return Inst<IR::NZCV>(Opcode::GetNZFromOp, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IREmitter::SetCpsrNZ(const IR::NZCV& nz) {
|
||||||
|
Inst(Opcode::A32SetCpsrNZ, nz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IREmitter::SetCpsrNZC(const IR::NZCV& nz, const IR::U1& c) {
|
||||||
|
Inst(Opcode::A32SetCpsrNZC, nz, c);
|
||||||
|
}
|
||||||
|
|
||||||
void IREmitter::DataSynchronizationBarrier() {
|
void IREmitter::DataSynchronizationBarrier() {
|
||||||
Inst(Opcode::A32DataSynchronizationBarrier);
|
Inst(Opcode::A32DataSynchronizationBarrier);
|
||||||
}
|
}
|
||||||
|
@ -62,15 +62,15 @@ public:
|
|||||||
void SetCheckBit(const IR::U1& value);
|
void SetCheckBit(const IR::U1& value);
|
||||||
IR::U1 GetOverflowFrom(const IR::Value& value);
|
IR::U1 GetOverflowFrom(const IR::Value& value);
|
||||||
IR::U1 GetCFlag();
|
IR::U1 GetCFlag();
|
||||||
void SetNFlag(const IR::U1& value);
|
|
||||||
void SetZFlag(const IR::U1& value);
|
|
||||||
void SetCFlag(const IR::U1& value);
|
|
||||||
void SetVFlag(const IR::U1& value);
|
|
||||||
void OrQFlag(const IR::U1& value);
|
void OrQFlag(const IR::U1& value);
|
||||||
IR::U32 GetGEFlags();
|
IR::U32 GetGEFlags();
|
||||||
void SetGEFlags(const IR::U32& value);
|
void SetGEFlags(const IR::U32& value);
|
||||||
void SetGEFlagsCompressed(const IR::U32& value);
|
void SetGEFlagsCompressed(const IR::U32& value);
|
||||||
|
|
||||||
|
IR::NZCV NZFrom(const IR::Value& value);
|
||||||
|
void SetCpsrNZ(const IR::NZCV& nz);
|
||||||
|
void SetCpsrNZC(const IR::NZCV& nz, const IR::U1& c);
|
||||||
|
|
||||||
void DataSynchronizationBarrier();
|
void DataSynchronizationBarrier();
|
||||||
void DataMemoryBarrier();
|
void DataMemoryBarrier();
|
||||||
void InstructionSynchronizationBarrier();
|
void InstructionSynchronizationBarrier();
|
||||||
|
@ -5,20 +5,17 @@
|
|||||||
|
|
||||||
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
||||||
|
|
||||||
#include <ostream>
|
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
namespace Dynarmic::A32 {
|
namespace Dynarmic::A32 {
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor) {
|
std::string ToString(const LocationDescriptor& descriptor) {
|
||||||
o << fmt::format("{{{:08x},{},{},{:08x}{}}}",
|
return fmt::format("{{{:08x},{},{},{:08x}{}}}",
|
||||||
descriptor.PC(),
|
descriptor.PC(),
|
||||||
descriptor.TFlag() ? "T" : "!T",
|
descriptor.TFlag() ? "T" : "!T",
|
||||||
descriptor.EFlag() ? "E" : "!E",
|
descriptor.EFlag() ? "E" : "!E",
|
||||||
descriptor.FPSCR().Value(),
|
descriptor.FPSCR().Value(),
|
||||||
descriptor.SingleStepping() ? ",step" : "");
|
descriptor.SingleStepping() ? ",step" : "");
|
||||||
return o;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Dynarmic::A32
|
} // namespace Dynarmic::A32
|
||||||
|
@ -6,9 +6,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iosfwd>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
#include <mcl/stdint.hpp>
|
#include <mcl/stdint.hpp>
|
||||||
|
|
||||||
#include "dynarmic/frontend/A32/FPSCR.h"
|
#include "dynarmic/frontend/A32/FPSCR.h"
|
||||||
@ -131,10 +132,9 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Provides a string representation of a LocationDescriptor.
|
* Provides a string representation of a LocationDescriptor.
|
||||||
*
|
*
|
||||||
* @param o Output stream
|
|
||||||
* @param descriptor The descriptor to get a string representation of
|
* @param descriptor The descriptor to get a string representation of
|
||||||
*/
|
*/
|
||||||
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor);
|
std::string ToString(const LocationDescriptor& descriptor);
|
||||||
|
|
||||||
} // namespace Dynarmic::A32
|
} // namespace Dynarmic::A32
|
||||||
|
|
||||||
@ -152,3 +152,11 @@ struct hash<Dynarmic::A32::LocationDescriptor> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct fmt::formatter<Dynarmic::A32::LocationDescriptor> : fmt::formatter<std::string> {
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(Dynarmic::A32::LocationDescriptor descriptor, FormatContext& ctx) const {
|
||||||
|
return formatter<std::string>::format(Dynarmic::A32::ToString(descriptor), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -57,24 +57,4 @@ std::string RegListToString(RegList reg_list) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, Reg reg) {
|
|
||||||
o << RegToString(reg);
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, ExtReg reg) {
|
|
||||||
o << ExtRegToString(reg);
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, CoprocReg reg) {
|
|
||||||
o << CoprocRegToString(reg);
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, RegList reg_list) {
|
|
||||||
o << RegListToString(reg_list);
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::A32
|
} // namespace Dynarmic::A32
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <iosfwd>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
#include <mcl/assert.hpp>
|
#include <mcl/assert.hpp>
|
||||||
#include <mcl/stdint.hpp>
|
#include <mcl/stdint.hpp>
|
||||||
|
|
||||||
@ -72,11 +72,6 @@ const char* ExtRegToString(ExtReg reg);
|
|||||||
const char* CoprocRegToString(CoprocReg reg);
|
const char* CoprocRegToString(CoprocReg reg);
|
||||||
std::string RegListToString(RegList reg_list);
|
std::string RegListToString(RegList reg_list);
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, Reg reg);
|
|
||||||
std::ostream& operator<<(std::ostream& o, ExtReg reg);
|
|
||||||
std::ostream& operator<<(std::ostream& o, CoprocReg reg);
|
|
||||||
std::ostream& operator<<(std::ostream& o, RegList reg_list);
|
|
||||||
|
|
||||||
constexpr bool IsSingleExtReg(ExtReg reg) {
|
constexpr bool IsSingleExtReg(ExtReg reg) {
|
||||||
return reg >= ExtReg::S0 && reg <= ExtReg::S31;
|
return reg >= ExtReg::S0 && reg <= ExtReg::S31;
|
||||||
}
|
}
|
||||||
@ -148,3 +143,35 @@ inline ExtReg ToVector(bool Q, size_t base, bool bit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Dynarmic::A32
|
} // namespace Dynarmic::A32
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct fmt::formatter<Dynarmic::A32::Reg> : fmt::formatter<const char*> {
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(Dynarmic::A32::Reg reg, FormatContext& ctx) const {
|
||||||
|
return formatter<const char*>::format(Dynarmic::A32::RegToString(reg), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct fmt::formatter<Dynarmic::A32::ExtReg> : fmt::formatter<const char*> {
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(Dynarmic::A32::ExtReg reg, FormatContext& ctx) const {
|
||||||
|
return formatter<const char*>::format(Dynarmic::A32::ExtRegToString(reg), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct fmt::formatter<Dynarmic::A32::CoprocReg> : fmt::formatter<const char*> {
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(Dynarmic::A32::CoprocReg reg, FormatContext& ctx) const {
|
||||||
|
return formatter<const char*>::format(Dynarmic::A32::CoprocRegToString(reg), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct fmt::formatter<Dynarmic::A32::RegList> : fmt::formatter<std::string> {
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(Dynarmic::A32::RegList reg_list, FormatContext& ctx) const {
|
||||||
|
return formatter<std::string>::format(Dynarmic::A32::RegListToString(reg_list), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -181,9 +181,7 @@ bool TranslatorVisitor::arm_AND_imm(Cond cond, bool S, Reg n, Reg d, int rotate,
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -210,9 +208,7 @@ bool TranslatorVisitor::arm_AND_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5
|
|||||||
}
|
}
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -235,9 +231,7 @@ bool TranslatorVisitor::arm_AND_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, Shif
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -264,9 +258,7 @@ bool TranslatorVisitor::arm_BIC_imm(Cond cond, bool S, Reg n, Reg d, int rotate,
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -294,9 +286,7 @@ bool TranslatorVisitor::arm_BIC_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -319,9 +309,7 @@ bool TranslatorVisitor::arm_BIC_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, Shif
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -438,9 +426,7 @@ bool TranslatorVisitor::arm_EOR_imm(Cond cond, bool S, Reg n, Reg d, int rotate,
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -468,9 +454,7 @@ bool TranslatorVisitor::arm_EOR_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -493,9 +477,7 @@ bool TranslatorVisitor::arm_EOR_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, Shif
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -522,9 +504,7 @@ bool TranslatorVisitor::arm_MOV_imm(Cond cond, bool S, Reg d, int rotate, Imm<8>
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -552,9 +532,7 @@ bool TranslatorVisitor::arm_MOV_reg(Cond cond, bool S, Reg d, Imm<5> imm5, Shift
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -575,9 +553,7 @@ bool TranslatorVisitor::arm_MOV_rsr(Cond cond, bool S, Reg d, Reg s, ShiftType s
|
|||||||
const auto result = shifted.result;
|
const auto result = shifted.result;
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -604,9 +580,7 @@ bool TranslatorVisitor::arm_MVN_imm(Cond cond, bool S, Reg d, int rotate, Imm<8>
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -634,9 +608,7 @@ bool TranslatorVisitor::arm_MVN_reg(Cond cond, bool S, Reg d, Imm<5> imm5, Shift
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -659,9 +631,7 @@ bool TranslatorVisitor::arm_MVN_rsr(Cond cond, bool S, Reg d, Reg s, ShiftType s
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -688,9 +658,7 @@ bool TranslatorVisitor::arm_ORR_imm(Cond cond, bool S, Reg n, Reg d, int rotate,
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -718,9 +686,7 @@ bool TranslatorVisitor::arm_ORR_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -743,9 +709,7 @@ bool TranslatorVisitor::arm_ORR_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, Shif
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1066,9 +1030,7 @@ bool TranslatorVisitor::arm_TEQ_imm(Cond cond, Reg n, int rotate, Imm<8> imm8) {
|
|||||||
const auto imm_carry = ArmExpandImm_C(rotate, imm8, ir.GetCFlag());
|
const auto imm_carry = ArmExpandImm_C(rotate, imm8, ir.GetCFlag());
|
||||||
const auto result = ir.Eor(ir.GetRegister(n), ir.Imm32(imm_carry.imm32));
|
const auto result = ir.Eor(ir.GetRegister(n), ir.Imm32(imm_carry.imm32));
|
||||||
|
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1082,9 +1044,7 @@ bool TranslatorVisitor::arm_TEQ_reg(Cond cond, Reg n, Imm<5> imm5, ShiftType shi
|
|||||||
const auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, carry_in);
|
const auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, carry_in);
|
||||||
const auto result = ir.Eor(ir.GetRegister(n), shifted.result);
|
const auto result = ir.Eor(ir.GetRegister(n), shifted.result);
|
||||||
|
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1103,9 +1063,7 @@ bool TranslatorVisitor::arm_TEQ_rsr(Cond cond, Reg n, Reg s, ShiftType shift, Re
|
|||||||
const auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
|
const auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
|
||||||
const auto result = ir.Eor(ir.GetRegister(n), shifted.result);
|
const auto result = ir.Eor(ir.GetRegister(n), shifted.result);
|
||||||
|
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1118,9 +1076,7 @@ bool TranslatorVisitor::arm_TST_imm(Cond cond, Reg n, int rotate, Imm<8> imm8) {
|
|||||||
const auto imm_carry = ArmExpandImm_C(rotate, imm8, ir.GetCFlag());
|
const auto imm_carry = ArmExpandImm_C(rotate, imm8, ir.GetCFlag());
|
||||||
const auto result = ir.And(ir.GetRegister(n), ir.Imm32(imm_carry.imm32));
|
const auto result = ir.And(ir.GetRegister(n), ir.Imm32(imm_carry.imm32));
|
||||||
|
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1134,9 +1090,7 @@ bool TranslatorVisitor::arm_TST_reg(Cond cond, Reg n, Imm<5> imm5, ShiftType shi
|
|||||||
const auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, carry_in);
|
const auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, carry_in);
|
||||||
const auto result = ir.And(ir.GetRegister(n), shifted.result);
|
const auto result = ir.And(ir.GetRegister(n), shifted.result);
|
||||||
|
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1155,9 +1109,7 @@ bool TranslatorVisitor::arm_TST_rsr(Cond cond, Reg n, Reg s, ShiftType shift, Re
|
|||||||
const auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
|
const auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
|
||||||
const auto result = ir.And(ir.GetRegister(n), shifted.result);
|
const auto result = ir.And(ir.GetRegister(n), shifted.result);
|
||||||
|
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,8 +20,7 @@ bool TranslatorVisitor::arm_MLA(Cond cond, bool S, Reg d, Reg a, Reg m, Reg n) {
|
|||||||
const auto result = ir.Add(ir.Mul(ir.GetRegister(n), ir.GetRegister(m)), ir.GetRegister(a));
|
const auto result = ir.Add(ir.Mul(ir.GetRegister(n), ir.GetRegister(m)), ir.GetRegister(a));
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZ(ir.NZFrom(result));
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -59,8 +58,7 @@ bool TranslatorVisitor::arm_MUL(Cond cond, bool S, Reg d, Reg m, Reg n) {
|
|||||||
const auto result = ir.Mul(ir.GetRegister(n), ir.GetRegister(m));
|
const auto result = ir.Mul(ir.GetRegister(n), ir.GetRegister(m));
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZ(ir.NZFrom(result));
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -91,8 +89,7 @@ bool TranslatorVisitor::arm_SMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Re
|
|||||||
ir.SetRegister(dLo, lo);
|
ir.SetRegister(dLo, lo);
|
||||||
ir.SetRegister(dHi, hi);
|
ir.SetRegister(dHi, hi);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(hi));
|
ir.SetCpsrNZ(ir.NZFrom(result));
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -121,8 +118,7 @@ bool TranslatorVisitor::arm_SMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Re
|
|||||||
ir.SetRegister(dLo, lo);
|
ir.SetRegister(dLo, lo);
|
||||||
ir.SetRegister(dHi, hi);
|
ir.SetRegister(dHi, hi);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(hi));
|
ir.SetCpsrNZ(ir.NZFrom(result));
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -177,8 +173,7 @@ bool TranslatorVisitor::arm_UMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Re
|
|||||||
ir.SetRegister(dLo, lo);
|
ir.SetRegister(dLo, lo);
|
||||||
ir.SetRegister(dHi, hi);
|
ir.SetRegister(dHi, hi);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(hi));
|
ir.SetCpsrNZ(ir.NZFrom(result));
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -207,8 +202,7 @@ bool TranslatorVisitor::arm_UMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Re
|
|||||||
ir.SetRegister(dLo, lo);
|
ir.SetRegister(dLo, lo);
|
||||||
ir.SetRegister(dHi, hi);
|
ir.SetRegister(dHi, hi);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(hi));
|
ir.SetCpsrNZ(ir.NZFrom(result));
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -22,9 +22,7 @@ bool TranslatorVisitor::thumb16_LSL_imm(Imm<5> imm5, Reg m, Reg d) {
|
|||||||
|
|
||||||
ir.SetRegister(d, result.result);
|
ir.SetRegister(d, result.result);
|
||||||
if (!ir.current_location.IT().IsInITBlock()) {
|
if (!ir.current_location.IT().IsInITBlock()) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
ir.SetCpsrNZC(ir.NZFrom(result.result), result.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result.result));
|
|
||||||
ir.SetCFlag(result.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -37,9 +35,7 @@ bool TranslatorVisitor::thumb16_LSR_imm(Imm<5> imm5, Reg m, Reg d) {
|
|||||||
|
|
||||||
ir.SetRegister(d, result.result);
|
ir.SetRegister(d, result.result);
|
||||||
if (!ir.current_location.IT().IsInITBlock()) {
|
if (!ir.current_location.IT().IsInITBlock()) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
ir.SetCpsrNZC(ir.NZFrom(result.result), result.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result.result));
|
|
||||||
ir.SetCFlag(result.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -52,9 +48,7 @@ bool TranslatorVisitor::thumb16_ASR_imm(Imm<5> imm5, Reg m, Reg d) {
|
|||||||
|
|
||||||
ir.SetRegister(d, result.result);
|
ir.SetRegister(d, result.result);
|
||||||
if (!ir.current_location.IT().IsInITBlock()) {
|
if (!ir.current_location.IT().IsInITBlock()) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
ir.SetCpsrNZC(ir.NZFrom(result.result), result.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result.result));
|
|
||||||
ir.SetCFlag(result.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -117,8 +111,7 @@ bool TranslatorVisitor::thumb16_MOV_imm(Reg d, Imm<8> imm8) {
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (!ir.current_location.IT().IsInITBlock()) {
|
if (!ir.current_location.IT().IsInITBlock()) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZ(ir.NZFrom(result));
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -171,8 +164,7 @@ bool TranslatorVisitor::thumb16_AND_reg(Reg m, Reg d_n) {
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (!ir.current_location.IT().IsInITBlock()) {
|
if (!ir.current_location.IT().IsInITBlock()) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZ(ir.NZFrom(result));
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -186,8 +178,7 @@ bool TranslatorVisitor::thumb16_EOR_reg(Reg m, Reg d_n) {
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (!ir.current_location.IT().IsInITBlock()) {
|
if (!ir.current_location.IT().IsInITBlock()) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZ(ir.NZFrom(result));
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -202,9 +193,7 @@ bool TranslatorVisitor::thumb16_LSL_reg(Reg m, Reg d_n) {
|
|||||||
|
|
||||||
ir.SetRegister(d, result_carry.result);
|
ir.SetRegister(d, result_carry.result);
|
||||||
if (!ir.current_location.IT().IsInITBlock()) {
|
if (!ir.current_location.IT().IsInITBlock()) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result_carry.result));
|
ir.SetCpsrNZC(ir.NZFrom(result_carry.result), result_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result_carry.result));
|
|
||||||
ir.SetCFlag(result_carry.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -219,9 +208,7 @@ bool TranslatorVisitor::thumb16_LSR_reg(Reg m, Reg d_n) {
|
|||||||
|
|
||||||
ir.SetRegister(d, result.result);
|
ir.SetRegister(d, result.result);
|
||||||
if (!ir.current_location.IT().IsInITBlock()) {
|
if (!ir.current_location.IT().IsInITBlock()) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
ir.SetCpsrNZC(ir.NZFrom(result.result), result.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result.result));
|
|
||||||
ir.SetCFlag(result.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -236,9 +223,7 @@ bool TranslatorVisitor::thumb16_ASR_reg(Reg m, Reg d_n) {
|
|||||||
|
|
||||||
ir.SetRegister(d, result.result);
|
ir.SetRegister(d, result.result);
|
||||||
if (!ir.current_location.IT().IsInITBlock()) {
|
if (!ir.current_location.IT().IsInITBlock()) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
ir.SetCpsrNZC(ir.NZFrom(result.result), result.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result.result));
|
|
||||||
ir.SetCFlag(result.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -283,9 +268,7 @@ bool TranslatorVisitor::thumb16_ROR_reg(Reg m, Reg d_n) {
|
|||||||
|
|
||||||
ir.SetRegister(d, result.result);
|
ir.SetRegister(d, result.result);
|
||||||
if (!ir.current_location.IT().IsInITBlock()) {
|
if (!ir.current_location.IT().IsInITBlock()) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
ir.SetCpsrNZC(ir.NZFrom(result.result), result.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result.result));
|
|
||||||
ir.SetCFlag(result.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -293,8 +276,7 @@ bool TranslatorVisitor::thumb16_ROR_reg(Reg m, Reg d_n) {
|
|||||||
// TST <Rn>, <Rm>
|
// TST <Rn>, <Rm>
|
||||||
bool TranslatorVisitor::thumb16_TST_reg(Reg m, Reg n) {
|
bool TranslatorVisitor::thumb16_TST_reg(Reg m, Reg n) {
|
||||||
const auto result = ir.And(ir.GetRegister(n), ir.GetRegister(m));
|
const auto result = ir.And(ir.GetRegister(n), ir.GetRegister(m));
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZ(ir.NZFrom(result));
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,8 +314,7 @@ bool TranslatorVisitor::thumb16_ORR_reg(Reg m, Reg d_n) {
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (!ir.current_location.IT().IsInITBlock()) {
|
if (!ir.current_location.IT().IsInITBlock()) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZ(ir.NZFrom(result));
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -347,8 +328,7 @@ bool TranslatorVisitor::thumb16_MUL_reg(Reg n, Reg d_m) {
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (!ir.current_location.IT().IsInITBlock()) {
|
if (!ir.current_location.IT().IsInITBlock()) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZ(ir.NZFrom(result));
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -362,8 +342,7 @@ bool TranslatorVisitor::thumb16_BIC_reg(Reg m, Reg d_n) {
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (!ir.current_location.IT().IsInITBlock()) {
|
if (!ir.current_location.IT().IsInITBlock()) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZ(ir.NZFrom(result));
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -375,8 +354,7 @@ bool TranslatorVisitor::thumb16_MVN_reg(Reg m, Reg d) {
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (!ir.current_location.IT().IsInITBlock()) {
|
if (!ir.current_location.IT().IsInITBlock()) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZ(ir.NZFrom(result));
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,7 @@ bool TranslatorVisitor::thumb32_TST_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm
|
|||||||
const auto imm_carry = ThumbExpandImm_C(i, imm3, imm8, ir.GetCFlag());
|
const auto imm_carry = ThumbExpandImm_C(i, imm3, imm8, ir.GetCFlag());
|
||||||
const auto result = ir.And(ir.GetRegister(n), ir.Imm32(imm_carry.imm32));
|
const auto result = ir.And(ir.GetRegister(n), ir.Imm32(imm_carry.imm32));
|
||||||
|
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,9 +30,7 @@ bool TranslatorVisitor::thumb32_AND_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Re
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -49,9 +45,7 @@ bool TranslatorVisitor::thumb32_BIC_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Re
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -66,9 +60,7 @@ bool TranslatorVisitor::thumb32_MOV_imm(Imm<1> i, bool S, Imm<3> imm3, Reg d, Im
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -84,9 +76,7 @@ bool TranslatorVisitor::thumb32_ORR_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Re
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -101,9 +91,7 @@ bool TranslatorVisitor::thumb32_MVN_imm(Imm<1> i, bool S, Imm<3> imm3, Reg d, Im
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -119,9 +107,7 @@ bool TranslatorVisitor::thumb32_ORN_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Re
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -134,9 +120,7 @@ bool TranslatorVisitor::thumb32_TEQ_imm(Imm<1> i, Reg n, Imm<3> imm3, Imm<8> imm
|
|||||||
const auto imm_carry = ThumbExpandImm_C(i, imm3, imm8, ir.GetCFlag());
|
const auto imm_carry = ThumbExpandImm_C(i, imm3, imm8, ir.GetCFlag());
|
||||||
const auto result = ir.Eor(ir.GetRegister(n), ir.Imm32(imm_carry.imm32));
|
const auto result = ir.Eor(ir.GetRegister(n), ir.Imm32(imm_carry.imm32));
|
||||||
|
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,9 +135,7 @@ bool TranslatorVisitor::thumb32_EOR_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Re
|
|||||||
|
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), imm_carry.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(imm_carry.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,7 @@ bool ShiftInstruction(TranslatorVisitor& v, Reg m, Reg d, Reg s, bool S, ShiftFu
|
|||||||
const auto result_carry = (v.ir.*shift_fn)(v.ir.GetRegister(m), shift_s, apsr_c);
|
const auto result_carry = (v.ir.*shift_fn)(v.ir.GetRegister(m), shift_s, apsr_c);
|
||||||
|
|
||||||
if (S) {
|
if (S) {
|
||||||
v.ir.SetNFlag(v.ir.MostSignificantBit(result_carry.result));
|
v.ir.SetCpsrNZC(v.ir.NZFrom(result_carry.result), result_carry.carry);
|
||||||
v.ir.SetZFlag(v.ir.IsZero(result_carry.result));
|
|
||||||
v.ir.SetCFlag(result_carry.carry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v.ir.SetRegister(d, result_carry.result);
|
v.ir.SetRegister(d, result_carry.result);
|
||||||
|
@ -15,9 +15,7 @@ bool TranslatorVisitor::thumb32_TST_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftTy
|
|||||||
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
|
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
|
||||||
const auto result = ir.And(ir.GetRegister(n), shifted.result);
|
const auto result = ir.And(ir.GetRegister(n), shifted.result);
|
||||||
|
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,9 +30,7 @@ bool TranslatorVisitor::thumb32_AND_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2
|
|||||||
const auto result = ir.And(ir.GetRegister(n), shifted.result);
|
const auto result = ir.And(ir.GetRegister(n), shifted.result);
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -48,9 +44,7 @@ bool TranslatorVisitor::thumb32_BIC_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2
|
|||||||
const auto result = ir.AndNot(ir.GetRegister(n), shifted.result);
|
const auto result = ir.AndNot(ir.GetRegister(n), shifted.result);
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -64,9 +58,7 @@ bool TranslatorVisitor::thumb32_MOV_reg(bool S, Imm<3> imm3, Reg d, Imm<2> imm2,
|
|||||||
const auto result = shifted.result;
|
const auto result = shifted.result;
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -82,9 +74,7 @@ bool TranslatorVisitor::thumb32_ORR_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2
|
|||||||
const auto result = ir.Or(ir.GetRegister(n), shifted.result);
|
const auto result = ir.Or(ir.GetRegister(n), shifted.result);
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -98,9 +88,7 @@ bool TranslatorVisitor::thumb32_MVN_reg(bool S, Imm<3> imm3, Reg d, Imm<2> imm2,
|
|||||||
const auto result = ir.Not(shifted.result);
|
const auto result = ir.Not(shifted.result);
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -116,9 +104,7 @@ bool TranslatorVisitor::thumb32_ORN_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2
|
|||||||
const auto result = ir.Or(ir.GetRegister(n), ir.Not(shifted.result));
|
const auto result = ir.Or(ir.GetRegister(n), ir.Not(shifted.result));
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -131,9 +117,7 @@ bool TranslatorVisitor::thumb32_TEQ_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftTy
|
|||||||
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
|
const auto shifted = EmitImmShift(ir.GetRegister(m), type, imm3, imm2, ir.GetCFlag());
|
||||||
const auto result = ir.Eor(ir.GetRegister(n), shifted.result);
|
const auto result = ir.Eor(ir.GetRegister(n), shifted.result);
|
||||||
|
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,9 +132,7 @@ bool TranslatorVisitor::thumb32_EOR_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2
|
|||||||
const auto result = ir.Eor(ir.GetRegister(n), shifted.result);
|
const auto result = ir.Eor(ir.GetRegister(n), shifted.result);
|
||||||
ir.SetRegister(d, result);
|
ir.SetRegister(d, result);
|
||||||
if (S) {
|
if (S) {
|
||||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
ir.SetCpsrNZC(ir.NZFrom(result), shifted.carry);
|
||||||
ir.SetZFlag(ir.IsZero(result));
|
|
||||||
ir.SetCFlag(shifted.carry);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ enum class ThumbInstSize {
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool IsThumb16(u16 first_part) {
|
bool IsThumb16(u16 first_part) {
|
||||||
return (first_part & 0xF800) < 0xE800;
|
return first_part < 0xE800;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsUnconditionalInstruction(bool is_thumb_16, u32 instruction) {
|
bool IsUnconditionalInstruction(bool is_thumb_16, u32 instruction) {
|
||||||
|
@ -5,15 +5,12 @@
|
|||||||
|
|
||||||
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
|
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
|
||||||
|
|
||||||
#include <ostream>
|
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
namespace Dynarmic::A64 {
|
namespace Dynarmic::A64 {
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor) {
|
std::string ToString(const LocationDescriptor& descriptor) {
|
||||||
o << fmt::format("{{{}, {}{}}}", descriptor.PC(), descriptor.FPCR().Value(), descriptor.SingleStepping() ? ", step" : "");
|
return fmt::format("{{{}, {}{}}}", descriptor.PC(), descriptor.FPCR().Value(), descriptor.SingleStepping() ? ", step" : "");
|
||||||
return o;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Dynarmic::A64
|
} // namespace Dynarmic::A64
|
||||||
|
@ -6,9 +6,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iosfwd>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
#include <mcl/bit/bit_field.hpp>
|
#include <mcl/bit/bit_field.hpp>
|
||||||
#include <mcl/stdint.hpp>
|
#include <mcl/stdint.hpp>
|
||||||
|
|
||||||
@ -84,10 +85,9 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Provides a string representation of a LocationDescriptor.
|
* Provides a string representation of a LocationDescriptor.
|
||||||
*
|
*
|
||||||
* @param o Output stream
|
|
||||||
* @param descriptor The descriptor to get a string representation of
|
* @param descriptor The descriptor to get a string representation of
|
||||||
*/
|
*/
|
||||||
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor);
|
std::string ToString(const LocationDescriptor& descriptor);
|
||||||
|
|
||||||
} // namespace Dynarmic::A64
|
} // namespace Dynarmic::A64
|
||||||
|
|
||||||
@ -105,3 +105,11 @@ struct hash<Dynarmic::A64::LocationDescriptor> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct fmt::formatter<Dynarmic::A64::LocationDescriptor> : fmt::formatter<std::string> {
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(Dynarmic::A64::LocationDescriptor descriptor, FormatContext& ctx) const {
|
||||||
|
return formatter<std::string>::format(Dynarmic::A64::ToString(descriptor), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -30,14 +30,4 @@ std::string VecToString(Vec vec) {
|
|||||||
return fmt::format("v{}", static_cast<size_t>(vec));
|
return fmt::format("v{}", static_cast<size_t>(vec));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, Reg reg) {
|
|
||||||
o << RegToString(reg);
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, Vec vec) {
|
|
||||||
o << VecToString(vec);
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::A64
|
} // namespace Dynarmic::A64
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <iosfwd>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
#include <mcl/assert.hpp>
|
#include <mcl/assert.hpp>
|
||||||
#include <mcl/stdint.hpp>
|
#include <mcl/stdint.hpp>
|
||||||
|
|
||||||
@ -101,9 +101,6 @@ const char* CondToString(Cond cond);
|
|||||||
std::string RegToString(Reg reg);
|
std::string RegToString(Reg reg);
|
||||||
std::string VecToString(Vec vec);
|
std::string VecToString(Vec vec);
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, Reg reg);
|
|
||||||
std::ostream& operator<<(std::ostream& o, Vec vec);
|
|
||||||
|
|
||||||
constexpr size_t RegNumber(Reg reg) {
|
constexpr size_t RegNumber(Reg reg) {
|
||||||
return static_cast<size_t>(reg);
|
return static_cast<size_t>(reg);
|
||||||
}
|
}
|
||||||
@ -127,3 +124,19 @@ inline Vec operator+(Vec vec, size_t number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Dynarmic::A64
|
} // namespace Dynarmic::A64
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct fmt::formatter<Dynarmic::A64::Reg> : fmt::formatter<std::string> {
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(Dynarmic::A64::Reg reg, FormatContext& ctx) const {
|
||||||
|
return formatter<std::string>::format(Dynarmic::A64::RegToString(reg), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct fmt::formatter<Dynarmic::A64::Vec> : fmt::formatter<std::string> {
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(Dynarmic::A64::Vec vec, FormatContext& ctx) const {
|
||||||
|
return formatter<std::string>::format(Dynarmic::A64::VecToString(vec), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -135,6 +135,10 @@ U32U64 IREmitter::ConditionalSelect(Cond cond, const U32U64& a, const U32U64& b)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U1 IREmitter::GetCFlagFromNZCV(const NZCV& nzcv) {
|
||||||
|
return Inst<U1>(Opcode::GetCFlagFromNZCV, nzcv);
|
||||||
|
}
|
||||||
|
|
||||||
NZCV IREmitter::NZCVFromPackedFlags(const U32& a) {
|
NZCV IREmitter::NZCVFromPackedFlags(const U32& a) {
|
||||||
return Inst<NZCV>(Opcode::NZCVFromPackedFlags, a);
|
return Inst<NZCV>(Opcode::NZCVFromPackedFlags, a);
|
||||||
}
|
}
|
||||||
|
15
externals/dynarmic/src/dynarmic/ir/ir_emitter.h
vendored
15
externals/dynarmic/src/dynarmic/ir/ir_emitter.h
vendored
@ -101,6 +101,7 @@ public:
|
|||||||
NZCV ConditionalSelect(Cond cond, const NZCV& a, const NZCV& b);
|
NZCV ConditionalSelect(Cond cond, const NZCV& a, const NZCV& b);
|
||||||
U32U64 ConditionalSelect(Cond cond, const U32U64& a, const U32U64& b);
|
U32U64 ConditionalSelect(Cond cond, const U32U64& a, const U32U64& b);
|
||||||
|
|
||||||
|
U1 GetCFlagFromNZCV(const NZCV& nzcv);
|
||||||
NZCV NZCVFromPackedFlags(const U32& a);
|
NZCV NZCVFromPackedFlags(const U32& a);
|
||||||
// This pseudo-instruction may only be added to instructions that support it.
|
// This pseudo-instruction may only be added to instructions that support it.
|
||||||
NZCV NZCVFrom(const Value& value);
|
NZCV NZCVFrom(const Value& value);
|
||||||
@ -393,14 +394,24 @@ public:
|
|||||||
|
|
||||||
void SetTerm(const Terminal& terminal);
|
void SetTerm(const Terminal& terminal);
|
||||||
|
|
||||||
void SetInsertionPoint(IR::Inst* new_insertion_point) {
|
void SetInsertionPointBefore(IR::Inst* new_insertion_point) {
|
||||||
insertion_point = IR::Block::iterator{*new_insertion_point};
|
insertion_point = IR::Block::iterator{*new_insertion_point};
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetInsertionPoint(IR::Block::iterator new_insertion_point) {
|
void SetInsertionPointBefore(IR::Block::iterator new_insertion_point) {
|
||||||
insertion_point = new_insertion_point;
|
insertion_point = new_insertion_point;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetInsertionPointAfter(IR::Inst* new_insertion_point) {
|
||||||
|
insertion_point = IR::Block::iterator{*new_insertion_point};
|
||||||
|
++insertion_point;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetInsertionPointAfter(IR::Block::iterator new_insertion_point) {
|
||||||
|
insertion_point = new_insertion_point;
|
||||||
|
++insertion_point;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
IR::Block::iterator insertion_point;
|
IR::Block::iterator insertion_point;
|
||||||
|
|
||||||
|
@ -5,15 +5,12 @@
|
|||||||
|
|
||||||
#include "dynarmic/ir/location_descriptor.h"
|
#include "dynarmic/ir/location_descriptor.h"
|
||||||
|
|
||||||
#include <ostream>
|
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
namespace Dynarmic::IR {
|
namespace Dynarmic::IR {
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor) {
|
std::string ToString(const LocationDescriptor& descriptor) {
|
||||||
o << fmt::format("{{{:016x}}}", descriptor.Value());
|
return fmt::format("{{{:016x}}}", descriptor.Value());
|
||||||
return o;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Dynarmic::IR
|
} // namespace Dynarmic::IR
|
||||||
|
@ -6,8 +6,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iosfwd>
|
#include <string>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
#include <mcl/stdint.hpp>
|
#include <mcl/stdint.hpp>
|
||||||
|
|
||||||
namespace Dynarmic::IR {
|
namespace Dynarmic::IR {
|
||||||
@ -31,7 +32,7 @@ private:
|
|||||||
u64 value;
|
u64 value;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor);
|
std::string ToString(const LocationDescriptor& descriptor);
|
||||||
|
|
||||||
inline bool operator<(const LocationDescriptor& x, const LocationDescriptor& y) noexcept {
|
inline bool operator<(const LocationDescriptor& x, const LocationDescriptor& y) noexcept {
|
||||||
return x.Value() < y.Value();
|
return x.Value() < y.Value();
|
||||||
@ -53,3 +54,11 @@ struct hash<Dynarmic::IR::LocationDescriptor> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct fmt::formatter<Dynarmic::IR::LocationDescriptor> : fmt::formatter<std::string> {
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(Dynarmic::IR::LocationDescriptor descriptor, FormatContext& ctx) const {
|
||||||
|
return formatter<std::string>::format(ToString(descriptor), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
#include <mcl/assert.hpp>
|
#include <mcl/assert.hpp>
|
||||||
|
|
||||||
#include "dynarmic/ir/opcodes.h"
|
#include "dynarmic/ir/opcodes.h"
|
||||||
@ -176,10 +175,8 @@ bool Inst::WritesToCPSR() const {
|
|||||||
case Opcode::A32SetCpsrNZCVRaw:
|
case Opcode::A32SetCpsrNZCVRaw:
|
||||||
case Opcode::A32SetCpsrNZCV:
|
case Opcode::A32SetCpsrNZCV:
|
||||||
case Opcode::A32SetCpsrNZCVQ:
|
case Opcode::A32SetCpsrNZCVQ:
|
||||||
case Opcode::A32SetNFlag:
|
case Opcode::A32SetCpsrNZ:
|
||||||
case Opcode::A32SetZFlag:
|
case Opcode::A32SetCpsrNZC:
|
||||||
case Opcode::A32SetCFlag:
|
|
||||||
case Opcode::A32SetVFlag:
|
|
||||||
case Opcode::A32OrQFlag:
|
case Opcode::A32OrQFlag:
|
||||||
case Opcode::A32SetGEFlags:
|
case Opcode::A32SetGEFlags:
|
||||||
case Opcode::A32SetGEFlagsCompressed:
|
case Opcode::A32SetGEFlagsCompressed:
|
||||||
@ -546,8 +543,12 @@ bool Inst::IsAPseudoOperation() const {
|
|||||||
case Opcode::GetOverflowFromOp:
|
case Opcode::GetOverflowFromOp:
|
||||||
case Opcode::GetGEFromOp:
|
case Opcode::GetGEFromOp:
|
||||||
case Opcode::GetNZCVFromOp:
|
case Opcode::GetNZCVFromOp:
|
||||||
|
case Opcode::GetNZFromOp:
|
||||||
case Opcode::GetUpperFromOp:
|
case Opcode::GetUpperFromOp:
|
||||||
case Opcode::GetLowerFromOp:
|
case Opcode::GetLowerFromOp:
|
||||||
|
case Opcode::MostSignificantBit:
|
||||||
|
case Opcode::IsZero32:
|
||||||
|
case Opcode::IsZero64:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -583,40 +584,19 @@ bool Inst::AreAllArgsImmediates() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Inst::HasAssociatedPseudoOperation() const {
|
bool Inst::HasAssociatedPseudoOperation() const {
|
||||||
return carry_inst
|
return next_pseudoop && !IsAPseudoOperation();
|
||||||
|| overflow_inst
|
|
||||||
|| ge_inst
|
|
||||||
|| nzcv_inst
|
|
||||||
|| upper_inst
|
|
||||||
|| lower_inst;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Inst* Inst::GetAssociatedPseudoOperation(Opcode opcode) {
|
Inst* Inst::GetAssociatedPseudoOperation(Opcode opcode) {
|
||||||
// This is faster than doing a search through the block.
|
Inst* pseudoop = next_pseudoop;
|
||||||
switch (opcode) {
|
while (pseudoop) {
|
||||||
case Opcode::GetCarryFromOp:
|
if (pseudoop->GetOpcode() == opcode) {
|
||||||
ASSERT(!carry_inst || carry_inst->GetOpcode() == Opcode::GetCarryFromOp);
|
ASSERT(pseudoop->GetArg(0).GetInst() == this);
|
||||||
return carry_inst;
|
return pseudoop;
|
||||||
case Opcode::GetOverflowFromOp:
|
}
|
||||||
ASSERT(!overflow_inst || overflow_inst->GetOpcode() == Opcode::GetOverflowFromOp);
|
pseudoop = pseudoop->next_pseudoop;
|
||||||
return overflow_inst;
|
|
||||||
case Opcode::GetGEFromOp:
|
|
||||||
ASSERT(!ge_inst || ge_inst->GetOpcode() == Opcode::GetGEFromOp);
|
|
||||||
return ge_inst;
|
|
||||||
case Opcode::GetNZCVFromOp:
|
|
||||||
ASSERT(!nzcv_inst || nzcv_inst->GetOpcode() == Opcode::GetNZCVFromOp);
|
|
||||||
return nzcv_inst;
|
|
||||||
case Opcode::GetUpperFromOp:
|
|
||||||
ASSERT(!upper_inst || upper_inst->GetOpcode() == Opcode::GetUpperFromOp);
|
|
||||||
return upper_inst;
|
|
||||||
case Opcode::GetLowerFromOp:
|
|
||||||
ASSERT(!lower_inst || lower_inst->GetOpcode() == Opcode::GetLowerFromOp);
|
|
||||||
return lower_inst;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
ASSERT_FALSE("Not a valid pseudo-operation");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Type Inst::GetType() const {
|
Type Inst::GetType() const {
|
||||||
@ -679,67 +659,31 @@ void Inst::ReplaceUsesWith(Value replacement) {
|
|||||||
void Inst::Use(const Value& value) {
|
void Inst::Use(const Value& value) {
|
||||||
value.GetInst()->use_count++;
|
value.GetInst()->use_count++;
|
||||||
|
|
||||||
switch (op) {
|
if (IsAPseudoOperation()) {
|
||||||
case Opcode::GetCarryFromOp:
|
if (op == Opcode::GetNZCVFromOp) {
|
||||||
ASSERT_MSG(!value.GetInst()->carry_inst, "Only one of each type of pseudo-op allowed");
|
ASSERT_MSG(value.GetInst()->MayGetNZCVFromOp(), "This value doesn't support the GetNZCVFromOp pseduo-op");
|
||||||
value.GetInst()->carry_inst = this;
|
}
|
||||||
break;
|
|
||||||
case Opcode::GetOverflowFromOp:
|
Inst* insert_point = value.GetInst();
|
||||||
ASSERT_MSG(!value.GetInst()->overflow_inst, "Only one of each type of pseudo-op allowed");
|
while (insert_point->next_pseudoop) {
|
||||||
value.GetInst()->overflow_inst = this;
|
insert_point = insert_point->next_pseudoop;
|
||||||
break;
|
DEBUG_ASSERT(insert_point->GetArg(0).GetInst() == value.GetInst());
|
||||||
case Opcode::GetGEFromOp:
|
}
|
||||||
ASSERT_MSG(!value.GetInst()->ge_inst, "Only one of each type of pseudo-op allowed");
|
insert_point->next_pseudoop = this;
|
||||||
value.GetInst()->ge_inst = this;
|
|
||||||
break;
|
|
||||||
case Opcode::GetNZCVFromOp:
|
|
||||||
ASSERT_MSG(!value.GetInst()->nzcv_inst, "Only one of each type of pseudo-op allowed");
|
|
||||||
ASSERT_MSG(value.GetInst()->MayGetNZCVFromOp(), "This value doesn't support the GetNZCVFromOp pseduo-op");
|
|
||||||
value.GetInst()->nzcv_inst = this;
|
|
||||||
break;
|
|
||||||
case Opcode::GetUpperFromOp:
|
|
||||||
ASSERT_MSG(!value.GetInst()->upper_inst, "Only one of each type of pseudo-op allowed");
|
|
||||||
value.GetInst()->upper_inst = this;
|
|
||||||
break;
|
|
||||||
case Opcode::GetLowerFromOp:
|
|
||||||
ASSERT_MSG(!value.GetInst()->lower_inst, "Only one of each type of pseudo-op allowed");
|
|
||||||
value.GetInst()->lower_inst = this;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Inst::UndoUse(const Value& value) {
|
void Inst::UndoUse(const Value& value) {
|
||||||
value.GetInst()->use_count--;
|
value.GetInst()->use_count--;
|
||||||
|
|
||||||
switch (op) {
|
if (IsAPseudoOperation()) {
|
||||||
case Opcode::GetCarryFromOp:
|
Inst* insert_point = value.GetInst();
|
||||||
ASSERT(value.GetInst()->carry_inst->GetOpcode() == Opcode::GetCarryFromOp);
|
while (insert_point->next_pseudoop != this) {
|
||||||
value.GetInst()->carry_inst = nullptr;
|
insert_point = insert_point->next_pseudoop;
|
||||||
break;
|
DEBUG_ASSERT(insert_point->GetArg(0).GetInst() == value.GetInst());
|
||||||
case Opcode::GetOverflowFromOp:
|
}
|
||||||
ASSERT(value.GetInst()->overflow_inst->GetOpcode() == Opcode::GetOverflowFromOp);
|
insert_point->next_pseudoop = next_pseudoop;
|
||||||
value.GetInst()->overflow_inst = nullptr;
|
next_pseudoop = nullptr;
|
||||||
break;
|
|
||||||
case Opcode::GetGEFromOp:
|
|
||||||
ASSERT(value.GetInst()->ge_inst->GetOpcode() == Opcode::GetGEFromOp);
|
|
||||||
value.GetInst()->ge_inst = nullptr;
|
|
||||||
break;
|
|
||||||
case Opcode::GetNZCVFromOp:
|
|
||||||
ASSERT(value.GetInst()->nzcv_inst->GetOpcode() == Opcode::GetNZCVFromOp);
|
|
||||||
value.GetInst()->nzcv_inst = nullptr;
|
|
||||||
break;
|
|
||||||
case Opcode::GetUpperFromOp:
|
|
||||||
ASSERT(value.GetInst()->upper_inst->GetOpcode() == Opcode::GetUpperFromOp);
|
|
||||||
value.GetInst()->upper_inst = nullptr;
|
|
||||||
break;
|
|
||||||
case Opcode::GetLowerFromOp:
|
|
||||||
ASSERT(value.GetInst()->lower_inst->GetOpcode() == Opcode::GetLowerFromOp);
|
|
||||||
value.GetInst()->lower_inst = nullptr;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,18 +149,8 @@ private:
|
|||||||
size_t use_count = 0;
|
size_t use_count = 0;
|
||||||
std::array<Value, max_arg_count> args;
|
std::array<Value, max_arg_count> args;
|
||||||
|
|
||||||
// Pointers to related pseudooperations:
|
// Linked list of pseudooperations associated with this instruction.
|
||||||
// Since not all combinations are possible, we use a union to save space
|
Inst* next_pseudoop = nullptr;
|
||||||
union {
|
|
||||||
Inst* carry_inst = nullptr;
|
|
||||||
Inst* ge_inst;
|
|
||||||
Inst* upper_inst;
|
|
||||||
};
|
|
||||||
Inst* overflow_inst = nullptr;
|
|
||||||
union {
|
|
||||||
Inst* nzcv_inst = nullptr;
|
|
||||||
Inst* lower_inst;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Dynarmic::IR
|
} // namespace Dynarmic::IR
|
||||||
|
@ -73,8 +73,4 @@ std::string GetNameOf(Opcode op) {
|
|||||||
return OpcodeInfo::opcode_info.at(static_cast<size_t>(op)).name;
|
return OpcodeInfo::opcode_info.at(static_cast<size_t>(op)).name;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, Opcode opcode) {
|
|
||||||
return o << GetNameOf(opcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::IR
|
} // namespace Dynarmic::IR
|
||||||
|
12
externals/dynarmic/src/dynarmic/ir/opcodes.h
vendored
12
externals/dynarmic/src/dynarmic/ir/opcodes.h
vendored
@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <iosfwd>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
#include <mcl/stdint.hpp>
|
#include <mcl/stdint.hpp>
|
||||||
|
|
||||||
namespace Dynarmic::IR {
|
namespace Dynarmic::IR {
|
||||||
@ -43,6 +43,12 @@ Type GetArgTypeOf(Opcode op, size_t arg_index);
|
|||||||
/// Get the name of an opcode.
|
/// Get the name of an opcode.
|
||||||
std::string GetNameOf(Opcode op);
|
std::string GetNameOf(Opcode op);
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, Opcode opcode);
|
|
||||||
|
|
||||||
} // namespace Dynarmic::IR
|
} // namespace Dynarmic::IR
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct fmt::formatter<Dynarmic::IR::Opcode> : fmt::formatter<std::string> {
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(Dynarmic::IR::Opcode op, FormatContext& ctx) const {
|
||||||
|
return formatter<std::string>::format(Dynarmic::IR::GetNameOf(op), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -22,11 +22,9 @@ A32OPC(SetCpsr, Void, U32
|
|||||||
A32OPC(SetCpsrNZCV, Void, NZCV )
|
A32OPC(SetCpsrNZCV, Void, NZCV )
|
||||||
A32OPC(SetCpsrNZCVRaw, Void, U32 )
|
A32OPC(SetCpsrNZCVRaw, Void, U32 )
|
||||||
A32OPC(SetCpsrNZCVQ, Void, U32 )
|
A32OPC(SetCpsrNZCVQ, Void, U32 )
|
||||||
A32OPC(SetNFlag, Void, U1 )
|
A32OPC(SetCpsrNZ, Void, NZCV )
|
||||||
A32OPC(SetZFlag, Void, U1 )
|
A32OPC(SetCpsrNZC, Void, NZCV, U1 )
|
||||||
A32OPC(GetCFlag, U1, )
|
A32OPC(GetCFlag, U1, )
|
||||||
A32OPC(SetCFlag, Void, U1 )
|
|
||||||
A32OPC(SetVFlag, Void, U1 )
|
|
||||||
A32OPC(OrQFlag, Void, U1 )
|
A32OPC(OrQFlag, Void, U1 )
|
||||||
A32OPC(GetGEFlags, U32, )
|
A32OPC(GetGEFlags, U32, )
|
||||||
A32OPC(SetGEFlags, Void, U32 )
|
A32OPC(SetGEFlags, Void, U32 )
|
||||||
@ -90,9 +88,11 @@ OPCODE(GetCarryFromOp, U1, Opaq
|
|||||||
OPCODE(GetOverflowFromOp, U1, Opaque )
|
OPCODE(GetOverflowFromOp, U1, Opaque )
|
||||||
OPCODE(GetGEFromOp, U32, Opaque )
|
OPCODE(GetGEFromOp, U32, Opaque )
|
||||||
OPCODE(GetNZCVFromOp, NZCV, Opaque )
|
OPCODE(GetNZCVFromOp, NZCV, Opaque )
|
||||||
|
OPCODE(GetNZFromOp, NZCV, Opaque )
|
||||||
OPCODE(GetUpperFromOp, U128, Opaque )
|
OPCODE(GetUpperFromOp, U128, Opaque )
|
||||||
OPCODE(GetLowerFromOp, U128, Opaque )
|
OPCODE(GetLowerFromOp, U128, Opaque )
|
||||||
|
|
||||||
|
OPCODE(GetCFlagFromNZCV, U1, NZCV )
|
||||||
OPCODE(NZCVFromPackedFlags, NZCV, U32 )
|
OPCODE(NZCVFromPackedFlags, NZCV, U32 )
|
||||||
|
|
||||||
// Calculations
|
// Calculations
|
||||||
|
@ -13,13 +13,6 @@ namespace Dynarmic::Optimization {
|
|||||||
void A32ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
|
void A32ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
|
||||||
for (auto& inst : block) {
|
for (auto& inst : block) {
|
||||||
switch (inst.GetOpcode()) {
|
switch (inst.GetOpcode()) {
|
||||||
case IR::Opcode::A32SetCFlag: {
|
|
||||||
const IR::Value arg = inst.GetArg(0);
|
|
||||||
if (!arg.IsImmediate() && arg.GetInst()->GetOpcode() == IR::Opcode::A32GetCFlag) {
|
|
||||||
inst.Invalidate();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case IR::Opcode::A32ReadMemory8: {
|
case IR::Opcode::A32ReadMemory8: {
|
||||||
if (!inst.AreAllArgsImmediates()) {
|
if (!inst.AreAllArgsImmediates()) {
|
||||||
break;
|
break;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <mcl/assert.hpp>
|
#include <mcl/assert.hpp>
|
||||||
#include <mcl/stdint.hpp>
|
#include <mcl/stdint.hpp>
|
||||||
|
|
||||||
|
#include "dynarmic/frontend/A32/a32_ir_emitter.h"
|
||||||
#include "dynarmic/frontend/A32/a32_types.h"
|
#include "dynarmic/frontend/A32/a32_types.h"
|
||||||
#include "dynarmic/ir/basic_block.h"
|
#include "dynarmic/ir/basic_block.h"
|
||||||
#include "dynarmic/ir/opcodes.h"
|
#include "dynarmic/ir/opcodes.h"
|
||||||
@ -16,7 +17,7 @@
|
|||||||
|
|
||||||
namespace Dynarmic::Optimization {
|
namespace Dynarmic::Optimization {
|
||||||
|
|
||||||
void A32GetSetElimination(IR::Block& block) {
|
void A32GetSetElimination(IR::Block& block, A32GetSetEliminationOptions opt) {
|
||||||
using Iterator = IR::Block::iterator;
|
using Iterator = IR::Block::iterator;
|
||||||
struct RegisterInfo {
|
struct RegisterInfo {
|
||||||
IR::Value register_value;
|
IR::Value register_value;
|
||||||
@ -29,24 +30,34 @@ void A32GetSetElimination(IR::Block& block) {
|
|||||||
std::array<RegisterInfo, 32> ext_reg_vector_double_info;
|
std::array<RegisterInfo, 32> ext_reg_vector_double_info;
|
||||||
std::array<RegisterInfo, 16> ext_reg_vector_quad_info;
|
std::array<RegisterInfo, 16> ext_reg_vector_quad_info;
|
||||||
struct CpsrInfo {
|
struct CpsrInfo {
|
||||||
RegisterInfo n;
|
RegisterInfo nz;
|
||||||
RegisterInfo z;
|
|
||||||
RegisterInfo c;
|
RegisterInfo c;
|
||||||
RegisterInfo v;
|
RegisterInfo nzc;
|
||||||
|
RegisterInfo nzcv;
|
||||||
RegisterInfo ge;
|
RegisterInfo ge;
|
||||||
} cpsr_info;
|
} cpsr_info;
|
||||||
|
|
||||||
const auto do_set = [&block](RegisterInfo& info, IR::Value value, Iterator set_inst) {
|
const auto do_delete_last_set = [&block](RegisterInfo& info) {
|
||||||
if (info.set_instruction_present) {
|
if (info.set_instruction_present) {
|
||||||
|
info.set_instruction_present = false;
|
||||||
info.last_set_instruction->Invalidate();
|
info.last_set_instruction->Invalidate();
|
||||||
block.Instructions().erase(info.last_set_instruction);
|
block.Instructions().erase(info.last_set_instruction);
|
||||||
}
|
}
|
||||||
|
info = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto do_set = [&do_delete_last_set](RegisterInfo& info, IR::Value value, Iterator set_inst) {
|
||||||
|
do_delete_last_set(info);
|
||||||
info.register_value = value;
|
info.register_value = value;
|
||||||
info.set_instruction_present = true;
|
info.set_instruction_present = true;
|
||||||
info.last_set_instruction = set_inst;
|
info.last_set_instruction = set_inst;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const auto do_set_without_inst = [&do_delete_last_set](RegisterInfo& info, IR::Value value) {
|
||||||
|
do_delete_last_set(info);
|
||||||
|
info.register_value = value;
|
||||||
|
};
|
||||||
|
|
||||||
const auto do_get = [](RegisterInfo& info, Iterator get_inst) {
|
const auto do_get = [](RegisterInfo& info, Iterator get_inst) {
|
||||||
if (info.register_value.IsEmpty()) {
|
if (info.register_value.IsEmpty()) {
|
||||||
info.register_value = IR::Value(&*get_inst);
|
info.register_value = IR::Value(&*get_inst);
|
||||||
@ -55,6 +66,9 @@ void A32GetSetElimination(IR::Block& block) {
|
|||||||
get_inst->ReplaceUsesWith(info.register_value);
|
get_inst->ReplaceUsesWith(info.register_value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Location and version don't matter here.
|
||||||
|
A32::IREmitter ir{block, A32::LocationDescriptor{block.Location()}, {}};
|
||||||
|
|
||||||
for (auto inst = block.begin(); inst != block.end(); ++inst) {
|
for (auto inst = block.begin(); inst != block.end(); ++inst) {
|
||||||
switch (inst->GetOpcode()) {
|
switch (inst->GetOpcode()) {
|
||||||
case IR::Opcode::A32SetRegister: {
|
case IR::Opcode::A32SetRegister: {
|
||||||
@ -167,24 +181,66 @@ void A32GetSetElimination(IR::Block& block) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A32SetNFlag: {
|
|
||||||
do_set(cpsr_info.n, inst->GetArg(0), inst);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case IR::Opcode::A32SetZFlag: {
|
|
||||||
do_set(cpsr_info.z, inst->GetArg(0), inst);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case IR::Opcode::A32SetCFlag: {
|
|
||||||
do_set(cpsr_info.c, inst->GetArg(0), inst);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case IR::Opcode::A32GetCFlag: {
|
case IR::Opcode::A32GetCFlag: {
|
||||||
|
if (cpsr_info.c.register_value.IsEmpty() && cpsr_info.nzcv.register_value.GetType() == IR::Type::NZCVFlags) {
|
||||||
|
ir.SetInsertionPointBefore(inst);
|
||||||
|
IR::U1 c = ir.GetCFlagFromNZCV(IR::NZCV{cpsr_info.nzcv.register_value});
|
||||||
|
inst->ReplaceUsesWith(c);
|
||||||
|
cpsr_info.c.register_value = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
do_get(cpsr_info.c, inst);
|
do_get(cpsr_info.c, inst);
|
||||||
|
// ensure source is not deleted
|
||||||
|
cpsr_info.nzc = {};
|
||||||
|
cpsr_info.nzcv = {};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A32SetVFlag: {
|
case IR::Opcode::A32SetCpsrNZCV:
|
||||||
do_set(cpsr_info.v, inst->GetArg(0), inst);
|
case IR::Opcode::A32SetCpsrNZCVRaw: {
|
||||||
|
do_delete_last_set(cpsr_info.nz);
|
||||||
|
do_delete_last_set(cpsr_info.c);
|
||||||
|
do_delete_last_set(cpsr_info.nzc);
|
||||||
|
do_set(cpsr_info.nzcv, inst->GetArg(0), inst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IR::Opcode::A32SetCpsrNZCVQ: {
|
||||||
|
do_delete_last_set(cpsr_info.nz);
|
||||||
|
do_delete_last_set(cpsr_info.c);
|
||||||
|
do_delete_last_set(cpsr_info.nzc);
|
||||||
|
do_delete_last_set(cpsr_info.nzcv);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IR::Opcode::A32SetCpsrNZ: {
|
||||||
|
if (cpsr_info.nzc.set_instruction_present) {
|
||||||
|
cpsr_info.nzc.last_set_instruction->SetArg(0, IR::Value::EmptyNZCVImmediateMarker());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt.convert_nz_to_nzc && !cpsr_info.c.register_value.IsEmpty()) {
|
||||||
|
ir.SetInsertionPointAfter(inst);
|
||||||
|
ir.SetCpsrNZC(IR::NZCV{inst->GetArg(0)}, ir.GetCFlag());
|
||||||
|
inst->Invalidate();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cpsr_info.c remains valid
|
||||||
|
cpsr_info.nzc = {};
|
||||||
|
cpsr_info.nzcv = {};
|
||||||
|
do_set(cpsr_info.nz, inst->GetArg(0), inst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IR::Opcode::A32SetCpsrNZC: {
|
||||||
|
if (opt.convert_nzc_to_nz && !inst->GetArg(1).IsImmediate() && inst->GetArg(1).GetInstRecursive()->GetOpcode() == IR::Opcode::A32GetCFlag) {
|
||||||
|
ir.SetInsertionPointAfter(inst);
|
||||||
|
ir.SetCpsrNZ(IR::NZCV{inst->GetArg(0)});
|
||||||
|
inst->Invalidate();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpsr_info.nzcv = {};
|
||||||
|
do_set(cpsr_info.nzc, {}, inst);
|
||||||
|
do_set_without_inst(cpsr_info.nz, inst->GetArg(0));
|
||||||
|
do_set_without_inst(cpsr_info.c, inst->GetArg(1));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::A32SetGEFlags: {
|
case IR::Opcode::A32SetGEFlags: {
|
||||||
|
@ -26,7 +26,7 @@ void A64CallbackConfigPass(IR::Block& block, const A64::UserConfig& conf) {
|
|||||||
if (op == A64::DataCacheOperation::ZeroByVA) {
|
if (op == A64::DataCacheOperation::ZeroByVA) {
|
||||||
A64::IREmitter ir{block};
|
A64::IREmitter ir{block};
|
||||||
ir.current_location = A64::LocationDescriptor{IR::LocationDescriptor{inst.GetArg(0).GetU64()}};
|
ir.current_location = A64::LocationDescriptor{IR::LocationDescriptor{inst.GetArg(0).GetU64()}};
|
||||||
ir.SetInsertionPoint(&inst);
|
ir.SetInsertionPointBefore(&inst);
|
||||||
|
|
||||||
size_t bytes = 4 << static_cast<size_t>(conf.dczid_el0 & 0b1111);
|
size_t bytes = 4 << static_cast<size_t>(conf.dczid_el0 & 0b1111);
|
||||||
IR::U64 addr{inst.GetArg(2)};
|
IR::U64 addr{inst.GetArg(2)};
|
||||||
|
@ -26,9 +26,14 @@ struct PolyfillOptions {
|
|||||||
bool operator==(const PolyfillOptions&) const = default;
|
bool operator==(const PolyfillOptions&) const = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct A32GetSetEliminationOptions {
|
||||||
|
bool convert_nzc_to_nz = false;
|
||||||
|
bool convert_nz_to_nzc = false;
|
||||||
|
};
|
||||||
|
|
||||||
void PolyfillPass(IR::Block& block, const PolyfillOptions& opt);
|
void PolyfillPass(IR::Block& block, const PolyfillOptions& opt);
|
||||||
void A32ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb);
|
void A32ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb);
|
||||||
void A32GetSetElimination(IR::Block& block);
|
void A32GetSetElimination(IR::Block& block, A32GetSetEliminationOptions opt);
|
||||||
void A64CallbackConfigPass(IR::Block& block, const A64::UserConfig& conf);
|
void A64CallbackConfigPass(IR::Block& block, const A64::UserConfig& conf);
|
||||||
void A64GetSetElimination(IR::Block& block);
|
void A64GetSetElimination(IR::Block& block);
|
||||||
void A64MergeInterpretBlocksPass(IR::Block& block, A64::UserCallbacks* cb);
|
void A64MergeInterpretBlocksPass(IR::Block& block, A64::UserCallbacks* cb);
|
||||||
|
@ -148,7 +148,7 @@ void PolyfillPass(IR::Block& block, const PolyfillOptions& polyfill) {
|
|||||||
IR::IREmitter ir{block};
|
IR::IREmitter ir{block};
|
||||||
|
|
||||||
for (auto& inst : block) {
|
for (auto& inst : block) {
|
||||||
ir.SetInsertionPoint(&inst);
|
ir.SetInsertionPointBefore(&inst);
|
||||||
|
|
||||||
switch (inst.GetOpcode()) {
|
switch (inst.GetOpcode()) {
|
||||||
case IR::Opcode::SHA256MessageSchedule0:
|
case IR::Opcode::SHA256MessageSchedule0:
|
||||||
|
4
externals/dynarmic/src/dynarmic/ir/type.cpp
vendored
4
externals/dynarmic/src/dynarmic/ir/type.cpp
vendored
@ -43,8 +43,4 @@ bool AreTypesCompatible(Type t1, Type t2) {
|
|||||||
return t1 == t2 || t1 == Type::Opaque || t2 == Type::Opaque;
|
return t1 == t2 || t1 == Type::Opaque || t2 == Type::Opaque;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, Type type) {
|
|
||||||
return o << GetNameOf(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::IR
|
} // namespace Dynarmic::IR
|
||||||
|
12
externals/dynarmic/src/dynarmic/ir/type.h
vendored
12
externals/dynarmic/src/dynarmic/ir/type.h
vendored
@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <iosfwd>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
#include <mcl/stdint.hpp>
|
#include <mcl/stdint.hpp>
|
||||||
|
|
||||||
namespace Dynarmic::IR {
|
namespace Dynarmic::IR {
|
||||||
@ -49,6 +49,12 @@ std::string GetNameOf(Type type);
|
|||||||
/// @returns true if t1 and t2 are compatible types
|
/// @returns true if t1 and t2 are compatible types
|
||||||
bool AreTypesCompatible(Type t1, Type t2);
|
bool AreTypesCompatible(Type t1, Type t2);
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, Type type);
|
|
||||||
|
|
||||||
} // namespace Dynarmic::IR
|
} // namespace Dynarmic::IR
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct fmt::formatter<Dynarmic::IR::Type> : fmt::formatter<std::string> {
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(Dynarmic::IR::Type type, FormatContext& ctx) const {
|
||||||
|
return formatter<std::string>::format(Dynarmic::IR::GetNameOf(type), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
6
externals/dynarmic/src/dynarmic/ir/value.cpp
vendored
6
externals/dynarmic/src/dynarmic/ir/value.cpp
vendored
@ -79,6 +79,12 @@ Value::Value(AccType value)
|
|||||||
inner.imm_acctype = value;
|
inner.imm_acctype = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value Value::EmptyNZCVImmediateMarker() {
|
||||||
|
Value result{};
|
||||||
|
result.type = Type::NZCVFlags;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool Value::IsIdentity() const {
|
bool Value::IsIdentity() const {
|
||||||
if (type == Type::Opaque)
|
if (type == Type::Opaque)
|
||||||
return inner.inst->GetOpcode() == Opcode::Identity;
|
return inner.inst->GetOpcode() == Opcode::Identity;
|
||||||
|
2
externals/dynarmic/src/dynarmic/ir/value.h
vendored
2
externals/dynarmic/src/dynarmic/ir/value.h
vendored
@ -53,6 +53,8 @@ public:
|
|||||||
explicit Value(Cond value);
|
explicit Value(Cond value);
|
||||||
explicit Value(AccType value);
|
explicit Value(AccType value);
|
||||||
|
|
||||||
|
static Value EmptyNZCVImmediateMarker();
|
||||||
|
|
||||||
bool IsIdentity() const;
|
bool IsIdentity() const;
|
||||||
bool IsEmpty() const;
|
bool IsEmpty() const;
|
||||||
bool IsImmediate() const;
|
bool IsImmediate() const;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user